Merge branch 'dev' into pr9236
This commit is contained in:
commit
37f7fa7ef4
418 changed files with 12465 additions and 4342 deletions
|
|
@ -12,7 +12,9 @@ import org.schabi.newpipe.R;
|
|||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||
import org.schabi.newpipe.extractor.localization.Localization;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
import org.schabi.newpipe.util.image.ImageStrategy;
|
||||
import org.schabi.newpipe.util.image.PicassoHelper;
|
||||
import org.schabi.newpipe.util.image.PreferredImageQuality;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
|
@ -35,9 +37,11 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
.getPreferredContentCountry(requireContext());
|
||||
initialLanguage = defaultPreferences.getString(getString(R.string.app_language_key), "en");
|
||||
|
||||
findPreference(getString(R.string.download_thumbnail_key)).setOnPreferenceChangeListener(
|
||||
final Preference imageQualityPreference = requirePreference(R.string.image_quality_key);
|
||||
imageQualityPreference.setOnPreferenceChangeListener(
|
||||
(preference, newValue) -> {
|
||||
PicassoHelper.setShouldLoadImages((Boolean) newValue);
|
||||
ImageStrategy.setPreferredImageQuality(PreferredImageQuality
|
||||
.fromPreferenceKey(requireContext(), (String) newValue));
|
||||
try {
|
||||
PicassoHelper.clearCache(preference.getContext());
|
||||
Toast.makeText(preference.getContext(),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import org.schabi.newpipe.error.ErrorInfo;
|
|||
import org.schabi.newpipe.error.ErrorUtil;
|
||||
import org.schabi.newpipe.error.UserAction;
|
||||
import org.schabi.newpipe.local.feed.notifications.NotificationWorker;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
import org.schabi.newpipe.util.image.PicassoHelper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public class MainSettingsFragment extends BasePreferenceFragment {
|
|||
setHasOptionsMenu(true); // Otherwise onCreateOptionsMenu is not called
|
||||
|
||||
// Check if the app is updatable
|
||||
if (!ReleaseVersionUtil.isReleaseApk()) {
|
||||
if (!ReleaseVersionUtil.INSTANCE.isReleaseApk()) {
|
||||
getPreferenceScreen().removePreference(
|
||||
findPreference(getString(R.string.update_pref_screen_key)));
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import org.schabi.newpipe.R;
|
|||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||
import org.schabi.newpipe.error.ErrorUtil;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionManager;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
import org.schabi.newpipe.util.image.PicassoHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import org.schabi.newpipe.error.ErrorUtil;
|
|||
import org.schabi.newpipe.error.UserAction;
|
||||
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
import org.schabi.newpipe.util.image.PicassoHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,20 @@ public final class SettingMigrations {
|
|||
}
|
||||
};
|
||||
|
||||
public static final Migration MIGRATION_5_6 = new Migration(5, 6) {
|
||||
@Override
|
||||
protected void migrate(@NonNull final Context context) {
|
||||
final boolean loadImages = sp.getBoolean("download_thumbnail_key", true);
|
||||
|
||||
sp.edit()
|
||||
.putString(context.getString(R.string.image_quality_key),
|
||||
context.getString(loadImages
|
||||
? R.string.image_quality_default
|
||||
: R.string.image_quality_none_key))
|
||||
.apply();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* List of all implemented migrations.
|
||||
* <p>
|
||||
|
|
@ -140,12 +154,13 @@ public final class SettingMigrations {
|
|||
MIGRATION_2_3,
|
||||
MIGRATION_3_4,
|
||||
MIGRATION_4_5,
|
||||
MIGRATION_5_6,
|
||||
};
|
||||
|
||||
/**
|
||||
* Version number for preferences. Must be incremented every time a migration is necessary.
|
||||
*/
|
||||
private static final int VERSION = 5;
|
||||
private static final int VERSION = 6;
|
||||
|
||||
|
||||
public static void runMigrationsIfNeeded(@NonNull final Context context,
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ public class SettingsActivity extends AppCompatActivity implements
|
|||
*/
|
||||
private void ensureSearchRepresentsApplicationState() {
|
||||
// Check if the update settings are available
|
||||
if (!ReleaseVersionUtil.isReleaseApk()) {
|
||||
if (!ReleaseVersionUtil.INSTANCE.isReleaseApk()) {
|
||||
SettingsResourceRegistry.getInstance()
|
||||
.getEntryByPreferencesResId(R.xml.update_settings)
|
||||
.setSearchable(false);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.preference.ListPreference;
|
|||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
|
@ -26,7 +27,7 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
|
|||
addPreferencesFromResourceRegistry();
|
||||
|
||||
updateSeekOptions();
|
||||
|
||||
updateResolutionOptions();
|
||||
listener = (sharedPreferences, key) -> {
|
||||
|
||||
// on M and above, if user chooses to minimise to popup player on exit
|
||||
|
|
@ -48,10 +49,84 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
|
|||
}
|
||||
} else if (getString(R.string.use_inexact_seek_key).equals(key)) {
|
||||
updateSeekOptions();
|
||||
} else if (getString(R.string.show_higher_resolutions_key).equals(key)) {
|
||||
updateResolutionOptions();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update default resolution, default popup resolution & mobile data resolution options.
|
||||
* <br />
|
||||
* Show high resolutions when "Show higher resolution" option is enabled.
|
||||
* Set default resolution to "best resolution" when "Show higher resolution" option
|
||||
* is disabled.
|
||||
*/
|
||||
private void updateResolutionOptions() {
|
||||
final Resources resources = getResources();
|
||||
final boolean showHigherResolutions = getPreferenceManager().getSharedPreferences()
|
||||
.getBoolean(resources.getString(R.string.show_higher_resolutions_key), false);
|
||||
|
||||
// get sorted resolution lists
|
||||
final List<String> resolutionListDescriptions = ListHelper.getSortedResolutionList(
|
||||
resources,
|
||||
R.array.resolution_list_description,
|
||||
R.array.high_resolution_list_descriptions,
|
||||
showHigherResolutions);
|
||||
final List<String> resolutionListValues = ListHelper.getSortedResolutionList(
|
||||
resources,
|
||||
R.array.resolution_list_values,
|
||||
R.array.high_resolution_list_values,
|
||||
showHigherResolutions);
|
||||
final List<String> limitDataUsageResolutionValues = ListHelper.getSortedResolutionList(
|
||||
resources,
|
||||
R.array.limit_data_usage_values_list,
|
||||
R.array.high_resolution_limit_data_usage_values_list,
|
||||
showHigherResolutions);
|
||||
final List<String> limitDataUsageResolutionDescriptions = ListHelper
|
||||
.getSortedResolutionList(resources,
|
||||
R.array.limit_data_usage_description_list,
|
||||
R.array.high_resolution_list_descriptions,
|
||||
showHigherResolutions);
|
||||
|
||||
// get resolution preferences
|
||||
final ListPreference defaultResolution = findPreference(
|
||||
getString(R.string.default_resolution_key));
|
||||
final ListPreference defaultPopupResolution = findPreference(
|
||||
getString(R.string.default_popup_resolution_key));
|
||||
final ListPreference mobileDataResolution = findPreference(
|
||||
getString(R.string.limit_mobile_data_usage_key));
|
||||
|
||||
// update resolution preferences with new resolutions, entries & values for each
|
||||
defaultResolution.setEntries(resolutionListDescriptions.toArray(new String[0]));
|
||||
defaultResolution.setEntryValues(resolutionListValues.toArray(new String[0]));
|
||||
defaultPopupResolution.setEntries(resolutionListDescriptions.toArray(new String[0]));
|
||||
defaultPopupResolution.setEntryValues(resolutionListValues.toArray(new String[0]));
|
||||
mobileDataResolution.setEntries(
|
||||
limitDataUsageResolutionDescriptions.toArray(new String[0]));
|
||||
mobileDataResolution.setEntryValues(limitDataUsageResolutionValues.toArray(new String[0]));
|
||||
|
||||
// if "Show higher resolution" option is disabled,
|
||||
// set default resolution to "best resolution"
|
||||
if (!showHigherResolutions) {
|
||||
if (ListHelper.isHighResolutionSelected(defaultResolution.getValue(),
|
||||
R.array.high_resolution_list_values,
|
||||
resources)) {
|
||||
defaultResolution.setValueIndex(0);
|
||||
}
|
||||
if (ListHelper.isHighResolutionSelected(defaultPopupResolution.getValue(),
|
||||
R.array.high_resolution_list_values,
|
||||
resources)) {
|
||||
defaultPopupResolution.setValueIndex(0);
|
||||
}
|
||||
if (ListHelper.isHighResolutionSelected(mobileDataResolution.getValue(),
|
||||
R.array.high_resolution_limit_data_usage_values_list,
|
||||
resources)) {
|
||||
mobileDataResolution.setValueIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update fast-forward/-rewind seek duration options
|
||||
* according to language and inexact seek setting.
|
||||
|
|
|
|||
|
|
@ -5,35 +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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
|
|
@ -45,8 +32,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
|
||||
|
|
@ -56,6 +44,11 @@ public class NotificationActionsPreference extends Preference {
|
|||
public void onBindViewHolder(@NonNull final PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
((TextView) holder.itemView.findViewById(R.id.summary))
|
||||
.setText(R.string.notification_actions_summary_android13);
|
||||
}
|
||||
|
||||
holder.itemView.setClickable(false);
|
||||
setupActions(holder.itemView);
|
||||
}
|
||||
|
|
@ -75,13 +68,29 @@ public class NotificationActionsPreference extends Preference {
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void setupActions(@NonNull final View view) {
|
||||
compactSlots = NotificationConstants.getCompactSlotsFromPreferences(getContext(),
|
||||
getSharedPreferences(), 5);
|
||||
compactSlots = new ArrayList<>(NotificationConstants.getCompactSlotsFromPreferences(
|
||||
getContext(), getSharedPreferences()));
|
||||
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
|
||||
|
|
@ -99,143 +108,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;
|
||||
|
||||
final View view = parentView.findViewById(SLOT_ITEMS[i]);
|
||||
setupSelectedAction(view);
|
||||
setupTitle(view);
|
||||
setupCheckbox(view);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
selectedAction = getSharedPreferences().getInt(
|
||||
getContext().getString(NotificationConstants.SLOT_PREF_KEYS[i]),
|
||||
NotificationConstants.SLOT_DEFAULTS[i]);
|
||||
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 13+
|
||||
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.ALL_ACTIONS[v.getId()];
|
||||
updateInfo();
|
||||
alertDialog.dismiss();
|
||||
};
|
||||
|
||||
for (int id = 0; id < NotificationConstants.ALL_ACTIONS.length; ++id) {
|
||||
final int action = NotificationConstants.ALL_ACTIONS[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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue