mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	Extract NotificationSlot from NotificationActionsPreference
This commit is contained in:
		| @@ -5,38 +5,22 @@ import static org.schabi.newpipe.player.notification.NotificationConstants.ACTIO | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.res.ColorStateList; | ||||
| import android.os.Build; | ||||
| import android.util.AttributeSet; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.RadioButton; | ||||
| import android.widget.RadioGroup; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.content.res.AppCompatResources; | ||||
| import androidx.core.widget.TextViewCompat; | ||||
| import androidx.preference.Preference; | ||||
| import androidx.preference.PreferenceViewHolder; | ||||
|  | ||||
| import org.schabi.newpipe.App; | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.databinding.ListRadioIconItemBinding; | ||||
| import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding; | ||||
| import org.schabi.newpipe.player.notification.NotificationConstants; | ||||
| import org.schabi.newpipe.util.DeviceUtils; | ||||
| import org.schabi.newpipe.util.ThemeHelper; | ||||
| import org.schabi.newpipe.views.FocusOverlayView; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
| import java.util.stream.IntStream; | ||||
|  | ||||
| public class NotificationActionsPreference extends Preference { | ||||
| @@ -47,8 +31,9 @@ public class NotificationActionsPreference extends Preference { | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Nullable private NotificationSlot[] notificationSlots = null; | ||||
|     @Nullable private List<Integer> compactSlots = null; | ||||
|     private NotificationSlot[] notificationSlots; | ||||
|     private List<Integer> compactSlots; | ||||
|  | ||||
|  | ||||
|     //////////////////////////////////////////////////////////////////////////// | ||||
|     // Lifecycle | ||||
| @@ -85,10 +70,26 @@ public class NotificationActionsPreference extends Preference { | ||||
|         compactSlots = NotificationConstants.getCompactSlotsFromPreferences(getContext(), | ||||
|                 getSharedPreferences(), 5); | ||||
|         notificationSlots = IntStream.range(0, 5) | ||||
|                 .mapToObj(i -> new NotificationSlot(i, view)) | ||||
|                 .mapToObj(i -> new NotificationSlot(getContext(), getSharedPreferences(), i, view, | ||||
|                         compactSlots.contains(i), this::onToggleCompactSlot)) | ||||
|                 .toArray(NotificationSlot[]::new); | ||||
|     } | ||||
|  | ||||
|     private void onToggleCompactSlot(final int i, final CheckBox checkBox) { | ||||
|         if (checkBox.isChecked()) { | ||||
|             compactSlots.remove((Integer) i); | ||||
|         } else if (compactSlots.size() < 3) { | ||||
|             compactSlots.add(i); | ||||
|         } else { | ||||
|             Toast.makeText(getContext(), | ||||
|                     R.string.notification_actions_at_most_three, | ||||
|                     Toast.LENGTH_SHORT).show(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         checkBox.toggle(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     //////////////////////////////////////////////////////////////////////////// | ||||
|     // Saving | ||||
| @@ -106,156 +107,10 @@ public class NotificationActionsPreference extends Preference { | ||||
|  | ||||
|             for (int i = 0; i < 5; i++) { | ||||
|                 editor.putInt(getContext().getString(NotificationConstants.SLOT_PREF_KEYS[i]), | ||||
|                         notificationSlots[i].selectedAction); | ||||
|                         notificationSlots[i].getSelectedAction()); | ||||
|             } | ||||
|  | ||||
|             editor.apply(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     //////////////////////////////////////////////////////////////////////////// | ||||
|     // Notification action | ||||
|     //////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     private static final int[] SLOT_ITEMS = { | ||||
|             R.id.notificationAction0, | ||||
|             R.id.notificationAction1, | ||||
|             R.id.notificationAction2, | ||||
|             R.id.notificationAction3, | ||||
|             R.id.notificationAction4, | ||||
|     }; | ||||
|  | ||||
|     private static final int[] SLOT_TITLES = { | ||||
|             R.string.notification_action_0_title, | ||||
|             R.string.notification_action_1_title, | ||||
|             R.string.notification_action_2_title, | ||||
|             R.string.notification_action_3_title, | ||||
|             R.string.notification_action_4_title, | ||||
|     }; | ||||
|  | ||||
|     private class NotificationSlot { | ||||
|  | ||||
|         final int i; | ||||
|         @NotificationConstants.Action int selectedAction; | ||||
|  | ||||
|         ImageView icon; | ||||
|         TextView summary; | ||||
|  | ||||
|         NotificationSlot(final int actionIndex, final View parentView) { | ||||
|             this.i = actionIndex; | ||||
|             selectedAction = Objects.requireNonNull(getSharedPreferences()).getInt( | ||||
|                     getContext().getString(NotificationConstants.SLOT_PREF_KEYS[i]), | ||||
|                     NotificationConstants.SLOT_DEFAULTS[i]); | ||||
|             final View view = parentView.findViewById(SLOT_ITEMS[i]); | ||||
|  | ||||
|             // only show the last two notification slots on Android 13+ | ||||
|             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || i >= 3) { | ||||
|                 setupSelectedAction(view); | ||||
|                 setupTitle(view); | ||||
|                 setupCheckbox(view); | ||||
|             } else { | ||||
|                 view.setVisibility(View.GONE); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void setupTitle(final View view) { | ||||
|             ((TextView) view.findViewById(R.id.notificationActionTitle)) | ||||
|                     .setText(SLOT_TITLES[i]); | ||||
|             view.findViewById(R.id.notificationActionClickableArea).setOnClickListener( | ||||
|                     v -> openActionChooserDialog()); | ||||
|         } | ||||
|  | ||||
|         void setupCheckbox(final View view) { | ||||
|             final CheckBox compactSlotCheckBox = view.findViewById(R.id.notificationActionCheckBox); | ||||
|             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||||
|                 // there are no compact slots to customize on Android 33+ | ||||
|                 compactSlotCheckBox.setVisibility(View.GONE); | ||||
|                 view.findViewById(R.id.notificationActionCheckBoxClickableArea) | ||||
|                         .setVisibility(View.GONE); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             compactSlotCheckBox.setChecked(compactSlots.contains(i)); | ||||
|             view.findViewById(R.id.notificationActionCheckBoxClickableArea).setOnClickListener( | ||||
|                     v -> { | ||||
|                         if (compactSlotCheckBox.isChecked()) { | ||||
|                             compactSlots.remove((Integer) i); | ||||
|                         } else if (compactSlots.size() < 3) { | ||||
|                             compactSlots.add(i); | ||||
|                         } else { | ||||
|                             Toast.makeText(getContext(), | ||||
|                                     R.string.notification_actions_at_most_three, | ||||
|                                     Toast.LENGTH_SHORT).show(); | ||||
|                             return; | ||||
|                         } | ||||
|  | ||||
|                         compactSlotCheckBox.toggle(); | ||||
|                     }); | ||||
|         } | ||||
|  | ||||
|         void setupSelectedAction(final View view) { | ||||
|             icon = view.findViewById(R.id.notificationActionIcon); | ||||
|             summary = view.findViewById(R.id.notificationActionSummary); | ||||
|             updateInfo(); | ||||
|         } | ||||
|  | ||||
|         void updateInfo() { | ||||
|             if (NotificationConstants.ACTION_ICONS[selectedAction] == 0) { | ||||
|                 icon.setImageDrawable(null); | ||||
|             } else { | ||||
|                 icon.setImageDrawable(AppCompatResources.getDrawable(getContext(), | ||||
|                         NotificationConstants.ACTION_ICONS[selectedAction])); | ||||
|             } | ||||
|  | ||||
|             summary.setText(NotificationConstants.getActionName(getContext(), selectedAction)); | ||||
|         } | ||||
|  | ||||
|         void openActionChooserDialog() { | ||||
|             final LayoutInflater inflater = LayoutInflater.from(getContext()); | ||||
|             final SingleChoiceDialogViewBinding binding = | ||||
|                     SingleChoiceDialogViewBinding.inflate(inflater); | ||||
|  | ||||
|             final AlertDialog alertDialog = new AlertDialog.Builder(getContext()) | ||||
|                     .setTitle(SLOT_TITLES[i]) | ||||
|                     .setView(binding.getRoot()) | ||||
|                     .setCancelable(true) | ||||
|                     .create(); | ||||
|  | ||||
|             final View.OnClickListener radioButtonsClickListener = v -> { | ||||
|                 selectedAction = NotificationConstants.SLOT_ALLOWED_ACTIONS[i][v.getId()]; | ||||
|                 updateInfo(); | ||||
|                 alertDialog.dismiss(); | ||||
|             }; | ||||
|  | ||||
|             for (int id = 0; id < NotificationConstants.SLOT_ALLOWED_ACTIONS[i].length; ++id) { | ||||
|                 final int action = NotificationConstants.SLOT_ALLOWED_ACTIONS[i][id]; | ||||
|                 final RadioButton radioButton = ListRadioIconItemBinding.inflate(inflater) | ||||
|                         .getRoot(); | ||||
|  | ||||
|                 // if present set action icon with correct color | ||||
|                 final int iconId = NotificationConstants.ACTION_ICONS[action]; | ||||
|                 if (iconId != 0) { | ||||
|                     radioButton.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, iconId, 0); | ||||
|  | ||||
|                     final var color = ColorStateList.valueOf(ThemeHelper | ||||
|                             .resolveColorFromAttr(getContext(), android.R.attr.textColorPrimary)); | ||||
|                     TextViewCompat.setCompoundDrawableTintList(radioButton, color); | ||||
|                 } | ||||
|  | ||||
|                 radioButton.setText(NotificationConstants.getActionName(getContext(), action)); | ||||
|                 radioButton.setChecked(action == selectedAction); | ||||
|                 radioButton.setId(id); | ||||
|                 radioButton.setLayoutParams(new RadioGroup.LayoutParams( | ||||
|                         ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); | ||||
|                 radioButton.setOnClickListener(radioButtonsClickListener); | ||||
|                 binding.list.addView(radioButton); | ||||
|             } | ||||
|             alertDialog.show(); | ||||
|  | ||||
|             if (DeviceUtils.isTv(getContext())) { | ||||
|                 FocusOverlayView.setupFocusObserver(alertDialog); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,172 @@ | ||||
| package org.schabi.newpipe.settings.custom; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.res.ColorStateList; | ||||
| import android.os.Build; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.RadioButton; | ||||
| import android.widget.RadioGroup; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.content.res.AppCompatResources; | ||||
| import androidx.core.widget.TextViewCompat; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.databinding.ListRadioIconItemBinding; | ||||
| import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding; | ||||
| import org.schabi.newpipe.player.notification.NotificationConstants; | ||||
| import org.schabi.newpipe.util.DeviceUtils; | ||||
| import org.schabi.newpipe.util.ThemeHelper; | ||||
| import org.schabi.newpipe.views.FocusOverlayView; | ||||
|  | ||||
| import java.util.Objects; | ||||
| import java.util.function.BiConsumer; | ||||
|  | ||||
| class NotificationSlot { | ||||
|  | ||||
|     private static final int[] SLOT_ITEMS = { | ||||
|             R.id.notificationAction0, | ||||
|             R.id.notificationAction1, | ||||
|             R.id.notificationAction2, | ||||
|             R.id.notificationAction3, | ||||
|             R.id.notificationAction4, | ||||
|     }; | ||||
|  | ||||
|     private static final int[] SLOT_TITLES = { | ||||
|             R.string.notification_action_0_title, | ||||
|             R.string.notification_action_1_title, | ||||
|             R.string.notification_action_2_title, | ||||
|             R.string.notification_action_3_title, | ||||
|             R.string.notification_action_4_title, | ||||
|     }; | ||||
|  | ||||
|     private final int i; | ||||
|     private @NotificationConstants.Action int selectedAction; | ||||
|     private final Context context; | ||||
|     private final BiConsumer<Integer, CheckBox> onToggleCompactSlot; | ||||
|  | ||||
|     private ImageView icon; | ||||
|     private TextView summary; | ||||
|  | ||||
|     NotificationSlot(final Context context, | ||||
|                      final SharedPreferences prefs, | ||||
|                      final int actionIndex, | ||||
|                      final View parentView, | ||||
|                      final boolean isCompactSlotChecked, | ||||
|                      final BiConsumer<Integer, CheckBox> onToggleCompactSlot) { | ||||
|         this.context = context; | ||||
|         this.i = actionIndex; | ||||
|         this.onToggleCompactSlot = onToggleCompactSlot; | ||||
|  | ||||
|         selectedAction = Objects.requireNonNull(prefs).getInt( | ||||
|                 context.getString(NotificationConstants.SLOT_PREF_KEYS[i]), | ||||
|                 NotificationConstants.SLOT_DEFAULTS[i]); | ||||
|         final View view = parentView.findViewById(SLOT_ITEMS[i]); | ||||
|  | ||||
|         // only show the last two notification slots on Android 13+ | ||||
|         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || i >= 3) { | ||||
|             setupSelectedAction(view); | ||||
|             setupTitle(view); | ||||
|             setupCheckbox(view, isCompactSlotChecked); | ||||
|         } else { | ||||
|             view.setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void setupTitle(final View view) { | ||||
|         ((TextView) view.findViewById(R.id.notificationActionTitle)) | ||||
|                 .setText(SLOT_TITLES[i]); | ||||
|         view.findViewById(R.id.notificationActionClickableArea).setOnClickListener( | ||||
|                 v -> openActionChooserDialog()); | ||||
|     } | ||||
|  | ||||
|     void setupCheckbox(final View view, final boolean isCompactSlotChecked) { | ||||
|         final CheckBox compactSlotCheckBox = view.findViewById(R.id.notificationActionCheckBox); | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||||
|             // there are no compact slots to customize on Android 33+ | ||||
|             compactSlotCheckBox.setVisibility(View.GONE); | ||||
|             view.findViewById(R.id.notificationActionCheckBoxClickableArea) | ||||
|                     .setVisibility(View.GONE); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         compactSlotCheckBox.setChecked(isCompactSlotChecked); | ||||
|         view.findViewById(R.id.notificationActionCheckBoxClickableArea).setOnClickListener( | ||||
|                 v -> onToggleCompactSlot.accept(i, compactSlotCheckBox)); | ||||
|     } | ||||
|  | ||||
|     void setupSelectedAction(final View view) { | ||||
|         icon = view.findViewById(R.id.notificationActionIcon); | ||||
|         summary = view.findViewById(R.id.notificationActionSummary); | ||||
|         updateInfo(); | ||||
|     } | ||||
|  | ||||
|     void updateInfo() { | ||||
|         if (NotificationConstants.ACTION_ICONS[selectedAction] == 0) { | ||||
|             icon.setImageDrawable(null); | ||||
|         } else { | ||||
|             icon.setImageDrawable(AppCompatResources.getDrawable(context, | ||||
|                     NotificationConstants.ACTION_ICONS[selectedAction])); | ||||
|         } | ||||
|  | ||||
|         summary.setText(NotificationConstants.getActionName(context, selectedAction)); | ||||
|     } | ||||
|  | ||||
|     void openActionChooserDialog() { | ||||
|         final LayoutInflater inflater = LayoutInflater.from(context); | ||||
|         final SingleChoiceDialogViewBinding binding = | ||||
|                 SingleChoiceDialogViewBinding.inflate(inflater); | ||||
|  | ||||
|         final AlertDialog alertDialog = new AlertDialog.Builder(context) | ||||
|                 .setTitle(SLOT_TITLES[i]) | ||||
|                 .setView(binding.getRoot()) | ||||
|                 .setCancelable(true) | ||||
|                 .create(); | ||||
|  | ||||
|         final View.OnClickListener radioButtonsClickListener = v -> { | ||||
|             selectedAction = NotificationConstants.SLOT_ALLOWED_ACTIONS[i][v.getId()]; | ||||
|             updateInfo(); | ||||
|             alertDialog.dismiss(); | ||||
|         }; | ||||
|  | ||||
|         for (int id = 0; id < NotificationConstants.SLOT_ALLOWED_ACTIONS[i].length; ++id) { | ||||
|             final int action = NotificationConstants.SLOT_ALLOWED_ACTIONS[i][id]; | ||||
|             final RadioButton radioButton = ListRadioIconItemBinding.inflate(inflater) | ||||
|                     .getRoot(); | ||||
|  | ||||
|             // if present set action icon with correct color | ||||
|             final int iconId = NotificationConstants.ACTION_ICONS[action]; | ||||
|             if (iconId != 0) { | ||||
|                 radioButton.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, iconId, 0); | ||||
|  | ||||
|                 final var color = ColorStateList.valueOf(ThemeHelper | ||||
|                         .resolveColorFromAttr(context, android.R.attr.textColorPrimary)); | ||||
|                 TextViewCompat.setCompoundDrawableTintList(radioButton, color); | ||||
|             } | ||||
|  | ||||
|             radioButton.setText(NotificationConstants.getActionName(context, action)); | ||||
|             radioButton.setChecked(action == selectedAction); | ||||
|             radioButton.setId(id); | ||||
|             radioButton.setLayoutParams(new RadioGroup.LayoutParams( | ||||
|                     ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); | ||||
|             radioButton.setOnClickListener(radioButtonsClickListener); | ||||
|             binding.list.addView(radioButton); | ||||
|         } | ||||
|         alertDialog.show(); | ||||
|  | ||||
|         if (DeviceUtils.isTv(context)) { | ||||
|             FocusOverlayView.setupFocusObserver(alertDialog); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @NotificationConstants.Action | ||||
|     public int getSelectedAction() { | ||||
|         return selectedAction; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox