You've already forked revanced-integrations
mirror of
https://github.com/revanced/revanced-integrations
synced 2025-11-19 03:23:27 +01:00
Compare commits
33 Commits
v1.4.0-dev
...
v1.5.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32a14efe6f | ||
|
|
4ec955fd01 | ||
|
|
f47495ccd8 | ||
|
|
9ac2d63489 | ||
|
|
74b6ab8712 | ||
|
|
ad477e4859 | ||
|
|
6f1ac5d073 | ||
|
|
254da31d16 | ||
|
|
7c40c947ef | ||
|
|
4be65be414 | ||
|
|
b060732e86 | ||
|
|
da8ec49589 | ||
|
|
b9c1eec69f | ||
|
|
d6032216e4 | ||
|
|
468dfac054 | ||
|
|
75a494e09b | ||
|
|
771a0de3bc | ||
|
|
6aacd1a225 | ||
|
|
8d48a90a8b | ||
|
|
6188fa75c6 | ||
|
|
ab07a563b9 | ||
|
|
c7ae3355a1 | ||
|
|
eee3f352c5 | ||
|
|
36aa6c9aa8 | ||
|
|
e5aa30ebe5 | ||
|
|
5d14f53acd | ||
|
|
67673d089f | ||
|
|
07482094a3 | ||
|
|
7fcb244cfb | ||
|
|
4ec76435d5 | ||
|
|
eea4a48cd5 | ||
|
|
db7e24994b | ||
|
|
da57fb9523 |
3
.editorconfig
Normal file
3
.editorconfig
Normal file
@@ -0,0 +1,3 @@
|
||||
[*.{kt,kts}]
|
||||
ktlint_code_style = intellij_idea
|
||||
ktlint_standard_no-wildcard-imports = disabled
|
||||
118
CHANGELOG.md
118
CHANGELOG.md
@@ -1,3 +1,121 @@
|
||||
# [1.5.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.7...v1.5.0-dev.8) (2024-03-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide ads:** Prevent app crash if hiding fullscreen ads is not possible ([#590](https://github.com/ReVanced/revanced-integrations/issues/590)) ([4ec955f](https://github.com/ReVanced/revanced-integrations/commit/4ec955fd0133643826e47be7089fbfa07fd9a089))
|
||||
|
||||
# [1.5.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.6...v1.5.0-dev.7) (2024-03-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **TikTok:** Hook application context earlier to prevent crash ([#588](https://github.com/ReVanced/revanced-integrations/issues/588)) ([9ac2d63](https://github.com/ReVanced/revanced-integrations/commit/9ac2d634897d961eba1b704f2722ea757bb83e0a))
|
||||
|
||||
# [1.5.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.5...v1.5.0-dev.6) (2024-03-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Handle custom preferences ([#586](https://github.com/ReVanced/revanced-integrations/issues/586)) ([ad477e4](https://github.com/ReVanced/revanced-integrations/commit/ad477e4859ef69beda297f7a2a6c29a918077628))
|
||||
|
||||
# [1.5.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.4...v1.5.0-dev.5) (2024-03-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Downloads:** Use external downloader when selecting 'Download' in home feed flyout menu ([#587](https://github.com/ReVanced/revanced-integrations/issues/587)) ([254da31](https://github.com/ReVanced/revanced-integrations/commit/254da31d16c39781f46e1cdea1e9ba22e2fce6d1))
|
||||
|
||||
# [1.5.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.3...v1.5.0-dev.4) (2024-03-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - HDR auto brightness:** Remove non functional and obsolete patch ([#585](https://github.com/ReVanced/revanced-integrations/issues/585)) ([b060732](https://github.com/ReVanced/revanced-integrations/commit/b060732e861b011cac8737ed597385a3315f6057))
|
||||
|
||||
# [1.5.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.2...v1.5.0-dev.3) (2024-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Disable suggested video end screen:** Disable by default to fix autoplay issues ([#578](https://github.com/ReVanced/revanced-integrations/issues/578)) ([b9c1eec](https://github.com/ReVanced/revanced-integrations/commit/b9c1eec69fab64f213dd77d1f932e3244d81ab2d))
|
||||
|
||||
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2024-03-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Downloads:** Use new task context ([#583](https://github.com/ReVanced/revanced-integrations/issues/583)) ([468dfac](https://github.com/ReVanced/revanced-integrations/commit/468dfac0544e282658675a8be65b4e43aa351068))
|
||||
|
||||
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.4...v1.5.0-dev.1) (2024-03-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - External downloader:** Add ability to use in-app download button ([771a0de](https://github.com/ReVanced/revanced-integrations/commit/771a0de3bc9bec3ec5a8e4f8b02edfa9df7b1997))
|
||||
|
||||
## [1.4.1-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.3...v1.4.1-dev.4) (2024-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide seekbar:** Use original seekbar color if Theme patch is not included ([#580](https://github.com/ReVanced/revanced-integrations/issues/580)) ([8d48a90](https://github.com/ReVanced/revanced-integrations/commit/8d48a90a8b8bc7ce9e22580b7a66c4c12fd6d54f))
|
||||
|
||||
## [1.4.1-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.2...v1.4.1-dev.3) (2024-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Revert AGP dependency update ([ab07a56](https://github.com/ReVanced/revanced-integrations/commit/ab07a563b9ef890dc8a673eeb4268ce1c9f15a69))
|
||||
|
||||
## [1.4.1-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.1...v1.4.1-dev.2) (2024-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Client spoof:** Allow playback for links with timestamp ([#582](https://github.com/ReVanced/revanced-integrations/issues/582)) ([eee3f35](https://github.com/ReVanced/revanced-integrations/commit/eee3f352c59141f47f6bda6c6cd350f1a16f1450))
|
||||
|
||||
## [1.4.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.4.0...v1.4.1-dev.1) (2024-03-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Announcements:** Only compare ID to not show same announcement after a fix-up ([#579](https://github.com/ReVanced/revanced-integrations/issues/579)) ([5d14f53](https://github.com/ReVanced/revanced-integrations/commit/5d14f53acd0b1eabd6951543edd7d7c662b6c502))
|
||||
|
||||
# [1.4.0](https://github.com/ReVanced/revanced-integrations/compare/v1.3.2...v1.4.0) (2024-03-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Twitter - Hide ads:** Hide ads in search ([b40687c](https://github.com/ReVanced/revanced-integrations/commit/b40687c5c7fa301c78035219b27c0bd85c968bb2))
|
||||
* **YouTube - Disable suggested end screen:** Reliably hide end screen ([b4ab5f6](https://github.com/ReVanced/revanced-integrations/commit/b4ab5f65d5607678a000783aae14257b845706b5))
|
||||
* **YouTube - Hide ads:** Do not show error toast and hide full screen ads ([#569](https://github.com/ReVanced/revanced-integrations/issues/569)) ([0b0d46f](https://github.com/ReVanced/revanced-integrations/commit/0b0d46f5183c88f73d58c8f7b9320d38976ddd4e))
|
||||
* **YouTube - Hide Shorts:** Hide Shorts in feed when using tablet layout ([#572](https://github.com/ReVanced/revanced-integrations/issues/572)) ([7f5e7df](https://github.com/ReVanced/revanced-integrations/commit/7f5e7dfd68ad0200e9ea36d45f18a85ddfe534f8))
|
||||
* **YouTube - Spoof app version:** Remove broken versions ([#573](https://github.com/ReVanced/revanced-integrations/issues/573)) ([fb4aab7](https://github.com/ReVanced/revanced-integrations/commit/fb4aab792ae93fc7e7decbc19bd71ae700d5d235))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Sync for Reddit:** Add `Fix /s/ links` patch ([a8c82ad](https://github.com/ReVanced/revanced-integrations/commit/a8c82ad27b74e929311536227dee0909ebc27ee1))
|
||||
* **X:** Add `Open links as query` patch ([#570](https://github.com/ReVanced/revanced-integrations/issues/570)) ([95ca632](https://github.com/ReVanced/revanced-integrations/commit/95ca632d40b90ea8160dbbf33fd5d7f2281cf711))
|
||||
* **YouTube - Change start page:** Add more start pages ([27421fb](https://github.com/ReVanced/revanced-integrations/commit/27421fb5783e677075ab0c220030d6af64cfaa18))
|
||||
* **YouTube - Spoof app version:** Add target versions ([#574](https://github.com/ReVanced/revanced-integrations/issues/574)) ([da57fb9](https://github.com/ReVanced/revanced-integrations/commit/da57fb95233ed251518fbd5c56a92bc39c4e0015))
|
||||
* **YouTube:** Reorganize settings menu ([#571](https://github.com/ReVanced/revanced-integrations/issues/571)) ([eea4a48](https://github.com/ReVanced/revanced-integrations/commit/eea4a48cd565712c09d0ddd35ae256871ebe1964))
|
||||
|
||||
# [1.4.0-dev.9](https://github.com/ReVanced/revanced-integrations/compare/v1.4.0-dev.8...v1.4.0-dev.9) (2024-03-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Reorganize settings menu ([#571](https://github.com/ReVanced/revanced-integrations/issues/571)) ([eea4a48](https://github.com/ReVanced/revanced-integrations/commit/eea4a48cd565712c09d0ddd35ae256871ebe1964))
|
||||
|
||||
# [1.4.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.4.0-dev.7...v1.4.0-dev.8) (2024-03-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Spoof app version:** Add target versions ([#574](https://github.com/ReVanced/revanced-integrations/issues/574)) ([da57fb9](https://github.com/ReVanced/revanced-integrations/commit/da57fb95233ed251518fbd5c56a92bc39c4e0015))
|
||||
|
||||
# [1.4.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.4.0-dev.6...v1.4.0-dev.7) (2024-02-29)
|
||||
|
||||
|
||||
|
||||
@@ -5,14 +5,15 @@ import static app.revanced.integrations.shared.settings.BaseSettings.DEBUG_STACK
|
||||
import static app.revanced.integrations.shared.settings.BaseSettings.DEBUG_TOAST_ON_ERROR;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.shared.settings.BaseSettings;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import app.revanced.integrations.shared.settings.BaseSettings;
|
||||
|
||||
public class Logger {
|
||||
|
||||
/**
|
||||
@@ -24,7 +25,7 @@ public class Logger {
|
||||
|
||||
/**
|
||||
* @return For outer classes, this returns {@link Class#getSimpleName()}.
|
||||
* For inner, static, or anonymous classes, this returns the simple name of the enclosing class.<br>
|
||||
* For static, inner, or anonymous classes, this returns the simple name of the enclosing class.
|
||||
* <br>
|
||||
* For example, each of these classes return 'SomethingView':
|
||||
* <code>
|
||||
@@ -38,13 +39,13 @@ public class Logger {
|
||||
|
||||
String fullClassName = selfClass.getName();
|
||||
final int dollarSignIndex = fullClassName.indexOf('$');
|
||||
if (dollarSignIndex == -1) {
|
||||
return selfClass.getSimpleName(); // already an outer class
|
||||
if (dollarSignIndex < 0) {
|
||||
return selfClass.getSimpleName(); // Already an outer class.
|
||||
}
|
||||
|
||||
// class is inner, static, or anonymous
|
||||
// parse the simple name full name
|
||||
// a class with no package returns index of -1, but incrementing gives index zero which is correct
|
||||
// Class is inner, static, or anonymous.
|
||||
// Parse the simple name full name.
|
||||
// A class with no package returns index of -1, but incrementing gives index zero which is correct.
|
||||
final int simpleClassNameStartIndex = fullClassName.lastIndexOf('.') + 1;
|
||||
return fullClassName.substring(simpleClassNameStartIndex, dollarSignIndex);
|
||||
}
|
||||
@@ -137,11 +138,19 @@ public class Logger {
|
||||
}
|
||||
|
||||
/**
|
||||
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#context} may not be initialized.
|
||||
* Always logs even if Debugging is not enabled.
|
||||
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
|
||||
* Normally this method should not be used.
|
||||
*/
|
||||
public static void initializationError(@NonNull Class<?> callingClass, @NonNull String message, @Nullable Exception ex) {
|
||||
public static void initializationInfo(@NonNull Class<?> callingClass, @NonNull String message) {
|
||||
Log.i(REVANCED_LOG_PREFIX + callingClass.getSimpleName(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
|
||||
* Normally this method should not be used.
|
||||
*/
|
||||
public static void initializationException(@NonNull Class<?> callingClass, @NonNull String message,
|
||||
@Nullable Exception ex) {
|
||||
Log.e(REVANCED_LOG_PREFIX + callingClass.getSimpleName(), message, ex);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -42,7 +40,7 @@ import kotlin.text.Regex;
|
||||
public class Utils {
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public static Context context;
|
||||
private static Context context;
|
||||
|
||||
private static String versionName;
|
||||
|
||||
@@ -56,13 +54,14 @@ public class Utils {
|
||||
try {
|
||||
final var packageName = Objects.requireNonNull(getContext()).getPackageName();
|
||||
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||
packageInfo = context.getPackageManager().getPackageInfo(
|
||||
packageInfo = packageManager.getPackageInfo(
|
||||
packageName,
|
||||
PackageManager.PackageInfoFlags.of(0)
|
||||
);
|
||||
else
|
||||
packageInfo = context.getPackageManager().getPackageInfo(
|
||||
packageInfo = packageManager.getPackageInfo(
|
||||
packageName,
|
||||
0
|
||||
);
|
||||
@@ -102,7 +101,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 +203,9 @@ public class Utils {
|
||||
public static <T extends View> 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;
|
||||
}
|
||||
}
|
||||
@@ -229,11 +229,25 @@ public class Utils {
|
||||
|
||||
public static Context getContext() {
|
||||
if (context == null) {
|
||||
Logger.initializationError(Utils.class, "Context is null, returning null!", null);
|
||||
Logger.initializationException(Utils.class, "Context is null, returning null!", null);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public static void setContext(Context appContext) {
|
||||
context = appContext;
|
||||
// In some apps like TikTok, the Setting classes can load in weird orders due to cyclic class dependencies.
|
||||
// Calling the regular printDebug method here can cause a Settings context null pointer exception,
|
||||
// even though the context is already set before the call.
|
||||
//
|
||||
// The initialization logger methods do not directly or indirectly
|
||||
// reference the Context or any Settings and are unaffected by this problem.
|
||||
//
|
||||
// Info level also helps debug if a patch hook is called before
|
||||
// the context is set since debug logging is off by default.
|
||||
Logger.initializationInfo(Utils.class, "Set context: " + appContext);
|
||||
}
|
||||
|
||||
public static void setClipboard(@NonNull String text) {
|
||||
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
android.content.ClipData clip = android.content.ClipData.newPlainText("ReVanced", text);
|
||||
@@ -276,7 +290,7 @@ public class Utils {
|
||||
Objects.requireNonNull(messageToToast);
|
||||
runOnMainThreadNowOrLater(() -> {
|
||||
if (context == null) {
|
||||
Logger.initializationError(Utils.class, "Cannot show toast (context is null): " + messageToToast, null);
|
||||
Logger.initializationException(Utils.class, "Cannot show toast (context is null): " + messageToToast, null);
|
||||
} else {
|
||||
Logger.printDebug(() -> "Showing toast: " + messageToToast);
|
||||
Toast.makeText(context, messageToToast, toastDuration).show();
|
||||
@@ -345,6 +359,12 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
public enum NetworkType {
|
||||
NONE,
|
||||
MOBILE,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
public static boolean isNetworkConnected() {
|
||||
NetworkType networkType = getNetworkType();
|
||||
return networkType == NetworkType.MOBILE
|
||||
@@ -393,48 +413,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<String, Preference> 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<String, Preference> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -152,47 +152,60 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a UI Preference with the {@link Setting} that backs it.
|
||||
* Handles syncing a UI Preference with the {@link Setting} that backs it.
|
||||
* If needed, subclasses can override this to handle additional UI Preference types.
|
||||
*
|
||||
* @param applySettingToPreference If true, then apply {@link Setting} -> Preference.
|
||||
* If false, then apply {@link Setting} <- Preference.
|
||||
*/
|
||||
protected void syncSettingWithPreference(@NonNull Preference pref,
|
||||
@NonNull Setting<?> setting,
|
||||
boolean applySettingToPreference) {
|
||||
if (pref instanceof SwitchPreference) {
|
||||
SwitchPreference switchPref = (SwitchPreference) pref;
|
||||
BooleanSetting boolSetting = (BooleanSetting) setting;
|
||||
if (applySettingToPreference) {
|
||||
switchPref.setChecked(boolSetting.get());
|
||||
} else {
|
||||
BooleanSetting.privateSetValue(boolSetting, switchPref.isChecked());
|
||||
}
|
||||
} else if (pref instanceof EditTextPreference) {
|
||||
EditTextPreference editPreference = (EditTextPreference) pref;
|
||||
if (applySettingToPreference) {
|
||||
editPreference.setText(setting.get().toString());
|
||||
} else {
|
||||
Setting.privateSetValueFromString(setting, editPreference.getText());
|
||||
}
|
||||
} else if (pref instanceof ListPreference) {
|
||||
ListPreference listPref = (ListPreference) pref;
|
||||
if (applySettingToPreference) {
|
||||
listPref.setValue(setting.get().toString());
|
||||
} else {
|
||||
Setting.privateSetValueFromString(setting, listPref.getValue());
|
||||
}
|
||||
updateListPreferenceSummary(listPref, setting);
|
||||
} else {
|
||||
Logger.printException(() -> "Setting cannot be handled: " + pref.getClass() + ": " + pref);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a UI Preference with the {@link Setting} that backs it.
|
||||
*
|
||||
* @param syncSetting If the UI should be synced {@link Setting} <-> Preference
|
||||
* @param applySettingToPreference If true, then apply {@link Setting} -> Preference.
|
||||
* If false, then apply {@link Setting} <- Preference.
|
||||
*/
|
||||
protected void updatePreference(@NonNull Preference pref, @NonNull Setting<?> setting,
|
||||
boolean syncSetting, boolean applySettingToPreference) {
|
||||
private void updatePreference(@NonNull Preference pref, @NonNull Setting<?> setting,
|
||||
boolean syncSetting, boolean applySettingToPreference) {
|
||||
if (!syncSetting && applySettingToPreference) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if (syncSetting) {
|
||||
if (pref instanceof SwitchPreference) {
|
||||
SwitchPreference switchPref = (SwitchPreference) pref;
|
||||
BooleanSetting boolSetting = (BooleanSetting) setting;
|
||||
if (applySettingToPreference) {
|
||||
switchPref.setChecked(boolSetting.get());
|
||||
} else {
|
||||
BooleanSetting.privateSetValue(boolSetting, switchPref.isChecked());
|
||||
}
|
||||
} else if (pref instanceof EditTextPreference) {
|
||||
EditTextPreference editPreference = (EditTextPreference) pref;
|
||||
if (applySettingToPreference) {
|
||||
editPreference.setText(setting.get().toString());
|
||||
} else {
|
||||
Setting.privateSetValueFromString(setting, editPreference.getText());
|
||||
}
|
||||
} else if (pref instanceof ListPreference) {
|
||||
ListPreference listPref = (ListPreference) pref;
|
||||
if (applySettingToPreference) {
|
||||
listPref.setValue(setting.get().toString());
|
||||
} else {
|
||||
Setting.privateSetValueFromString(setting, listPref.getValue());
|
||||
}
|
||||
updateListPreferenceSummary(listPref, setting);
|
||||
} else {
|
||||
Logger.printException(() -> "Setting cannot be handled: " + pref.getClass() + ": " + pref);
|
||||
return;
|
||||
}
|
||||
syncSettingWithPreference(pref, setting, applySettingToPreference);
|
||||
}
|
||||
|
||||
updatePreferenceAvailability(pref, setting);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package app.revanced.integrations.tiktok.settings.preference;
|
||||
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceScreen;
|
||||
import androidx.annotation.NonNull;
|
||||
import app.revanced.integrations.shared.settings.Setting;
|
||||
import app.revanced.integrations.shared.settings.preference.AbstractPreferenceFragment;
|
||||
import app.revanced.integrations.tiktok.settings.preference.categories.DownloadsPreferenceCategory;
|
||||
import app.revanced.integrations.tiktok.settings.preference.categories.FeedFilterPreferenceCategory;
|
||||
import app.revanced.integrations.tiktok.settings.preference.categories.IntegrationsPreferenceCategory;
|
||||
import app.revanced.integrations.tiktok.settings.preference.categories.SimSpoofPreferenceCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Preference fragment for ReVanced settings
|
||||
@@ -13,6 +17,21 @@ import app.revanced.integrations.tiktok.settings.preference.categories.SimSpoofP
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
|
||||
@Override
|
||||
protected void syncSettingWithPreference(@NonNull @NotNull Preference pref,
|
||||
@NonNull @NotNull Setting<?> setting,
|
||||
boolean applySettingToPreference) {
|
||||
if (pref instanceof RangeValuePreference) {
|
||||
RangeValuePreference rangeValuePref = (RangeValuePreference) pref;
|
||||
Setting.privateSetValueFromString(setting, rangeValuePref.getValue());
|
||||
} else if (pref instanceof DownloadPathPreference) {
|
||||
DownloadPathPreference downloadPathPref = (DownloadPathPreference) pref;
|
||||
Setting.privateSetValueFromString(setting, downloadPathPref.getValue());
|
||||
} else {
|
||||
super.syncSettingWithPreference(pref, setting, applySettingToPreference);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() {
|
||||
final var context = getContext();
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
package app.revanced.integrations.tiktok.spoof.sim;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.tiktok.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofSimPatch {
|
||||
public static boolean isEnable() {
|
||||
return Settings.SIM_SPOOF.get();
|
||||
}
|
||||
public static String getCountryIso(String value) {
|
||||
if (isEnable()) {
|
||||
return Settings.SIM_SPOOF_ISO.get();
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final Boolean ENABLED = Settings.SIM_SPOOF.get();
|
||||
|
||||
public static String getCountryIso(String value) {
|
||||
if (ENABLED) {
|
||||
String iso = Settings.SIM_SPOOF_ISO.get();
|
||||
Logger.printDebug(() -> "Spoofing sim ISO from: " + value + " to: " + iso);
|
||||
return iso;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getOperator(String value) {
|
||||
if (isEnable()) {
|
||||
return Settings.SIMSPOOF_MCCMNC.get();
|
||||
} else {
|
||||
return value;
|
||||
if (ENABLED) {
|
||||
String mcc_mnc = Settings.SIMSPOOF_MCCMNC.get();
|
||||
Logger.printDebug(() -> "Spoofing sim MCC-MNC from: " + value + " to: " + mcc_mnc);
|
||||
return mcc_mnc;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getOperatorName(String value) {
|
||||
if (isEnable()) {
|
||||
return Settings.SIMSPOOF_OP_NAME.get();
|
||||
} else {
|
||||
return value;
|
||||
if (ENABLED) {
|
||||
String operator = Settings.SIMSPOOF_OP_NAME.get();
|
||||
Logger.printDebug(() -> "Spoofing sim operator from: " + value + " to: " + operator);
|
||||
return operator;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ abstract class BaseJsonHook : JsonHook {
|
||||
abstract fun apply(json: JSONObject)
|
||||
|
||||
override fun transform(json: JSONObject) = json.apply { apply(json) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ interface JsonHook : Hook<JSONObject> {
|
||||
fun transform(json: JSONObject): JSONObject
|
||||
|
||||
override fun hook(type: JSONObject) = transform(type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,4 @@ object JsonHookPatch {
|
||||
|
||||
return StreamUtils.fromString(jsonObject.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ interface Hook<T> {
|
||||
* @param type The type to hook
|
||||
*/
|
||||
fun hook(type: T): T
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import app.revanced.integrations.twitter.patches.hook.json.BaseJsonHook
|
||||
import app.revanced.integrations.twitter.patches.hook.twifucker.TwiFucker
|
||||
import org.json.JSONObject
|
||||
|
||||
|
||||
object AdsHook : BaseJsonHook() {
|
||||
/**
|
||||
* Strips JSONObject from promoted ads.
|
||||
@@ -12,4 +11,4 @@ object AdsHook : BaseJsonHook() {
|
||||
* @param json The JSONObject.
|
||||
*/
|
||||
override fun apply(json: JSONObject) = TwiFucker.hidePromotedAds(json)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ object DummyHook : BaseJsonHook() {
|
||||
override fun apply(json: JSONObject) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import app.revanced.integrations.twitter.patches.hook.json.BaseJsonHook
|
||||
import app.revanced.integrations.twitter.patches.hook.twifucker.TwiFucker
|
||||
import org.json.JSONObject
|
||||
|
||||
|
||||
object RecommendedUsersHook : BaseJsonHook() {
|
||||
/**
|
||||
* Strips JSONObject from recommended users.
|
||||
@@ -12,4 +11,4 @@ object RecommendedUsersHook : BaseJsonHook() {
|
||||
* @param json The JSONObject.
|
||||
*/
|
||||
override fun apply(json: JSONObject) = TwiFucker.hideRecommendedUsers(json)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ package app.revanced.integrations.twitter.patches.links;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
public final class OpenLinksWithAppChooserPatch {
|
||||
public static void openWithChooser(final Context context, final Intent intent) {
|
||||
Log.d("ReVanced", "Opening intent with chooser: " + intent);
|
||||
|
||||
intent.setAction("android.intent.action.VIEW");
|
||||
|
||||
context.startActivity(Intent.createChooser(intent, null));
|
||||
|
||||
@@ -10,4 +10,4 @@ object JsonUtils {
|
||||
@JvmStatic
|
||||
@Throws(IOException::class, JSONException::class)
|
||||
fun parseJson(jsonInputStream: InputStream) = JSONObject(StreamUtils.toString(jsonInputStream))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ object StreamUtils {
|
||||
fun fromString(string: String): InputStream {
|
||||
return ByteArrayInputStream(string.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,3 @@ class Event<T> {
|
||||
observer.invoke(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package app.revanced.integrations.youtube.patches;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.StringRef;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class DownloadsPatch {
|
||||
|
||||
private static WeakReference<Activity> activityRef = new WeakReference<>(null);
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void activityCreated(Activity mainActivity) {
|
||||
activityRef = new WeakReference<>(mainActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* Called from the in app download hook,
|
||||
* for both the player action button (below the video)
|
||||
* and the 'Download video' flyout option for feed videos.
|
||||
*
|
||||
* Appears to always be called from the main thread.
|
||||
*/
|
||||
public static boolean inAppDownloadButtonOnClick(@NonNull String videoId) {
|
||||
try {
|
||||
if (!Settings.EXTERNAL_DOWNLOADER_ACTION_BUTTON.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If possible, use the main activity as the context.
|
||||
// Otherwise fall back on using the application context.
|
||||
Context context = activityRef.get();
|
||||
boolean isActivityContext = true;
|
||||
if (context == null) {
|
||||
// Utils context is the application context, and not an activity context.
|
||||
context = Utils.getContext();
|
||||
isActivityContext = false;
|
||||
}
|
||||
|
||||
launchExternalDownloader(videoId, context, isActivityContext);
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "inAppDownloadButtonOnClick failure", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isActivityContext If the context parameter is for an Activity. If this is false, then
|
||||
* the downloader is opened as a new task (which forces YT to minimize).
|
||||
*/
|
||||
public static void launchExternalDownloader(@NonNull String videoId,
|
||||
@NonNull Context context, boolean isActivityContext) {
|
||||
try {
|
||||
Objects.requireNonNull(videoId);
|
||||
Logger.printDebug(() -> "Launching external downloader with context: " + context);
|
||||
|
||||
// Trim string to avoid any accidental whitespace.
|
||||
var downloaderPackageName = Settings.EXTERNAL_DOWNLOADER_PACKAGE_NAME.get().trim();
|
||||
|
||||
boolean packageEnabled = false;
|
||||
try {
|
||||
packageEnabled = context.getPackageManager().getApplicationInfo(downloaderPackageName, 0).enabled;
|
||||
} catch (PackageManager.NameNotFoundException error) {
|
||||
Logger.printDebug(() -> "External downloader could not be found: " + error);
|
||||
}
|
||||
|
||||
// If the package is not installed, show the toast
|
||||
if (!packageEnabled) {
|
||||
Utils.showToastLong(StringRef.str("revanced_external_downloader_not_installed_warning", downloaderPackageName));
|
||||
return;
|
||||
}
|
||||
|
||||
String content = "https://youtu.be/" + videoId;
|
||||
Intent intent = new Intent("android.intent.action.SEND");
|
||||
intent.setType("text/plain");
|
||||
intent.setPackage(downloaderPackageName);
|
||||
intent.putExtra("android.intent.extra.TEXT", content);
|
||||
if (!isActivityContext) {
|
||||
Logger.printDebug(() -> "Using new task intent");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
context.startActivity(intent);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "launchExternalDownloader failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,12 @@ import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.youtube.swipecontrols.SwipeControlsHostActivity;
|
||||
|
||||
/**
|
||||
* Patch class for 'hdr-auto-brightness' patch
|
||||
* Patch class for 'hdr-auto-brightness' patch.
|
||||
*
|
||||
* Edit: This patch no longer does anything, as YT already uses BRIGHTNESS_OVERRIDE_NONE
|
||||
* as the default brightness level. The hooked code was also removed from YT 19.09+ as well.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unused")
|
||||
public class HDRAutoBrightnessPatch {
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@ public class HideBreakingNewsPatch {
|
||||
* Breaking news does not appear to be present in these older versions anyways.
|
||||
*/
|
||||
private static final boolean isSpoofingOldVersionWithHorizontalCardListWatchHistory =
|
||||
SpoofAppVersionPatch.isSpoofingToEqualOrLessThan("17.31.00");
|
||||
SpoofAppVersionPatch.isSpoofingToLessThan("18.01.00");
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
|
||||
@@ -6,24 +6,12 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.youtube.shared.PlayerOverlays;
|
||||
|
||||
/**
|
||||
* Hook receiver class for 'player-overlays-hook' patch
|
||||
*
|
||||
* @usedBy app.revanced.patches.youtube.misc.playeroverlay.patch.PlayerOverlaysHookPatch
|
||||
* @smali Lapp/revanced/integrations/patches/PlayerOverlaysHookPatch;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PlayerOverlaysHookPatch {
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* @param thisRef reference to the view
|
||||
* @smali YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava / lang / Object ;)V
|
||||
*/
|
||||
public static void YouTubePlayerOverlaysLayout_onFinishInflateHook(@Nullable Object thisRef) {
|
||||
if (thisRef == null) return;
|
||||
if (thisRef instanceof ViewGroup) {
|
||||
PlayerOverlays.attach((ViewGroup) thisRef);
|
||||
}
|
||||
public static void playerOverlayInflated(ViewGroup group) {
|
||||
PlayerOverlays.attach(group);
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ import static app.revanced.integrations.youtube.returnyoutubedislike.ReturnYouTu
|
||||
public class ReturnYouTubeDislikePatch {
|
||||
|
||||
public static final boolean IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER =
|
||||
SpoofAppVersionPatch.isSpoofingToEqualOrLessThan("18.33.40");
|
||||
SpoofAppVersionPatch.isSpoofingToLessThan("18.34.00");
|
||||
|
||||
/**
|
||||
* RYD data for the current video on screen.
|
||||
|
||||
@@ -6,12 +6,11 @@ import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.youtube.patches.announcements.requests.AnnouncementsRoutes;
|
||||
import app.revanced.integrations.youtube.requests.Requester;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -49,9 +48,10 @@ public final class AnnouncementsPatch {
|
||||
try {
|
||||
// Do not show the announcement if the request failed.
|
||||
if (connection.getResponseCode() != 200) {
|
||||
if (Settings.ANNOUNCEMENT_LAST_HASH.get().isEmpty()) return;
|
||||
if (Settings.ANNOUNCEMENT_LAST_ID.isSetToDefault())
|
||||
return;
|
||||
|
||||
Settings.ANNOUNCEMENT_LAST_HASH.resetToDefault();
|
||||
Settings.ANNOUNCEMENT_LAST_ID.resetToDefault();
|
||||
Utils.showToastLong(str("revanced_announcements_connection_failed"));
|
||||
|
||||
return;
|
||||
@@ -65,22 +65,20 @@ public final class AnnouncementsPatch {
|
||||
|
||||
var jsonString = Requester.parseInputStreamAndClose(connection.getInputStream(), false);
|
||||
|
||||
// Do not show the announcement if it is older or the same as the last one.
|
||||
final byte[] hashBytes = MessageDigest.getInstance("SHA-256").digest(jsonString.getBytes(StandardCharsets.UTF_8));
|
||||
final var hash = java.util.Base64.getEncoder().encodeToString(hashBytes);
|
||||
if (hash.equals(Settings.ANNOUNCEMENT_LAST_HASH.get())) return;
|
||||
|
||||
// Parse the announcement. Fall-back to raw string if it fails.
|
||||
int id = Settings.ANNOUNCEMENT_LAST_ID.defaultValue;
|
||||
String title;
|
||||
String message;
|
||||
Level level = Level.INFO;
|
||||
try {
|
||||
final var announcement = new JSONObject(jsonString);
|
||||
|
||||
id = announcement.getInt("id");
|
||||
title = announcement.getString("title");
|
||||
message = announcement.getJSONObject("content").getString("message");
|
||||
|
||||
if (!announcement.isNull("level")) level = Level.fromInt(announcement.getInt("level"));
|
||||
|
||||
} catch (Throwable ex) {
|
||||
Logger.printException(() -> "Failed to parse announcement. Fall-backing to raw string", ex);
|
||||
|
||||
@@ -88,6 +86,28 @@ public final class AnnouncementsPatch {
|
||||
message = jsonString;
|
||||
}
|
||||
|
||||
// TODO: Remove this migration code after a few months.
|
||||
if (!Settings.DEPRECATED_ANNOUNCEMENT_LAST_HASH.isSetToDefault()){
|
||||
final byte[] hashBytes = MessageDigest
|
||||
.getInstance("SHA-256")
|
||||
.digest(jsonString.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
final var hash = java.util.Base64.getEncoder().encodeToString(hashBytes);
|
||||
|
||||
// Migrate to saving the id instead of the hash.
|
||||
if (hash.equals(Settings.DEPRECATED_ANNOUNCEMENT_LAST_HASH.get())) {
|
||||
Settings.ANNOUNCEMENT_LAST_ID.save(id);
|
||||
}
|
||||
|
||||
Settings.DEPRECATED_ANNOUNCEMENT_LAST_HASH.resetToDefault();
|
||||
}
|
||||
|
||||
// Do not show the announcement, if the last announcement id is the same as the current one.
|
||||
if (Settings.ANNOUNCEMENT_LAST_ID.get() == id) return;
|
||||
|
||||
|
||||
|
||||
int finalId = id;
|
||||
final var finalTitle = title;
|
||||
final var finalMessage = Html.fromHtml(message, FROM_HTML_MODE_COMPACT);
|
||||
final Level finalLevel = level;
|
||||
@@ -99,7 +119,7 @@ public final class AnnouncementsPatch {
|
||||
.setMessage(finalMessage)
|
||||
.setIcon(finalLevel.icon)
|
||||
.setPositiveButton("Ok", (dialog, which) -> {
|
||||
Settings.ANNOUNCEMENT_LAST_HASH.save(hash);
|
||||
Settings.ANNOUNCEMENT_LAST_ID.save(finalId);
|
||||
dialog.dismiss();
|
||||
}).setNegativeButton("Dismiss", (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
@@ -119,18 +139,6 @@ public final class AnnouncementsPatch {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the last announcement hash if it is not empty.
|
||||
*
|
||||
* @return true if the last announcement hash was empty.
|
||||
*/
|
||||
private static boolean emptyLastAnnouncementHash() {
|
||||
if (Settings.ANNOUNCEMENT_LAST_HASH.get().isEmpty()) return true;
|
||||
Settings.ANNOUNCEMENT_LAST_HASH.resetToDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getOrSetConsumer() {
|
||||
final var consumer = Settings.ANNOUNCEMENT_CONSUMER.get();
|
||||
if (!consumer.isEmpty()) return consumer;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package app.revanced.integrations.youtube.patches.components;
|
||||
|
||||
import static app.revanced.integrations.shared.StringRef.str;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
@@ -170,7 +172,24 @@ public final class AdsFilter extends Filter {
|
||||
|
||||
Utils.runOnMainThreadDelayed(() -> {
|
||||
// Must run off main thread (Odd, but whatever).
|
||||
Utils.runOnBackgroundThread(() -> instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK));
|
||||
Utils.runOnBackgroundThread(() -> {
|
||||
try {
|
||||
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
|
||||
} catch (Exception ex) {
|
||||
// Injecting user events on Android 10+ requires the manifest to include
|
||||
// INJECT_EVENTS, and it's usage is heavily restricted
|
||||
// and requires the user to manually approve the permission in the device settings.
|
||||
//
|
||||
// And no matter what, permissions cannot be added for root installations
|
||||
// as manifest changes are ignored for mount installations.
|
||||
//
|
||||
// Instead, catch the SecurityException and turn off hide full screen ads
|
||||
// since this functionality does not work for these devices.
|
||||
Logger.printInfo(() -> "Could not inject back button event", ex);
|
||||
Settings.HIDE_FULLSCREEN_ADS.save(false);
|
||||
Utils.showToastLong(str("revanced_hide_fullscreen_ads_feature_not_available_toast"));
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,26 +1,12 @@
|
||||
package app.revanced.integrations.youtube.patches.spoof;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofAppVersionPatch {
|
||||
|
||||
private static final boolean SPOOF_APP_VERSION_ENABLED;
|
||||
private static final String SPOOF_APP_VERSION_TARGET;
|
||||
|
||||
static {
|
||||
// TODO: remove this migration code
|
||||
// Spoof targets 16.x and 17.x that no longer reliably work.
|
||||
if (Settings.SPOOF_APP_VERSION_TARGET.get().compareTo("18.01.01") < 0) {
|
||||
Logger.printInfo(() -> "Resetting spoof app version target");
|
||||
Settings.SPOOF_APP_VERSION_TARGET.resetToDefault();
|
||||
}
|
||||
// End migration
|
||||
|
||||
SPOOF_APP_VERSION_ENABLED = Settings.SPOOF_APP_VERSION.get();
|
||||
SPOOF_APP_VERSION_TARGET = Settings.SPOOF_APP_VERSION_TARGET.get();
|
||||
}
|
||||
private static final boolean SPOOF_APP_VERSION_ENABLED = Settings.SPOOF_APP_VERSION.get();
|
||||
private static final String SPOOF_APP_VERSION_TARGET = Settings.SPOOF_APP_VERSION_TARGET.get();
|
||||
|
||||
/**
|
||||
* Injection point
|
||||
@@ -30,8 +16,8 @@ public class SpoofAppVersionPatch {
|
||||
return version;
|
||||
}
|
||||
|
||||
public static boolean isSpoofingToEqualOrLessThan(String version) {
|
||||
return SPOOF_APP_VERSION_ENABLED && SPOOF_APP_VERSION_TARGET.compareTo(version) <= 0;
|
||||
public static boolean isSpoofingToLessThan(String version) {
|
||||
return SPOOF_APP_VERSION_ENABLED && SPOOF_APP_VERSION_TARGET.compareTo(version) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class SpoofSignaturePatch {
|
||||
try {
|
||||
Logger.printDebug(() -> "Original protobuf parameter value: " + parameters);
|
||||
|
||||
if (!Settings.SPOOF_SIGNATURE.get()) {
|
||||
if (parameters == null || !Settings.SPOOF_SIGNATURE.get()) {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class SpoofSignaturePatch {
|
||||
// For this reason, the player parameters of a clip are usually very long (150~300 characters).
|
||||
// Clips are 60 seconds or less in length, so no spoofing.
|
||||
//noinspection AssignmentUsedAsCondition
|
||||
if (useOriginalStoryboardRenderer = parameters.length() > 150 || containsAny(parameters, CLIPS_PARAMETERS)) {
|
||||
if (useOriginalStoryboardRenderer = parameters.length() > 150 || parameters.startsWith(CLIPS_PARAMETERS)) {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ReturnYouTubeDislike {
|
||||
private static final char MIDDLE_SEPARATOR_CHARACTER = '◎'; // 'bullseye'
|
||||
|
||||
private static final boolean IS_SPOOFING_TO_OLD_SEPARATOR_COLOR
|
||||
= SpoofAppVersionPatch.isSpoofingToEqualOrLessThan("18.09.39");
|
||||
= SpoofAppVersionPatch.isSpoofingToLessThan("18.10.00");
|
||||
|
||||
/**
|
||||
* Cached lookup of all video ids.
|
||||
|
||||
@@ -1,43 +1,32 @@
|
||||
package app.revanced.integrations.youtube.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.integrations.shared.settings.Setting.migrateFromOldPreferences;
|
||||
import static app.revanced.integrations.shared.settings.Setting.migrateOldSettingToNew;
|
||||
import static app.revanced.integrations.shared.settings.Setting.parent;
|
||||
import static app.revanced.integrations.shared.settings.Setting.parentsAny;
|
||||
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
|
||||
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
|
||||
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
|
||||
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.settings.*;
|
||||
import app.revanced.integrations.shared.settings.preference.SharedPrefCategory;
|
||||
import app.revanced.integrations.youtube.patches.spoof.SpoofAppVersionPatch;
|
||||
import app.revanced.integrations.youtube.sponsorblock.SponsorBlockSettings;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
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.youtube.sponsorblock.SponsorBlockSettings;
|
||||
import static app.revanced.integrations.shared.settings.Setting.*;
|
||||
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.*;
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
|
||||
public class Settings extends BaseSettings {
|
||||
// External downloader
|
||||
public static final BooleanSetting EXTERNAL_DOWNLOADER = new BooleanSetting("revanced_external_downloader", FALSE);
|
||||
public static final BooleanSetting EXTERNAL_DOWNLOADER_ACTION_BUTTON = new BooleanSetting("revanced_external_downloader_action_button", FALSE);
|
||||
public static final StringSetting EXTERNAL_DOWNLOADER_PACKAGE_NAME = new StringSetting("revanced_external_downloader_name",
|
||||
"org.schabi.newpipe" /* NewPipe */, parent(EXTERNAL_DOWNLOADER));
|
||||
"org.schabi.newpipe" /* NewPipe */, parentsAny(EXTERNAL_DOWNLOADER, EXTERNAL_DOWNLOADER_ACTION_BUTTON));
|
||||
|
||||
// Copy video URL
|
||||
public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE);
|
||||
public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE);
|
||||
|
||||
// Video
|
||||
public static final BooleanSetting HDR_AUTO_BRIGHTNESS = new BooleanSetting("revanced_hdr_auto_brightness", TRUE);
|
||||
public static final BooleanSetting RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
|
||||
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", TRUE);
|
||||
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
|
||||
@@ -46,6 +35,8 @@ public class Settings extends BaseSettings {
|
||||
public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", 1.0f);
|
||||
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
|
||||
"0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0", true);
|
||||
@Deprecated // Patch is obsolete and no longer works with 19.09+
|
||||
public static final BooleanSetting HDR_AUTO_BRIGHTNESS = new BooleanSetting("revanced_hdr_auto_brightness", TRUE);
|
||||
|
||||
// Ads
|
||||
public static final BooleanSetting HIDE_FULLSCREEN_ADS = new BooleanSetting("revanced_hide_fullscreen_ads", TRUE);
|
||||
@@ -73,7 +64,7 @@ public class Settings extends BaseSettings {
|
||||
public static final BooleanSetting DISABLE_FULLSCREEN_AMBIENT_MODE = new BooleanSetting("revanced_disable_fullscreen_ambient_mode", TRUE, true);
|
||||
public static final BooleanSetting DISABLE_RESUMING_SHORTS_PLAYER = new BooleanSetting("revanced_disable_resuming_shorts_player", FALSE);
|
||||
public static final BooleanSetting DISABLE_ROLLING_NUMBER_ANIMATIONS = new BooleanSetting("revanced_disable_rolling_number_animations", FALSE);
|
||||
public static final BooleanSetting DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", TRUE);
|
||||
public static final BooleanSetting DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE);
|
||||
public static final BooleanSetting GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_gradient_loading_screen", FALSE);
|
||||
public static final BooleanSetting HIDE_ALBUM_CARDS = new BooleanSetting("revanced_hide_album_cards", FALSE, true);
|
||||
public static final BooleanSetting HIDE_ARTIST_CARDS = new BooleanSetting("revanced_hide_artist_cards", FALSE);
|
||||
@@ -129,7 +120,7 @@ public class Settings extends BaseSettings {
|
||||
public static final IntegerSetting PLAYER_OVERLAY_OPACITY = new IntegerSetting("revanced_player_overlay_opacity",100, true);
|
||||
public static final BooleanSetting PLAYER_POPUP_PANELS = new BooleanSetting("revanced_hide_player_popup_panels", FALSE);
|
||||
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");
|
||||
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "18.09.39", true, parent(SPOOF_APP_VERSION));
|
||||
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "17.33.42", true, parent(SPOOF_APP_VERSION));
|
||||
public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true);
|
||||
public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message");
|
||||
public static final BooleanSetting USE_TABLET_MINIPLAYER = new BooleanSetting("revanced_tablet_miniplayer", FALSE, true);
|
||||
@@ -160,14 +151,13 @@ public class Settings extends BaseSettings {
|
||||
|
||||
// Seekbar
|
||||
public static final BooleanSetting RESTORE_OLD_SEEKBAR_THUMBNAILS = new BooleanSetting("revanced_restore_old_seekbar_thumbnails", TRUE);
|
||||
public static final BooleanSetting HIDE_SEEKBAR = new BooleanSetting("revanced_hide_seekbar", FALSE);
|
||||
public static final BooleanSetting HIDE_SEEKBAR = new BooleanSetting("revanced_hide_seekbar", FALSE, true);
|
||||
public static final BooleanSetting HIDE_SEEKBAR_THUMBNAIL = new BooleanSetting("revanced_hide_seekbar_thumbnail", FALSE);
|
||||
public static final BooleanSetting SEEKBAR_CUSTOM_COLOR = new BooleanSetting("revanced_seekbar_custom_color", TRUE, true);
|
||||
public static final BooleanSetting SEEKBAR_CUSTOM_COLOR = new BooleanSetting("revanced_seekbar_custom_color", FALSE, true);
|
||||
public static final StringSetting SEEKBAR_CUSTOM_COLOR_VALUE = new StringSetting("revanced_seekbar_custom_color_value", "#FF0000", true, parent(SEEKBAR_CUSTOM_COLOR));
|
||||
|
||||
// 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);
|
||||
@@ -207,7 +197,9 @@ public class Settings extends BaseSettings {
|
||||
public static final BooleanSetting BYPASS_URL_REDIRECTS = new BooleanSetting("revanced_bypass_url_redirects", TRUE);
|
||||
public static final BooleanSetting ANNOUNCEMENTS = new BooleanSetting("revanced_announcements", TRUE);
|
||||
public static final StringSetting ANNOUNCEMENT_CONSUMER = new StringSetting("revanced_announcement_consumer", "", false, false);
|
||||
public static final StringSetting ANNOUNCEMENT_LAST_HASH = new StringSetting("revanced_announcement_last_hash", "");
|
||||
@Deprecated
|
||||
public static final StringSetting DEPRECATED_ANNOUNCEMENT_LAST_HASH = new StringSetting("revanced_announcement_last_hash", "");
|
||||
public static final IntegerSetting ANNOUNCEMENT_LAST_ID = new IntegerSetting("revanced_announcement_last_id", -1);
|
||||
public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE);
|
||||
public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG= new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE,
|
||||
"revanced_remove_viewer_discretion_dialog_user_dialog_message");
|
||||
@@ -247,6 +239,7 @@ public class Settings extends BaseSettings {
|
||||
* Do not use directly, instead use {@link SponsorBlockSettings}
|
||||
*/
|
||||
public static final StringSetting SB_PRIVATE_USER_ID = new StringSetting("sb_private_user_id_Do_Not_Share", "");
|
||||
@Deprecated
|
||||
public static final StringSetting DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING = new StringSetting("uuid", ""); // Delete sometime in 2024
|
||||
public static final IntegerSetting SB_CREATE_NEW_SEGMENT_STEP = new IntegerSetting("sb_create_new_segment_step", 150, parent(SB_ENABLED));
|
||||
public static final BooleanSetting SB_VOTING_BUTTON = new BooleanSetting("sb_voting_button", FALSE, parent(SB_ENABLED));
|
||||
@@ -345,6 +338,14 @@ public class Settings extends BaseSettings {
|
||||
// and more time should be given for users who rarely upgrade.
|
||||
migrateOldSettingToNew(DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING, SB_PRIVATE_USER_ID);
|
||||
|
||||
|
||||
// Old spoof versions that no longer work reliably.
|
||||
if (SpoofAppVersionPatch.isSpoofingToLessThan("17.33.00")) {
|
||||
Logger.printInfo(() -> "Resetting spoof app version target");
|
||||
Settings.SPOOF_APP_VERSION_TARGET.resetToDefault();
|
||||
}
|
||||
|
||||
|
||||
// endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package app.revanced.integrations.youtube.settings.preference;
|
||||
|
||||
import android.os.Build;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceGroup;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.settings.preference.AbstractPreferenceFragment;
|
||||
import app.revanced.integrations.youtube.patches.DownloadsPatch;
|
||||
import app.revanced.integrations.youtube.patches.playback.speed.CustomPlaybackSpeedPatch;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
|
||||
@@ -12,14 +19,20 @@ import app.revanced.integrations.youtube.settings.Settings;
|
||||
* @noinspection deprecation
|
||||
*/
|
||||
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@Override
|
||||
protected void initialize() {
|
||||
super.initialize();
|
||||
|
||||
// If the preference was included, then initialize it based on the available playback speed
|
||||
Preference defaultSpeedPreference = findPreference(Settings.PLAYBACK_SPEED_DEFAULT.key);
|
||||
if (defaultSpeedPreference instanceof ListPreference) {
|
||||
CustomPlaybackSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference);
|
||||
try {
|
||||
// If the preference was included, then initialize it based on the available playback speed.
|
||||
Preference defaultSpeedPreference = findPreference(Settings.PLAYBACK_SPEED_DEFAULT.key);
|
||||
if (defaultSpeedPreference instanceof ListPreference) {
|
||||
CustomPlaybackSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "initialize failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user