diff --git a/app/src/main/java/app/revanced/integrations/shared/Utils.java b/app/src/main/java/app/revanced/integrations/shared/Utils.java index 279abdea..c2aa2f6b 100644 --- a/app/src/main/java/app/revanced/integrations/shared/Utils.java +++ b/app/src/main/java/app/revanced/integrations/shared/Utils.java @@ -12,6 +12,7 @@ import android.os.Handler; import android.os.Looper; import android.preference.Preference; import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; @@ -26,10 +27,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.text.Bidi; -import java.util.Locale; -import java.util.Objects; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.SynchronousQueue; @@ -102,7 +100,6 @@ public class Utils { view.setVisibility(View.GONE); } - /** * General purpose pool for network calls and other background tasks. * All tasks run at max thread priority. @@ -205,7 +202,9 @@ public class Utils { public static T getChildView(@NonNull ViewGroup viewGroup, @NonNull MatchFilter filter) { for (int i = 0, childCount = viewGroup.getChildCount(); i < childCount; i++) { View childAt = viewGroup.getChildAt(i); + //noinspection unchecked if (filter.matches(childAt)) { + //noinspection unchecked return (T) childAt; } } @@ -345,6 +344,12 @@ public class Utils { } } + public enum NetworkType { + NONE, + MOBILE, + OTHER, + } + public static boolean isNetworkConnected() { NetworkType networkType = getNetworkType(); return networkType == NetworkType.MOBILE @@ -393,48 +398,104 @@ public class Utils { } } + /** + * {@link PreferenceScreen} and {@link PreferenceGroup} sorting styles. + */ + private enum Sort { + /** + * Sort by the localized preference title. + */ + BY_TITLE("_sort_by_title"), + + /** + * Sort by the preference keys. + */ + BY_KEY("_sort_by_key"), + + /** + * Unspecified sorting. + */ + UNSORTED("_sort_by_unsorted"); + + final String keySuffix; + + Sort(String keySuffix) { + this.keySuffix = keySuffix; + } + + /** + * Defaults to {@link #UNSORTED} if key is null or has no sort suffix. + */ + @NonNull + static Sort fromKey(@Nullable String key) { + if (key != null) { + for (Sort sort : values()) { + if (key.endsWith(sort.keySuffix)) { + return sort; + } + } + } + return UNSORTED; + } + } + private static final Regex punctuationRegex = new Regex("\\p{P}+"); /** - * Sort the preferences by title and ignore the casing. - * - * Android Preferences are automatically sorted by title, - * but if using a localized string key it sorts on the key and not the actual title text that's used at runtime. - * - * @param menuDepthToSort Maximum menu depth to sort. Menus deeper than this value - * will show preferences in the order created in patches. + * Strips all punctuation and converts to lower case. A null parameter returns an empty string. */ - public static void sortPreferenceGroupByTitle(PreferenceGroup group, int menuDepthToSort) { - if (menuDepthToSort == 0) return; - - SortedMap preferences = new TreeMap<>(); - for (int i = 0, prefCount = group.getPreferenceCount(); i < prefCount; i++) { - Preference preference = group.getPreference(i); - if (preference instanceof PreferenceGroup) { - sortPreferenceGroupByTitle((PreferenceGroup) preference, menuDepthToSort - 1); - } - preferences.put(removePunctuationConvertToLowercase(preference.getTitle()), preference); - } - - int prefIndex = 0; - for (Preference pref : preferences.values()) { - int indexToSet = prefIndex++; - if (pref instanceof PreferenceGroup || pref.getIntent() != null) { - // Place preference groups last. - // Use an offset to push the group to the end. - indexToSet += 1000; - } - pref.setOrder(indexToSet); - } - } - - public static String removePunctuationConvertToLowercase(CharSequence original) { + public static String removePunctuationConvertToLowercase(@Nullable CharSequence original) { + if (original == null) return ""; return punctuationRegex.replace(original, "").toLowerCase(); } - public enum NetworkType { - NONE, - MOBILE, - OTHER, + /** + * Sort a PreferenceGroup and all it's sub groups by title or key. + * + * Sort order is determined by the preferences key {@link Sort} suffix. + * + * If a preference has no key or no {@link Sort} suffix, + * then the preferences are left unsorted. + */ + public static void sortPreferenceGroups(@NonNull PreferenceGroup group) { + Sort sort = Sort.fromKey(group.getKey()); + SortedMap preferences = new TreeMap<>(); + + for (int i = 0, prefCount = group.getPreferenceCount(); i < prefCount; i++) { + Preference preference = group.getPreference(i); + + if (preference instanceof PreferenceGroup) { + sortPreferenceGroups((PreferenceGroup) preference); + } + + final String sortValue; + switch (sort) { + case BY_TITLE: + sortValue = removePunctuationConvertToLowercase(preference.getTitle()); + break; + case BY_KEY: + sortValue = preference.getKey(); + break; + case UNSORTED: + continue; // Keep original sorting. + default: + throw new IllegalStateException(); + } + + preferences.put(sortValue, preference); + } + + int index = 0; + for (Preference pref : preferences.values()) { + int order = index++; + + // If the preference is a PreferenceScreen or is an intent preference, move to the top. + if (pref instanceof PreferenceScreen || pref.getIntent() != null) { + // Arbitrary high number. + order -= 1000; + } + + pref.setOrder(order); + } } } diff --git a/app/src/main/java/app/revanced/integrations/shared/settings/preference/AbstractPreferenceFragment.java b/app/src/main/java/app/revanced/integrations/shared/settings/preference/AbstractPreferenceFragment.java index 6ef0c778..dc1fcbd9 100644 --- a/app/src/main/java/app/revanced/integrations/shared/settings/preference/AbstractPreferenceFragment.java +++ b/app/src/main/java/app/revanced/integrations/shared/settings/preference/AbstractPreferenceFragment.java @@ -85,7 +85,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { if (identifier == 0) return; addPreferencesFromResource(identifier); - Utils.sortPreferenceGroupByTitle(getPreferenceScreen(), 2); + Utils.sortPreferenceGroups(getPreferenceScreen()); } private void showSettingUserDialogConfirmation(SwitchPreference switchPref, BooleanSetting setting) { diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/ButtonsFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/ButtonsFilter.java index 5db9a8a8..c92cba97 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/ButtonsFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/ButtonsFilter.java @@ -49,10 +49,6 @@ final class ButtonsFilter extends Filter { ); bufferButtonsGroupList.addAll( - new ByteArrayFilterGroup( - Settings.HIDE_LIVE_CHAT_BUTTON, - "yt_outline_message_bubble_overlap" - ), new ByteArrayFilterGroup( Settings.HIDE_REPORT_BUTTON, "yt_outline_flag" diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java index 70130a0d..e011f941 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java @@ -15,15 +15,14 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.shared.settings.BaseSettings; import app.revanced.integrations.shared.settings.BooleanSetting; import app.revanced.integrations.shared.settings.FloatSetting; import app.revanced.integrations.shared.settings.IntegerSetting; import app.revanced.integrations.shared.settings.LongSetting; import app.revanced.integrations.shared.settings.Setting; -import app.revanced.integrations.shared.settings.preference.SharedPrefCategory; -import app.revanced.integrations.shared.settings.BaseSettings; import app.revanced.integrations.shared.settings.StringSetting; +import app.revanced.integrations.shared.settings.preference.SharedPrefCategory; import app.revanced.integrations.youtube.sponsorblock.SponsorBlockSettings; public class Settings extends BaseSettings { @@ -167,7 +166,6 @@ public class Settings extends BaseSettings { // Action buttons public static final BooleanSetting HIDE_LIKE_DISLIKE_BUTTON = new BooleanSetting("revanced_hide_like_dislike_button", FALSE); - public static final BooleanSetting HIDE_LIVE_CHAT_BUTTON = new BooleanSetting("revanced_hide_live_chat_button", FALSE); public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE); public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE); public static final BooleanSetting HIDE_REMIX_BUTTON = new BooleanSetting("revanced_hide_remix_button", TRUE); diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java b/app/src/main/java/app/revanced/integrations/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java index 50b0a78b..117c2f99 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java @@ -150,7 +150,7 @@ public class ReturnYouTubeDislikePreferenceFragment extends PreferenceFragment { pref.getContext().startActivity(i); return false; }); - preferenceScreen.addPreference(aboutWebsitePreference); + aboutCategory.addPreference(aboutWebsitePreference); // RYD API connection statistics