mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-23 02:31:03 +00:00
feat(YouTube Music): Add Settings patch (#5838)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class HideCategoryBarPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point
|
||||||
|
*/
|
||||||
|
public static boolean hideCategoryBar() {
|
||||||
|
return Settings.HIDE_CATEGORY_BAR.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class HideGetPremiumPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point
|
||||||
|
*/
|
||||||
|
public static boolean hideGetPremiumLabel() {
|
||||||
|
return Settings.HIDE_GET_PREMIUM_LABEL.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class HideUpgradeButtonPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point
|
||||||
|
*/
|
||||||
|
public static boolean hideUpgradeButton() {
|
||||||
|
return Settings.HIDE_UPGRADE_BUTTON.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class HideVideoAdsPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point
|
||||||
|
*/
|
||||||
|
public static boolean showVideoAds(boolean original) {
|
||||||
|
if (Settings.HIDE_VIDEO_ADS.get()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class PermanentRepeatPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point
|
||||||
|
*/
|
||||||
|
public static boolean permanentRepeat() {
|
||||||
|
return Settings.PERMANENT_REPEAT.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package app.revanced.extension.music.settings;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.preference.ReVancedPreferenceFragment;
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.BaseActivityHook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooks GoogleApiActivity to inject a custom ReVancedPreferenceFragment with a toolbar.
|
||||||
|
*/
|
||||||
|
public class GoogleApiActivityHook extends BaseActivityHook {
|
||||||
|
/**
|
||||||
|
* Injection point
|
||||||
|
* <p>
|
||||||
|
* Creates an instance of GoogleApiActivityHook for use in static initialization.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static GoogleApiActivityHook createInstance() {
|
||||||
|
// Must touch the Music settings to ensure the class is loaded and
|
||||||
|
// the values can be found when setting the UI preferences.
|
||||||
|
// Logging anything under non debug ensures this is set.
|
||||||
|
Logger.printInfo(() -> "Permanent repeat enabled: " + Settings.PERMANENT_REPEAT.get());
|
||||||
|
|
||||||
|
return new GoogleApiActivityHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fixed theme for the activity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void customizeActivityTheme(Activity activity) {
|
||||||
|
// Override the default YouTube Music theme to increase start padding of list items.
|
||||||
|
// Custom style located in resources/music/values/style.xml
|
||||||
|
activity.setTheme(Utils.getResourceIdentifier("Theme.ReVanced.YouTubeMusic.Settings", "style"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resource ID for the YouTube Music settings layout.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected int getContentViewResourceId() {
|
||||||
|
return Utils.getResourceIdentifier("revanced_music_settings_with_toolbar", "layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fixed background color for the toolbar.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected int getToolbarBackgroundColor() {
|
||||||
|
return Utils.getResourceColor("ytm_color_black");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the navigation icon with a color filter applied.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Drawable getNavigationIcon() {
|
||||||
|
Drawable navigationIcon = ReVancedPreferenceFragment.getBackButtonDrawable();
|
||||||
|
navigationIcon.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN);
|
||||||
|
return navigationIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the click listener that finishes the activity when the navigation icon is clicked.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected View.OnClickListener getNavigationClickListener(Activity activity) {
|
||||||
|
return view -> activity.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ReVancedPreferenceFragment for the activity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected PreferenceFragment createPreferenceFragment() {
|
||||||
|
return new ReVancedPreferenceFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.extension.music.settings;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.FALSE;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
|
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||||
|
|
||||||
|
public class Settings extends BaseSettings {
|
||||||
|
|
||||||
|
// Ads
|
||||||
|
public static final BooleanSetting HIDE_VIDEO_ADS = new BooleanSetting("revanced_music_hide_video_ads", TRUE, true);
|
||||||
|
public static final BooleanSetting HIDE_GET_PREMIUM_LABEL = new BooleanSetting("revanced_music_hide_get_premium_label", TRUE, true);
|
||||||
|
public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true);
|
||||||
|
|
||||||
|
// General
|
||||||
|
public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true);
|
||||||
|
|
||||||
|
// Player
|
||||||
|
public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package app.revanced.extension.music.settings.preference;
|
||||||
|
|
||||||
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.GoogleApiActivityHook;
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference fragment for ReVanced settings.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"deprecation", "NewApi"})
|
||||||
|
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the preference fragment.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Utils.sortPreferenceGroups(getPreferenceScreen());
|
||||||
|
setPreferenceScreenToolbar(getPreferenceScreen());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "initialize failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets toolbar for all nested preference screens.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void customizeToolbar(Toolbar toolbar) {
|
||||||
|
GoogleApiActivityHook.setToolbarLayoutParams(toolbar);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package app.revanced.extension.shared.settings;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for hooking activities to inject a custom PreferenceFragment with a toolbar.
|
||||||
|
* Provides common logic for initializing the activity and setting up the toolbar.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"deprecation", "NewApi"})
|
||||||
|
public abstract class BaseActivityHook extends Activity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout parameters for the toolbar, extracted from the dummy toolbar.
|
||||||
|
*/
|
||||||
|
protected static ViewGroup.LayoutParams toolbarLayoutParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the layout parameters for the toolbar.
|
||||||
|
*/
|
||||||
|
public static void setToolbarLayoutParams(Toolbar toolbar) {
|
||||||
|
if (toolbarLayoutParams != null) {
|
||||||
|
toolbar.setLayoutParams(toolbarLayoutParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the activity by setting the theme, content view and injecting a PreferenceFragment.
|
||||||
|
*/
|
||||||
|
public static void initialize(BaseActivityHook hook, Activity activity) {
|
||||||
|
try {
|
||||||
|
hook.customizeActivityTheme(activity);
|
||||||
|
activity.setContentView(hook.getContentViewResourceId());
|
||||||
|
|
||||||
|
// Sanity check.
|
||||||
|
String dataString = activity.getIntent().getDataString();
|
||||||
|
if (!"revanced_settings_intent".equals(dataString)) {
|
||||||
|
Logger.printException(() -> "Unknown intent: " + dataString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferenceFragment fragment = hook.createPreferenceFragment();
|
||||||
|
hook.createToolbar(activity, fragment);
|
||||||
|
|
||||||
|
activity.getFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.replace(Utils.getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
|
||||||
|
.commit();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "initialize failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and configures a toolbar for the activity, replacing a dummy placeholder.
|
||||||
|
*/
|
||||||
|
@SuppressLint("UseCompatLoadingForDrawables")
|
||||||
|
protected void createToolbar(Activity activity, PreferenceFragment fragment) {
|
||||||
|
// Replace dummy placeholder toolbar.
|
||||||
|
// This is required to fix submenu title alignment issue with Android ASOP 15+
|
||||||
|
ViewGroup toolBarParent = activity.findViewById(
|
||||||
|
Utils.getResourceIdentifier("revanced_toolbar_parent", "id"));
|
||||||
|
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
|
||||||
|
toolbarLayoutParams = dummyToolbar.getLayoutParams();
|
||||||
|
toolBarParent.removeView(dummyToolbar);
|
||||||
|
|
||||||
|
// Sets appropriate system navigation bar color for the activity.
|
||||||
|
ToolbarPreferenceFragment.setNavigationBarColor(activity.getWindow());
|
||||||
|
|
||||||
|
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
|
||||||
|
toolbar.setBackgroundColor(getToolbarBackgroundColor());
|
||||||
|
toolbar.setNavigationIcon(getNavigationIcon());
|
||||||
|
toolbar.setNavigationOnClickListener(getNavigationClickListener(activity));
|
||||||
|
toolbar.setTitle(Utils.getResourceIdentifier("revanced_settings_title", "string"));
|
||||||
|
|
||||||
|
final int margin = Utils.dipToPixels(16);
|
||||||
|
toolbar.setTitleMarginStart(margin);
|
||||||
|
toolbar.setTitleMarginEnd(margin);
|
||||||
|
TextView toolbarTextView = Utils.getChildView(toolbar, false, view -> view instanceof TextView);
|
||||||
|
if (toolbarTextView != null) {
|
||||||
|
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
||||||
|
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||||
|
}
|
||||||
|
setToolbarLayoutParams(toolbar);
|
||||||
|
|
||||||
|
onPostToolbarSetup(activity, toolbar, fragment);
|
||||||
|
|
||||||
|
toolBarParent.addView(toolbar, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customizes the activity's theme.
|
||||||
|
*/
|
||||||
|
protected abstract void customizeActivityTheme(Activity activity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resource ID for the content view layout.
|
||||||
|
*/
|
||||||
|
protected abstract int getContentViewResourceId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the background color for the toolbar.
|
||||||
|
*/
|
||||||
|
protected abstract int getToolbarBackgroundColor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the navigation icon drawable for the toolbar.
|
||||||
|
*/
|
||||||
|
protected abstract Drawable getNavigationIcon();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the click listener for the toolbar's navigation icon.
|
||||||
|
*/
|
||||||
|
protected abstract View.OnClickListener getNavigationClickListener(Activity activity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the PreferenceFragment to be injected into the activity.
|
||||||
|
*/
|
||||||
|
protected PreferenceFragment createPreferenceFragment() {
|
||||||
|
return new ToolbarPreferenceFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs additional setup after the toolbar is configured.
|
||||||
|
*
|
||||||
|
* @param activity The activity hosting the toolbar.
|
||||||
|
* @param toolbar The configured toolbar.
|
||||||
|
* @param fragment The PreferenceFragment associated with the activity.
|
||||||
|
*/
|
||||||
|
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {}
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package app.revanced.extension.youtube.settings.preference;
|
package app.revanced.extension.shared.settings.preference;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import app.revanced.extension.shared.settings.preference.LogBufferManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom preference that clears the ReVanced debug log buffer when clicked.
|
* A custom preference that clears the ReVanced debug log buffer when clicked.
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package app.revanced.extension.youtube.settings.preference;
|
package app.revanced.extension.shared.settings.preference;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import app.revanced.extension.shared.settings.preference.LogBufferManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom preference that triggers exporting ReVanced debug logs to the clipboard when clicked.
|
* A custom preference that triggers exporting ReVanced debug logs to the clipboard when clicked.
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package app.revanced.extension.shared.settings.preference;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.graphics.Insets;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.preference.PreferenceScreen;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.BaseActivityHook;
|
||||||
|
|
||||||
|
@SuppressWarnings({"deprecation", "NewApi"})
|
||||||
|
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
|
||||||
|
/**
|
||||||
|
* Sets toolbar for all nested preference screens.
|
||||||
|
*/
|
||||||
|
protected void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
|
||||||
|
for (int i = 0, count = parentScreen.getPreferenceCount(); i < count; i++) {
|
||||||
|
Preference childPreference = parentScreen.getPreference(i);
|
||||||
|
if (childPreference instanceof PreferenceScreen) {
|
||||||
|
// Recursively set sub preferences.
|
||||||
|
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
|
||||||
|
|
||||||
|
childPreference.setOnPreferenceClickListener(
|
||||||
|
childScreen -> {
|
||||||
|
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
|
||||||
|
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
|
||||||
|
.findViewById(android.R.id.content)
|
||||||
|
.getParent();
|
||||||
|
|
||||||
|
// Allow package-specific background customization.
|
||||||
|
customizeDialogBackground(rootView);
|
||||||
|
|
||||||
|
// Fix the system navigation bar color for submenus.
|
||||||
|
setNavigationBarColor(preferenceScreenDialog.getWindow());
|
||||||
|
|
||||||
|
// Fix edge-to-edge screen with Android 15 and YT 19.45+
|
||||||
|
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||||
|
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
|
||||||
|
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
|
||||||
|
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
|
||||||
|
|
||||||
|
// Apply padding for display cutout in landscape.
|
||||||
|
int leftPadding = cutoutInsets.left;
|
||||||
|
int rightPadding = cutoutInsets.right;
|
||||||
|
int topPadding = statusInsets.top;
|
||||||
|
int bottomPadding = navInsets.bottom;
|
||||||
|
|
||||||
|
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
|
||||||
|
return insets;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Toolbar toolbar = new Toolbar(childScreen.getContext());
|
||||||
|
toolbar.setTitle(childScreen.getTitle());
|
||||||
|
toolbar.setNavigationIcon(getBackButtonDrawable());
|
||||||
|
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
|
||||||
|
|
||||||
|
final int margin = Utils.dipToPixels(16);
|
||||||
|
toolbar.setTitleMargin(margin, 0, margin, 0);
|
||||||
|
|
||||||
|
TextView toolbarTextView = Utils.getChildView(toolbar,
|
||||||
|
true, TextView.class::isInstance);
|
||||||
|
if (toolbarTextView != null) {
|
||||||
|
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
||||||
|
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow package-specific toolbar customization.
|
||||||
|
customizeToolbar(toolbar);
|
||||||
|
|
||||||
|
// Allow package-specific post-toolbar setup.
|
||||||
|
onPostToolbarSetup(toolbar, preferenceScreenDialog);
|
||||||
|
|
||||||
|
rootView.addView(toolbar, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the system navigation bar color for the activity.
|
||||||
|
* Applies the background color obtained from {@link Utils#getAppBackgroundColor()} to the navigation bar.
|
||||||
|
* For Android 10 (API 29) and above, enforces navigation bar contrast to ensure visibility.
|
||||||
|
*/
|
||||||
|
public static void setNavigationBarColor(@Nullable Window window) {
|
||||||
|
if (window == null) {
|
||||||
|
Logger.printDebug(() -> "Cannot set navigation bar color, window is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setNavigationBarColor(Utils.getAppBackgroundColor());
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
window.setNavigationBarContrastEnforced(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the drawable for the back button.
|
||||||
|
*/
|
||||||
|
@SuppressLint("UseCompatLoadingForDrawables")
|
||||||
|
public static Drawable getBackButtonDrawable() {
|
||||||
|
final int backButtonResource = Utils.getResourceIdentifier(
|
||||||
|
"revanced_settings_toolbar_arrow_left", "drawable");
|
||||||
|
Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource);
|
||||||
|
customizeBackButtonDrawable(drawable);
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customizes the back button drawable.
|
||||||
|
*/
|
||||||
|
protected static void customizeBackButtonDrawable(Drawable drawable) {
|
||||||
|
drawable.setTint(Utils.getAppForegroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows subclasses to customize the dialog's root view background.
|
||||||
|
*/
|
||||||
|
protected void customizeDialogBackground(ViewGroup rootView) {
|
||||||
|
rootView.setBackgroundColor(Utils.getAppBackgroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows subclasses to customize the toolbar.
|
||||||
|
*/
|
||||||
|
protected void customizeToolbar(Toolbar toolbar) {
|
||||||
|
BaseActivityHook.setToolbarLayoutParams(toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows subclasses to perform actions after toolbar setup.
|
||||||
|
*/
|
||||||
|
protected void onPostToolbarSetup(Toolbar toolbar, Dialog preferenceScreenDialog) {}
|
||||||
|
}
|
||||||
@@ -1,50 +1,120 @@
|
|||||||
package app.revanced.extension.youtube.settings;
|
package app.revanced.extension.youtube.settings;
|
||||||
|
|
||||||
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.util.TypedValue;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toolbar;
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
import app.revanced.extension.shared.Logger;
|
|
||||||
import app.revanced.extension.shared.Utils;
|
import app.revanced.extension.shared.Utils;
|
||||||
import app.revanced.extension.shared.settings.AppLanguage;
|
import app.revanced.extension.shared.settings.AppLanguage;
|
||||||
|
import app.revanced.extension.shared.settings.BaseActivityHook;
|
||||||
import app.revanced.extension.shared.settings.BaseSettings;
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.youtube.patches.VersionCheckPatch;
|
import app.revanced.extension.youtube.patches.VersionCheckPatch;
|
||||||
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
|
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
|
||||||
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
|
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks LicenseActivity.
|
* Hooks LicenseActivity to inject a custom ReVancedPreferenceFragment with a toolbar and search functionality.
|
||||||
* <p>
|
|
||||||
* This class is responsible for injecting our own fragment by replacing the LicenseActivity.
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("deprecation")
|
||||||
public class LicenseActivityHook extends Activity {
|
public class LicenseActivityHook extends BaseActivityHook {
|
||||||
|
|
||||||
private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value.
|
private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value.
|
||||||
|
|
||||||
private static ViewGroup.LayoutParams toolbarLayoutParams;
|
/**
|
||||||
|
* Controller for managing search view components in the toolbar.
|
||||||
|
*/
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
public static SearchViewController searchViewController;
|
public static SearchViewController searchViewController;
|
||||||
|
|
||||||
public static void setToolbarLayoutParams(Toolbar toolbar) {
|
/**
|
||||||
if (toolbarLayoutParams != null) {
|
* Injection point
|
||||||
toolbar.setLayoutParams(toolbarLayoutParams);
|
* <p>
|
||||||
|
* Creates an instance of LicenseActivityHook for use in static initialization.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static LicenseActivityHook createInstance() {
|
||||||
|
return new LicenseActivityHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customizes the activity theme based on dark/light mode.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void customizeActivityTheme(Activity activity) {
|
||||||
|
final var theme = Utils.isDarkModeEnabled()
|
||||||
|
? "Theme.YouTube.Settings.Dark"
|
||||||
|
: "Theme.YouTube.Settings";
|
||||||
|
activity.setTheme(Utils.getResourceIdentifier(theme, "style"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resource ID for the YouTube settings layout.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected int getContentViewResourceId() {
|
||||||
|
return Utils.getResourceIdentifier("revanced_settings_with_toolbar", "layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the toolbar background color based on dark/light mode.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected int getToolbarBackgroundColor() {
|
||||||
|
final String colorName = Utils.isDarkModeEnabled()
|
||||||
|
? "yt_black3"
|
||||||
|
: "yt_white1";
|
||||||
|
return Utils.getColorFromString(colorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the navigation icon drawable for the toolbar.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Drawable getNavigationIcon() {
|
||||||
|
return ReVancedPreferenceFragment.getBackButtonDrawable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the click listener for the navigation icon.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected View.OnClickListener getNavigationClickListener(Activity activity) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds search view components to the toolbar for ReVancedPreferenceFragment.
|
||||||
|
*
|
||||||
|
* @param activity The activity hosting the toolbar.
|
||||||
|
* @param toolbar The configured toolbar.
|
||||||
|
* @param fragment The PreferenceFragment associated with the activity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {
|
||||||
|
if (fragment instanceof ReVancedPreferenceFragment) {
|
||||||
|
searchViewController = SearchViewController.addSearchViewComponents(
|
||||||
|
activity, toolbar, (ReVancedPreferenceFragment) fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ReVancedPreferenceFragment for the activity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected PreferenceFragment createPreferenceFragment() {
|
||||||
|
return new ReVancedPreferenceFragment();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
* Overrides the ReVanced settings language.
|
* Overrides the ReVanced settings language.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public static Context getAttachBaseContext(Context original) {
|
public static Context getAttachBaseContext(Context original) {
|
||||||
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
|
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
|
||||||
if (language == AppLanguage.DEFAULT) {
|
if (language == AppLanguage.DEFAULT) {
|
||||||
@@ -57,6 +127,7 @@ public class LicenseActivityHook extends Activity {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public static boolean useCairoSettingsFragment(boolean original) {
|
public static boolean useCairoSettingsFragment(boolean original) {
|
||||||
// Early targets have layout issues and it's better to always force off.
|
// Early targets have layout issues and it's better to always force off.
|
||||||
if (!VersionCheckPatch.IS_19_34_OR_GREATER) {
|
if (!VersionCheckPatch.IS_19_34_OR_GREATER) {
|
||||||
@@ -80,87 +151,6 @@ public class LicenseActivityHook extends Activity {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
* <p>
|
* <p>
|
||||||
* Hooks LicenseActivity#onCreate in order to inject our own fragment.
|
|
||||||
*/
|
|
||||||
public static void initialize(Activity licenseActivity) {
|
|
||||||
try {
|
|
||||||
setActivityTheme(licenseActivity);
|
|
||||||
ReVancedPreferenceFragment.setNavigationBarColor(licenseActivity.getWindow());
|
|
||||||
licenseActivity.setContentView(getResourceIdentifier(
|
|
||||||
"revanced_settings_with_toolbar", "layout"));
|
|
||||||
|
|
||||||
// Sanity check.
|
|
||||||
String dataString = licenseActivity.getIntent().getDataString();
|
|
||||||
if (!"revanced_settings_intent".equals(dataString)) {
|
|
||||||
Logger.printException(() -> "Unknown intent: " + dataString);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferenceFragment fragment = new ReVancedPreferenceFragment();
|
|
||||||
createToolbar(licenseActivity, fragment);
|
|
||||||
|
|
||||||
//noinspection deprecation
|
|
||||||
licenseActivity.getFragmentManager()
|
|
||||||
.beginTransaction()
|
|
||||||
.replace(getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
|
|
||||||
.commit();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Logger.printException(() -> "initialize failure", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("UseCompatLoadingForDrawables")
|
|
||||||
private static void createToolbar(Activity activity, PreferenceFragment fragment) {
|
|
||||||
// Replace dummy placeholder toolbar.
|
|
||||||
// This is required to fix submenu title alignment issue with Android ASOP 15+
|
|
||||||
ViewGroup toolBarParent = activity.findViewById(
|
|
||||||
getResourceIdentifier("revanced_toolbar_parent", "id"));
|
|
||||||
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
|
|
||||||
toolbarLayoutParams = dummyToolbar.getLayoutParams();
|
|
||||||
toolBarParent.removeView(dummyToolbar);
|
|
||||||
|
|
||||||
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
|
|
||||||
toolbar.setBackgroundColor(getToolbarBackgroundColor());
|
|
||||||
toolbar.setNavigationIcon(ReVancedPreferenceFragment.getBackButtonDrawable());
|
|
||||||
toolbar.setTitle(getResourceIdentifier("revanced_settings_title", "string"));
|
|
||||||
|
|
||||||
final int margin = Utils.dipToPixels(16);
|
|
||||||
toolbar.setTitleMarginStart(margin);
|
|
||||||
toolbar.setTitleMarginEnd(margin);
|
|
||||||
TextView toolbarTextView = Utils.getChildView(toolbar, false,
|
|
||||||
view -> view instanceof TextView);
|
|
||||||
if (toolbarTextView != null) {
|
|
||||||
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
|
||||||
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
|
||||||
}
|
|
||||||
setToolbarLayoutParams(toolbar);
|
|
||||||
|
|
||||||
// Add Search bar only for ReVancedPreferenceFragment.
|
|
||||||
if (fragment instanceof ReVancedPreferenceFragment) {
|
|
||||||
searchViewController = SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
toolBarParent.addView(toolbar, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setActivityTheme(Activity activity) {
|
|
||||||
final var theme = Utils.isDarkModeEnabled()
|
|
||||||
? "Theme.YouTube.Settings.Dark"
|
|
||||||
: "Theme.YouTube.Settings";
|
|
||||||
activity.setTheme(getResourceIdentifier(theme, "style"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getToolbarBackgroundColor() {
|
|
||||||
final String colorName = Utils.isDarkModeEnabled()
|
|
||||||
? "yt_black3"
|
|
||||||
: "yt_white1";
|
|
||||||
|
|
||||||
return Utils.getColorFromString(colorName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection point.
|
|
||||||
*
|
|
||||||
* Updates dark/light mode since YT settings can force light/dark mode
|
* Updates dark/light mode since YT settings can force light/dark mode
|
||||||
* which can differ from the global device settings.
|
* which can differ from the global device settings.
|
||||||
*/
|
*/
|
||||||
@@ -173,6 +163,10 @@ public class LicenseActivityHook extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles configuration changes, such as orientation, to update the search view.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public static void handleConfigurationChanged(Activity activity, Configuration newConfig) {
|
public static void handleConfigurationChanged(Activity activity, Configuration newConfig) {
|
||||||
if (searchViewController != null) {
|
if (searchViewController != null) {
|
||||||
searchViewController.handleOrientationChange(newConfig.orientation);
|
searchViewController.handleOrientationChange(newConfig.orientation);
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ package app.revanced.extension.youtube.settings.preference;
|
|||||||
import static app.revanced.extension.shared.StringRef.str;
|
import static app.revanced.extension.shared.StringRef.str;
|
||||||
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
|
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.graphics.Insets;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceCategory;
|
import android.preference.PreferenceCategory;
|
||||||
@@ -17,11 +13,6 @@ import android.preference.SwitchPreference;
|
|||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowInsets;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toolbar;
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
@@ -40,16 +31,16 @@ import java.util.regex.Pattern;
|
|||||||
import app.revanced.extension.shared.Logger;
|
import app.revanced.extension.shared.Logger;
|
||||||
import app.revanced.extension.shared.Utils;
|
import app.revanced.extension.shared.Utils;
|
||||||
import app.revanced.extension.shared.settings.BaseSettings;
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment;
|
|
||||||
import app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory;
|
import app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory;
|
||||||
|
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||||
import app.revanced.extension.youtube.settings.LicenseActivityHook;
|
import app.revanced.extension.youtube.settings.LicenseActivityHook;
|
||||||
import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup;
|
import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preference fragment for ReVanced settings.
|
* Preference fragment for ReVanced settings.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings({"deprecation", "NewApi"})
|
||||||
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main PreferenceScreen used to display the current set of preferences.
|
* The main PreferenceScreen used to display the current set of preferences.
|
||||||
@@ -70,31 +61,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
|||||||
*/
|
*/
|
||||||
private final List<AbstractPreferenceSearchData<?>> allPreferences = new ArrayList<>();
|
private final List<AbstractPreferenceSearchData<?>> allPreferences = new ArrayList<>();
|
||||||
|
|
||||||
@SuppressLint("UseCompatLoadingForDrawables")
|
|
||||||
public static Drawable getBackButtonDrawable() {
|
|
||||||
final int backButtonResource = getResourceIdentifier("revanced_settings_toolbar_arrow_left", "drawable");
|
|
||||||
Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource);
|
|
||||||
drawable.setTint(Utils.getAppForegroundColor());
|
|
||||||
return drawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the system navigation bar color for the activity.
|
|
||||||
* Applies the background color obtained from {@link Utils#getAppBackgroundColor()} to the navigation bar.
|
|
||||||
* For Android 10 (API 29) and above, enforces navigation bar contrast to ensure visibility.
|
|
||||||
*/
|
|
||||||
public static void setNavigationBarColor(@Nullable Window window) {
|
|
||||||
if (window == null) {
|
|
||||||
Logger.printDebug(() -> "Cannot set navigation bar color, window is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.setNavigationBarColor(Utils.getAppBackgroundColor());
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
window.setNavigationBarContrastEnforced(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the preference fragment, copying the original screen to allow full restoration.
|
* Initializes the preference fragment, copying the original screen to allow full restoration.
|
||||||
*/
|
*/
|
||||||
@@ -139,8 +105,28 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets toolbar for all nested preference screens.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void customizeToolbar(Toolbar toolbar) {
|
||||||
|
LicenseActivityHook.setToolbarLayoutParams(toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform actions after toolbar setup.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onPostToolbarSetup(Toolbar toolbar, Dialog preferenceScreenDialog) {
|
||||||
|
if (LicenseActivityHook.searchViewController != null
|
||||||
|
&& LicenseActivityHook.searchViewController.isSearchActive()) {
|
||||||
|
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively collects all preferences from the screen or group.
|
* Recursively collects all preferences from the screen or group.
|
||||||
|
*
|
||||||
* @param includeDepth Menu depth to start including preferences.
|
* @param includeDepth Menu depth to start including preferences.
|
||||||
* A value of 0 adds all preferences.
|
* A value of 0 adds all preferences.
|
||||||
*/
|
*/
|
||||||
@@ -222,75 +208,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
|||||||
preferenceScreen.addPreference(noResultsPreference);
|
preferenceScreen.addPreference(noResultsPreference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets toolbar for all nested preference screens.
|
|
||||||
*/
|
|
||||||
private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
|
|
||||||
for (int i = 0, count = parentScreen.getPreferenceCount(); i < count; i++) {
|
|
||||||
Preference childPreference = parentScreen.getPreference(i);
|
|
||||||
if (childPreference instanceof PreferenceScreen) {
|
|
||||||
// Recursively set sub preferences.
|
|
||||||
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
|
|
||||||
|
|
||||||
childPreference.setOnPreferenceClickListener(
|
|
||||||
childScreen -> {
|
|
||||||
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
|
|
||||||
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
|
|
||||||
.findViewById(android.R.id.content)
|
|
||||||
.getParent();
|
|
||||||
|
|
||||||
// Fix the system navigation bar color for submenus.
|
|
||||||
setNavigationBarColor(preferenceScreenDialog.getWindow());
|
|
||||||
|
|
||||||
// Fix edge-to-edge screen with Android 15 and YT 19.45+
|
|
||||||
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
|
|
||||||
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
|
|
||||||
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
|
|
||||||
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
|
|
||||||
|
|
||||||
// Apply padding for display cutout in landscape.
|
|
||||||
int leftPadding = cutoutInsets.left;
|
|
||||||
int rightPadding = cutoutInsets.right;
|
|
||||||
int topPadding = statusInsets.top;
|
|
||||||
int bottomPadding = navInsets.bottom;
|
|
||||||
|
|
||||||
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
|
|
||||||
return insets;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Toolbar toolbar = new Toolbar(childScreen.getContext());
|
|
||||||
toolbar.setTitle(childScreen.getTitle());
|
|
||||||
toolbar.setNavigationIcon(getBackButtonDrawable());
|
|
||||||
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
|
|
||||||
|
|
||||||
final int margin = Utils.dipToPixels(16);
|
|
||||||
toolbar.setTitleMargin(margin, 0, margin, 0);
|
|
||||||
|
|
||||||
TextView toolbarTextView = Utils.getChildView(toolbar,
|
|
||||||
true, TextView.class::isInstance);
|
|
||||||
if (toolbarTextView != null) {
|
|
||||||
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
|
||||||
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
LicenseActivityHook.setToolbarLayoutParams(toolbar);
|
|
||||||
|
|
||||||
if (LicenseActivityHook.searchViewController != null
|
|
||||||
&& LicenseActivityHook.searchViewController.isSearchActive()) {
|
|
||||||
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
|
|
||||||
}
|
|
||||||
|
|
||||||
rootView.addView(toolbar, 0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
|
|||||||
@@ -372,8 +372,9 @@ public final class app/revanced/patches/music/layout/premium/HideGetPremiumPatch
|
|||||||
public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatchKt {
|
public final class app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatchKt {
|
||||||
public static final fun getRemoveUpgradeButtonPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideUpgradeButton ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
public static final fun getRemoveUpgradeButton ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatchKt {
|
public final class app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatchKt {
|
||||||
@@ -396,7 +397,21 @@ public final class app/revanced/patches/music/misc/gms/GmsCoreSupportPatchKt {
|
|||||||
public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsKt {
|
public final class app/revanced/patches/music/misc/settings/PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen {
|
||||||
|
public static final field INSTANCE Lapp/revanced/patches/music/misc/settings/PreferenceScreen;
|
||||||
|
public fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreenPreference;)V
|
||||||
|
public final fun getADS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getGENERAL ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getPLAYER ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/misc/settings/SettingsPatchKt {
|
||||||
|
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatchKt {
|
||||||
public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1652,7 +1667,6 @@ public final class app/revanced/patches/youtube/misc/settings/PreferenceScreen :
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/misc/settings/SettingsPatchKt {
|
public final class app/revanced/patches/youtube/misc/settings/SettingsPatchKt {
|
||||||
public static final fun addSettingPreference (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V
|
|
||||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
|
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,27 @@
|
|||||||
package app.revanced.patches.music.ad.video
|
package app.revanced.patches.music.ad.video
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideVideoAdsPatch;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val hideVideoAdsPatch = bytecodePatch(
|
val hideVideoAdsPatch = bytecodePatch(
|
||||||
name = "Hide music video ads",
|
name = "Hide music video ads",
|
||||||
description = "Hides ads that appear while listening to or streaming music videos, podcasts, or songs.",
|
description = "Adds an option to hide ads that appear while listening to or streaming music videos, podcasts, or songs.",
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
@@ -15,9 +29,21 @@ val hideVideoAdsPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("music", "ad.video.hideVideoAdsPatch")
|
||||||
|
|
||||||
|
PreferenceScreen.ADS.addPreferences(
|
||||||
|
SwitchPreference("revanced_music_hide_video_ads"),
|
||||||
|
)
|
||||||
|
|
||||||
navigate(showVideoAdsParentFingerprint.originalMethod)
|
navigate(showVideoAdsParentFingerprint.originalMethod)
|
||||||
.to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1)
|
.to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1)
|
||||||
.stop()
|
.stop()
|
||||||
.addInstruction(0, "const/4 p1, 0x0")
|
.addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->showVideoAds(Z)Z
|
||||||
|
move-result p1
|
||||||
|
"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package app.revanced.patches.music.audio.exclusiveaudio
|
package app.revanced.patches.music.audio.exclusiveaudio
|
||||||
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
import app.revanced.util.returnEarly
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@@ -8,6 +10,11 @@ val enableExclusiveAudioPlaybackPatch = bytecodePatch(
|
|||||||
name = "Enable exclusive audio playback",
|
name = "Enable exclusive audio playback",
|
||||||
description = "Enables the option to play audio without video.",
|
description = "Enables the option to play audio without video.",
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
|
|||||||
@@ -4,13 +4,27 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
|
import app.revanced.util.findFreeRegister
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/PermanentRepeatPatch;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val permanentRepeatPatch = bytecodePatch(
|
val permanentRepeatPatch = bytecodePatch(
|
||||||
name = "Permanent repeat",
|
name = "Permanent repeat",
|
||||||
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.",
|
description = "Adds an option to always repeat even if the playlist ends or another track is played."
|
||||||
use = false,
|
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
@@ -18,13 +32,27 @@ val permanentRepeatPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("music", "interaction.permanentrepeat.permanentRepeatPatch")
|
||||||
|
|
||||||
|
PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_music_play_permanent_repeat"),
|
||||||
|
)
|
||||||
|
|
||||||
val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex
|
val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex
|
||||||
val repeatIndex = startIndex + 1
|
val repeatIndex = startIndex + 1
|
||||||
|
|
||||||
repeatTrackFingerprint.method.apply {
|
repeatTrackFingerprint.method.apply {
|
||||||
|
// Start index is at a branch, but the same
|
||||||
|
// register is clobbered in both branch paths.
|
||||||
|
val freeRegister = findFreeRegister(startIndex + 1)
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
startIndex,
|
startIndex,
|
||||||
"goto :repeat",
|
"""
|
||||||
|
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->permanentRepeat()Z
|
||||||
|
move-result v$freeRegister
|
||||||
|
if-nez v$freeRegister, :repeat
|
||||||
|
""",
|
||||||
ExternalLabel("repeat", instructions[repeatIndex]),
|
ExternalLabel("repeat", instructions[repeatIndex]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,32 @@
|
|||||||
package app.revanced.patches.music.layout.compactheader
|
package app.revanced.patches.music.layout.compactheader
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
|
import app.revanced.util.addInstructionsAtControlFlowLabel
|
||||||
import app.revanced.util.findFreeRegister
|
import app.revanced.util.findFreeRegister
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val hideCategoryBar = bytecodePatch(
|
val hideCategoryBar = bytecodePatch(
|
||||||
name = "Hide category bar",
|
name = "Hide category bar",
|
||||||
description = "Hides the category bar at the top of the homepage.",
|
description = "Adds an option to hide the category bar at the top of the homepage."
|
||||||
use = false,
|
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
@@ -19,16 +34,27 @@ val hideCategoryBar = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("music", "layout.compactheader.hideCategoryBar")
|
||||||
|
|
||||||
|
PreferenceScreen.GENERAL.addPreferences(
|
||||||
|
SwitchPreference("revanced_music_hide_category_bar"),
|
||||||
|
)
|
||||||
|
|
||||||
constructCategoryBarFingerprint.method.apply {
|
constructCategoryBarFingerprint.method.apply {
|
||||||
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex
|
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex
|
||||||
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||||
val freeRegister = findFreeRegister(insertIndex, register)
|
val freeRegister = findFreeRegister(insertIndex, register)
|
||||||
|
|
||||||
addInstructions(
|
addInstructionsWithLabels(
|
||||||
insertIndex,
|
insertIndex,
|
||||||
"""
|
"""
|
||||||
|
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar()Z
|
||||||
|
move-result v$freeRegister
|
||||||
|
if-eqz v$freeRegister, :show
|
||||||
const/16 v$freeRegister, 0x8
|
const/16 v$freeRegister, 0x8
|
||||||
invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V
|
invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V
|
||||||
|
:show
|
||||||
|
nop
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,31 @@
|
|||||||
package app.revanced.patches.music.layout.premium
|
package app.revanced.patches.music.layout.premium
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideGetPremiumPatch;"
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
val hideGetPremiumPatch = bytecodePatch(
|
val hideGetPremiumPatch = bytecodePatch(
|
||||||
name = "Hide 'Get Music Premium' label",
|
name = "Hide 'Get Music Premium'",
|
||||||
description = "Hides the \"Get Music Premium\" label from the account menu and settings.",
|
description = "Adds an option to hide the \"Get Music Premium\" label in the settings and account menu.",
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
@@ -18,6 +33,12 @@ val hideGetPremiumPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("music", "layout.premium.hideGetPremiumPatch")
|
||||||
|
|
||||||
|
PreferenceScreen.ADS.addPreferences(
|
||||||
|
SwitchPreference("revanced_music_hide_get_premium_label"),
|
||||||
|
)
|
||||||
|
|
||||||
hideGetPremiumFingerprint.method.apply {
|
hideGetPremiumFingerprint.method.apply {
|
||||||
val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex
|
val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex
|
||||||
|
|
||||||
@@ -37,12 +58,17 @@ val hideGetPremiumPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
membershipSettingsFingerprint.method.addInstructions(
|
membershipSettingsFingerprint.method.addInstructionsWithLabels(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
const/4 v0, 0x0
|
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideGetPremiumLabel()Z
|
||||||
return-object v0
|
move-result v0
|
||||||
""",
|
if-eqz v0, :show
|
||||||
|
const/4 v0, 0x0
|
||||||
|
return-object v0
|
||||||
|
:show
|
||||||
|
nop
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,31 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|||||||
import app.revanced.patcher.extensions.newLabel
|
import app.revanced.patcher.extensions.newLabel
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
|
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val removeUpgradeButtonPatch = bytecodePatch(
|
val hideUpgradeButton = bytecodePatch(
|
||||||
name = "Remove upgrade button",
|
name = "Hide upgrade button",
|
||||||
description = "Removes the upgrade tab from the pivot bar.",
|
description = "Hides the upgrade tab from the pivot bar.",
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
@@ -25,6 +39,15 @@ val removeUpgradeButtonPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("music", "layout.upgradebutton.hideUpgradeButtonPatch")
|
||||||
|
|
||||||
|
// TODO: Add an extension patch to allow this to be enabled/disabled in app.
|
||||||
|
if (false) {
|
||||||
|
PreferenceScreen.ADS.addPreferences(
|
||||||
|
SwitchPreference("revanced_music_hide_upgrade_button")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pivotBarConstructorFingerprint.method.apply {
|
pivotBarConstructorFingerprint.method.apply {
|
||||||
val pivotBarElementFieldReference =
|
val pivotBarElementFieldReference =
|
||||||
getInstruction(pivotBarConstructorFingerprint.patternMatch!!.endIndex - 1)
|
getInstruction(pivotBarConstructorFingerprint.patternMatch!!.endIndex - 1)
|
||||||
@@ -77,3 +100,9 @@ val removeUpgradeButtonPatch = bytecodePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Patch was renamed", ReplaceWith("hideUpgradeButton"))
|
||||||
|
@Suppress("unused")
|
||||||
|
val removeUpgradeButton = bytecodePatch{
|
||||||
|
dependsOn(hideUpgradeButton)
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package app.revanced.patches.music.misc.androidauto
|
package app.revanced.patches.music.misc.androidauto
|
||||||
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
import app.revanced.util.returnEarly
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@@ -8,6 +10,11 @@ val bypassCertificateChecksPatch = bytecodePatch(
|
|||||||
name = "Bypass certificate checks",
|
name = "Bypass certificate checks",
|
||||||
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
|
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package app.revanced.patches.music.misc.backgroundplayback
|
package app.revanced.patches.music.misc.backgroundplayback
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
val backgroundPlaybackPatch = bytecodePatch(
|
val backgroundPlaybackPatch = bytecodePatch(
|
||||||
name = "Remove background playback restrictions",
|
name = "Remove background playback restrictions",
|
||||||
description = "Removes restrictions on background playback, including playing kids videos in the background.",
|
description = "Removes restrictions on background playback, including playing kids videos in the background.",
|
||||||
) {
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
@@ -20,12 +27,6 @@ val backgroundPlaybackPatch = bytecodePatch(
|
|||||||
"return-void",
|
"return-void",
|
||||||
)
|
)
|
||||||
|
|
||||||
backgroundPlaybackDisableFingerprint.method.addInstructions(
|
backgroundPlaybackDisableFingerprint.method.returnEarly(true)
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x1
|
|
||||||
return v0
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package app.revanced.patches.music.misc.gms
|
package app.revanced.patches.music.misc.gms
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Option
|
import app.revanced.patcher.patch.Option
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
|
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
|
||||||
import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
|
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
|
||||||
import app.revanced.patches.shared.castContextFetchFingerprint
|
import app.revanced.patches.shared.castContextFetchFingerprint
|
||||||
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
|
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
|
||||||
import app.revanced.patches.shared.primeMethodFingerprint
|
import app.revanced.patches.shared.primeMethodFingerprint
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@@ -33,4 +38,23 @@ private fun gmsCoreSupportResourcePatch(
|
|||||||
toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
|
toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
|
||||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||||
spoofedPackageSignature = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875",
|
spoofedPackageSignature = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875",
|
||||||
)
|
executeBlock = {
|
||||||
|
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
|
||||||
|
|
||||||
|
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||||
|
|
||||||
|
PreferenceScreen.MISC.addPreferences(
|
||||||
|
IntentPreference(
|
||||||
|
"microg_settings",
|
||||||
|
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
|
||||||
|
"$gmsCoreVendorGroupId.android.gms"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
dependsOn(
|
||||||
|
addResourcesPatch,
|
||||||
|
settingsPatch
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package app.revanced.patches.music.misc.settings
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal val googleApiActivityFingerprint = fingerprint {
|
||||||
|
returns("V")
|
||||||
|
parameters("Landroid/os/Bundle;")
|
||||||
|
custom { method, classDef ->
|
||||||
|
classDef.endsWith("GoogleApiActivity;") && method.name == "onCreate"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package app.revanced.patches.music.misc.settings
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.*
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.settingsPatch
|
||||||
|
import app.revanced.util.*
|
||||||
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
|
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
|
||||||
|
private const val GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/music/settings/GoogleApiActivityHook;"
|
||||||
|
|
||||||
|
private val preferences = mutableSetOf<BasePreference>()
|
||||||
|
|
||||||
|
|
||||||
|
private val settingsResourcePatch = resourcePatch {
|
||||||
|
dependsOn(
|
||||||
|
resourceMappingPatch,
|
||||||
|
settingsPatch(
|
||||||
|
IntentPreference(
|
||||||
|
titleKey = "revanced_settings_title",
|
||||||
|
summaryKey = null,
|
||||||
|
intent = newIntent("revanced_settings_intent"),
|
||||||
|
) to "settings_headers",
|
||||||
|
preferences
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
|
||||||
|
// TODO: Remove this when search will be abstract.
|
||||||
|
copyResources(
|
||||||
|
"settings",
|
||||||
|
ResourceGroup(
|
||||||
|
"layout",
|
||||||
|
"revanced_music_settings_with_toolbar.xml"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val targetResource = "values/styles.xml"
|
||||||
|
inputStreamFromBundledResource(
|
||||||
|
"settings/music",
|
||||||
|
targetResource,
|
||||||
|
)!!.let { inputStream ->
|
||||||
|
"resources".copyXmlNode(
|
||||||
|
document(inputStream),
|
||||||
|
document("res/$targetResource"),
|
||||||
|
).close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove horizontal divider from the settings Preferences.
|
||||||
|
val styleFile = get("res/values/styles.xml")
|
||||||
|
styleFile.writeText(
|
||||||
|
styleFile.readText()
|
||||||
|
.replace(
|
||||||
|
"allowDividerAbove\">true",
|
||||||
|
"allowDividerAbove\">false"
|
||||||
|
).replace(
|
||||||
|
"allowDividerBelow\">true",
|
||||||
|
"allowDividerBelow\">false"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val settingsPatch = bytecodePatch(
|
||||||
|
description = "Adds settings for ReVanced to YouTube Music.",
|
||||||
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsResourcePatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
addResources("music", "misc.settings.settingsPatch")
|
||||||
|
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
||||||
|
|
||||||
|
// Should make a separate debugging patch, but for now include it with all installations.
|
||||||
|
PreferenceScreen.MISC.addPreferences(
|
||||||
|
PreferenceScreenPreference(
|
||||||
|
key = "revanced_debug_screen",
|
||||||
|
sorting = Sorting.UNSORTED,
|
||||||
|
preferences = setOf(
|
||||||
|
SwitchPreference("revanced_debug"),
|
||||||
|
NonInteractivePreference(
|
||||||
|
"revanced_debug_export_logs_to_clipboard",
|
||||||
|
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
||||||
|
selectable = true
|
||||||
|
),
|
||||||
|
NonInteractivePreference(
|
||||||
|
"revanced_debug_logs_clear_buffer",
|
||||||
|
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
||||||
|
selectable = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add an "About" preference to the top.
|
||||||
|
preferences += NonInteractivePreference(
|
||||||
|
key = "revanced_settings_music_screen_0_about",
|
||||||
|
summaryKey = null,
|
||||||
|
tag = "app.revanced.extension.shared.settings.preference.ReVancedAboutPreference",
|
||||||
|
selectable = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Modify GoogleApiActivity and remove all existing layout code.
|
||||||
|
// Must modify an existing activity and cannot add a new activity to the manifest,
|
||||||
|
// as that fails for root installations.
|
||||||
|
|
||||||
|
googleApiActivityFingerprint.method.addInstructions(
|
||||||
|
1,
|
||||||
|
"""
|
||||||
|
invoke-static { }, $GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/music/settings/GoogleApiActivityHook;
|
||||||
|
move-result-object v0
|
||||||
|
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
|
||||||
|
return-void
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
// Remove other methods as they will break as the onCreate method is modified above.
|
||||||
|
googleApiActivityFingerprint.classDef.apply {
|
||||||
|
methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize {
|
||||||
|
PreferenceScreen.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an intent to open ReVanced settings.
|
||||||
|
*/
|
||||||
|
fun newIntent(settingsName: String) = IntentPreference.Intent(
|
||||||
|
data = settingsName,
|
||||||
|
targetClass = "com.google.android.gms.common.api.GoogleApiActivity"
|
||||||
|
) {
|
||||||
|
// The package name change has to be reflected in the intent.
|
||||||
|
setOrGetFallbackPackageName("com.google.android.apps.youtube.music")
|
||||||
|
}
|
||||||
|
|
||||||
|
object PreferenceScreen : BasePreferenceScreen() {
|
||||||
|
val ADS = Screen(
|
||||||
|
"revanced_settings_music_screen_1_ads",
|
||||||
|
summaryKey = null
|
||||||
|
)
|
||||||
|
val GENERAL = Screen(
|
||||||
|
"revanced_settings_music_screen_2_general",
|
||||||
|
summaryKey = null
|
||||||
|
)
|
||||||
|
val PLAYER = Screen(
|
||||||
|
"revanced_settings_music_screen_3_player",
|
||||||
|
summaryKey = null
|
||||||
|
)
|
||||||
|
val MISC = Screen(
|
||||||
|
"revanced_settings_music_screen_4_misc",
|
||||||
|
summaryKey = null
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun commit(screen: PreferenceScreenPreference) {
|
||||||
|
preferences += screen
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
package app.revanced.patches.music.misc.spoof
|
package app.revanced.patches.music.misc.spoof
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
|
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
import app.revanced.patches.music.playservice.is_7_33_or_greater
|
import app.revanced.patches.music.playservice.is_7_33_or_greater
|
||||||
import app.revanced.patches.music.playservice.is_8_11_or_greater
|
import app.revanced.patches.music.playservice.is_8_11_or_greater
|
||||||
import app.revanced.patches.music.playservice.is_8_15_or_greater
|
import app.revanced.patches.music.playservice.is_8_15_or_greater
|
||||||
import app.revanced.patches.music.playservice.versionCheckPatch
|
import app.revanced.patches.music.playservice.versionCheckPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
|
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
|
||||||
@@ -16,17 +23,36 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
|||||||
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
|
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||||
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
|
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
|
||||||
block = {
|
block = {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
versionCheckPatch,
|
||||||
|
userAgentClientSpoofPatch
|
||||||
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
"com.google.android.apps.youtube.music"(
|
"com.google.android.apps.youtube.music"(
|
||||||
"7.29.52"
|
"7.29.52"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
dependsOn(sharedExtensionPatch, versionCheckPatch, userAgentClientSpoofPatch)
|
|
||||||
},
|
},
|
||||||
executeBlock = {
|
executeBlock = {
|
||||||
|
addResources("shared", "misc.spoof.spoofVideoStreamsPatch")
|
||||||
|
|
||||||
|
PreferenceScreen.MISC.addPreferences(
|
||||||
|
PreferenceScreenPreference(
|
||||||
|
key = "revanced_spoof_video_streams_screen",
|
||||||
|
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
|
||||||
|
preferences = setOf(
|
||||||
|
SwitchPreference("revanced_spoof_video_streams"),
|
||||||
|
ListPreference("revanced_spoof_video_streams_client_type"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
musicActivityOnCreateFingerprint.method.addInstruction(
|
musicActivityOnCreateFingerprint.method.addInstruction(
|
||||||
1, // Must use 1 index so context is set by extension patch.
|
0,
|
||||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
|
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,8 @@ import app.revanced.patcher.patch.BytecodePatchBuilder
|
|||||||
import app.revanced.patcher.patch.BytecodePatchContext
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
|
||||||
import app.revanced.util.findFreeRegister
|
import app.revanced.util.findFreeRegister
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
@@ -46,6 +46,8 @@ fun spoofVideoStreamsPatch(
|
|||||||
dependsOn(addResourcesPatch)
|
dependsOn(addResourcesPatch)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||||
|
|
||||||
// region Enable extension helper method used by other patches
|
// region Enable extension helper method used by other patches
|
||||||
|
|
||||||
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
|
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/extension/youtube/patches/EnableDebuggingPatch;"
|
"Lapp/revanced/extension/youtube/patches/EnableDebuggingPatch;"
|
||||||
|
|
||||||
|
// TODO: Refactor this into a shared patch that can be used by both YT and YT Music.
|
||||||
|
// Almost all of the feature flag hooks are the same between both apps.
|
||||||
val enableDebuggingPatch = bytecodePatch(
|
val enableDebuggingPatch = bytecodePatch(
|
||||||
name = "Enable debugging",
|
name = "Enable debugging",
|
||||||
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
|
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
|
||||||
@@ -45,6 +47,7 @@ val enableDebuggingPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
||||||
addResources("youtube", "misc.debugging.enableDebuggingPatch")
|
addResources("youtube", "misc.debugging.enableDebuggingPatch")
|
||||||
|
|
||||||
PreferenceScreen.MISC.addPreferences(
|
PreferenceScreen.MISC.addPreferences(
|
||||||
@@ -58,13 +61,13 @@ val enableDebuggingPatch = bytecodePatch(
|
|||||||
SwitchPreference("revanced_debug_toast_on_error"),
|
SwitchPreference("revanced_debug_toast_on_error"),
|
||||||
NonInteractivePreference(
|
NonInteractivePreference(
|
||||||
"revanced_debug_export_logs_to_clipboard",
|
"revanced_debug_export_logs_to_clipboard",
|
||||||
tag = "app.revanced.extension.youtube.settings.preference.ExportLogToClipboardPreference",
|
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
||||||
selectable = true,
|
selectable = true
|
||||||
),
|
),
|
||||||
NonInteractivePreference(
|
NonInteractivePreference(
|
||||||
"revanced_debug_logs_clear_buffer",
|
"revanced_debug_logs_clear_buffer",
|
||||||
tag = "app.revanced.extension.youtube.settings.preference.ClearLogBufferPreference",
|
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
||||||
selectable = true,
|
selectable = true
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ private fun gmsCoreSupportResourcePatch(
|
|||||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
||||||
executeBlock = {
|
executeBlock = {
|
||||||
addResources("youtube", "misc.gms.gmsCoreSupportResourcePatch")
|
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
|
||||||
|
|
||||||
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||||
|
|
||||||
@@ -62,10 +62,14 @@ private fun gmsCoreSupportResourcePatch(
|
|||||||
"microg_settings",
|
"microg_settings",
|
||||||
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
|
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
|
||||||
"$gmsCoreVendorGroupId.android.gms"
|
"$gmsCoreVendorGroupId.android.gms"
|
||||||
},
|
}
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
) {
|
) {
|
||||||
dependsOn(settingsPatch, addResourcesPatch, accountCredentialsInvalidTextPatch)
|
dependsOn(
|
||||||
|
addResourcesPatch,
|
||||||
|
settingsPatch,
|
||||||
|
accountCredentialsInvalidTextPatch
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
|||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
|
||||||
|
private const val LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/extension/youtube/settings/LicenseActivityHook;"
|
"Lapp/revanced/extension/youtube/settings/LicenseActivityHook;"
|
||||||
|
|
||||||
internal var appearanceStringId = -1L
|
internal var appearanceStringId = -1L
|
||||||
@@ -37,10 +39,6 @@ internal var appearanceStringId = -1L
|
|||||||
|
|
||||||
private val preferences = mutableSetOf<BasePreference>()
|
private val preferences = mutableSetOf<BasePreference>()
|
||||||
|
|
||||||
fun addSettingPreference(screen: BasePreference) {
|
|
||||||
preferences += screen
|
|
||||||
}
|
|
||||||
|
|
||||||
private val settingsResourcePatch = resourcePatch {
|
private val settingsResourcePatch = resourcePatch {
|
||||||
dependsOn(
|
dependsOn(
|
||||||
resourceMappingPatch,
|
resourceMappingPatch,
|
||||||
@@ -225,7 +223,9 @@ val settingsPatch = bytecodePatch(
|
|||||||
licenseActivityOnCreateFingerprint.method.addInstructions(
|
licenseActivityOnCreateFingerprint.method.addInstructions(
|
||||||
1,
|
1,
|
||||||
"""
|
"""
|
||||||
invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V
|
invoke-static {}, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/youtube/settings/LicenseActivityHook;
|
||||||
|
move-result-object v0
|
||||||
|
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
|
||||||
return-void
|
return-void
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@@ -249,7 +249,7 @@ val settingsPatch = bytecodePatch(
|
|||||||
).toMutable().apply {
|
).toMutable().apply {
|
||||||
addInstructions(
|
addInstructions(
|
||||||
"""
|
"""
|
||||||
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
|
invoke-static { p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
|
||||||
move-result-object p1
|
move-result-object p1
|
||||||
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
|
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
|
||||||
return-void
|
return-void
|
||||||
@@ -294,7 +294,7 @@ val settingsPatch = bytecodePatch(
|
|||||||
addInstructions(
|
addInstructions(
|
||||||
"""
|
"""
|
||||||
invoke-super { p0, p1 }, Landroid/app/Activity;->onConfigurationChanged(Landroid/content/res/Configuration;)V
|
invoke-super { p0, p1 }, Landroid/app/Activity;->onConfigurationChanged(Landroid/content/res/Configuration;)V
|
||||||
invoke-static { p0, p1 }, $EXTENSION_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V
|
invoke-static { p0, p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V
|
||||||
return-void
|
return-void
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@@ -309,15 +309,15 @@ val settingsPatch = bytecodePatch(
|
|||||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
addInstructionsAtControlFlowLabel(
|
addInstructionsAtControlFlowLabel(
|
||||||
index,
|
index,
|
||||||
"invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
|
"invoke-static { v$register }, ${LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add setting to force cairo settings fragment on/off.
|
// Add setting to force Cairo settings fragment on/off.
|
||||||
cairoFragmentConfigFingerprint.method.insertLiteralOverride(
|
cairoFragmentConfigFingerprint.method.insertLiteralOverride(
|
||||||
CAIRO_CONFIG_LITERAL_VALUE,
|
CAIRO_CONFIG_LITERAL_VALUE,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
|
"$LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,18 +121,18 @@
|
|||||||
<item>ZH</item>
|
<item>ZH</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
</patch>
|
</patch>
|
||||||
</app>
|
|
||||||
<app id="youtube">
|
|
||||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||||
<string-array name="revanced_spoof_video_streams_client_type_entries">
|
<string-array name="revanced_spoof_video_streams_client_type_entries">
|
||||||
<item>Android VR</item>
|
<item>Android VR</item>
|
||||||
<item>VisionOS</item>
|
<item>visionOS</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_spoof_video_streams_client_type_entry_values">
|
<string-array name="revanced_spoof_video_streams_client_type_entry_values">
|
||||||
<item>ANDROID_VR_1_61_48</item>
|
<item>ANDROID_VR_1_61_48</item>
|
||||||
<item>VISIONOS</item>
|
<item>VISIONOS</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
</patch>
|
</patch>
|
||||||
|
</app>
|
||||||
|
<app id="youtube">
|
||||||
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
|
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
|
||||||
<string-array name="revanced_swipe_overlay_style_entries">
|
<string-array name="revanced_swipe_overlay_style_entries">
|
||||||
<item>@string/revanced_swipe_overlay_style_entry_1</item>
|
<item>@string/revanced_swipe_overlay_style_entry_1</item>
|
||||||
|
|||||||
@@ -124,6 +124,8 @@ To translate new languages visit translate.revanced.app"</string>
|
|||||||
and changes made here must also be made there. -->
|
and changes made here must also be made there. -->
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||||
|
<string name="microg_settings_title">GmsCore Settings</string>
|
||||||
|
<string name="microg_settings_summary">Settings for GmsCore</string>
|
||||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||||
<string name="gms_core_toast_not_installed_message">MicroG GmsCore is not installed. Install it.</string>
|
<string name="gms_core_toast_not_installed_message">MicroG GmsCore is not installed. Install it.</string>
|
||||||
<string name="gms_core_dialog_title">Action needed</string>
|
<string name="gms_core_dialog_title">Action needed</string>
|
||||||
@@ -140,6 +142,37 @@ Disabling battery optimizations for MicroG will not negatively affect battery us
|
|||||||
Tap the continue button and allow optimization changes."</string>
|
Tap the continue button and allow optimization changes."</string>
|
||||||
<string name="gms_core_dialog_continue_text">Continue</string>
|
<string name="gms_core_dialog_continue_text">Continue</string>
|
||||||
</patch>
|
</patch>
|
||||||
|
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||||
|
<string name="revanced_spoof_video_streams_screen_title">Spoof video streams</string>
|
||||||
|
<string name="revanced_spoof_video_streams_screen_summary">Spoof the client video streams to prevent playback issues</string>
|
||||||
|
<string name="revanced_spoof_video_streams_screen_title">Spoof video streams</string>
|
||||||
|
<string name="revanced_spoof_video_streams_screen_summary">Spoof the client video streams to prevent playback issues</string>
|
||||||
|
<string name="revanced_spoof_video_streams_title">Spoof video streams</string>
|
||||||
|
<string name="revanced_spoof_video_streams_summary_on">"Video streams are spoofed
|
||||||
|
|
||||||
|
If you are a YouTube Premium user, this setting may not be required"</string>
|
||||||
|
<string name="revanced_spoof_video_streams_summary_off">"Video streams are not spoofed
|
||||||
|
|
||||||
|
Playback may not work"</string>
|
||||||
|
<string name="revanced_spoof_video_streams_user_dialog_message">Turning off this setting may cause playback issues.</string>
|
||||||
|
<string name="revanced_spoof_video_streams_client_type_title">Default client</string>
|
||||||
|
</patch>
|
||||||
|
<patch id="misc.debugging.enableDebuggingPatch">
|
||||||
|
<string name="revanced_debug_screen_title">Debugging</string>
|
||||||
|
<string name="revanced_debug_screen_summary">Enable or disable debugging options</string>
|
||||||
|
<string name="revanced_debug_title">Debug logging</string>
|
||||||
|
<string name="revanced_debug_summary_on">Debug logs are enabled</string>
|
||||||
|
<string name="revanced_debug_summary_off">Debug logs are disabled</string>
|
||||||
|
<string name="revanced_debug_export_logs_to_clipboard_title">Export debug logs</string>
|
||||||
|
<string name="revanced_debug_export_logs_to_clipboard_summary">Copies ReVanced debug logs to the clipboard</string>
|
||||||
|
<string name="revanced_debug_logs_disabled">Debug logging is disabled</string>
|
||||||
|
<string name="revanced_debug_logs_none_found">No logs found</string>
|
||||||
|
<string name="revanced_debug_logs_copied_to_clipboard">Logs copied</string>
|
||||||
|
<string name="revanced_debug_logs_failed_to_export">Failed to export logs: %s</string>
|
||||||
|
<string name="revanced_debug_logs_clear_buffer_title">Clear debug logs</string>
|
||||||
|
<string name="revanced_debug_logs_clear_buffer_summary">Clears all stored ReVanced debug logs</string>
|
||||||
|
<string name="revanced_debug_logs_clear_toast">Logs cleared</string>
|
||||||
|
</patch>
|
||||||
</app>
|
</app>
|
||||||
<app id="youtube">
|
<app id="youtube">
|
||||||
<patch id="misc.settings.settingsPatch">
|
<patch id="misc.settings.settingsPatch">
|
||||||
@@ -168,11 +201,6 @@ Tap the continue button and allow optimization changes."</string>
|
|||||||
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts background play is enabled</string>
|
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts background play is enabled</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.debugging.enableDebuggingPatch">
|
<patch id="misc.debugging.enableDebuggingPatch">
|
||||||
<string name="revanced_debug_screen_title">Debugging</string>
|
|
||||||
<string name="revanced_debug_screen_summary">Enable or disable debugging options</string>
|
|
||||||
<string name="revanced_debug_title">Debug logging</string>
|
|
||||||
<string name="revanced_debug_summary_on">Debug logs are enabled</string>
|
|
||||||
<string name="revanced_debug_summary_off">Debug logs are disabled</string>
|
|
||||||
<string name="revanced_debug_protobuffer_title">Log protocol buffer</string>
|
<string name="revanced_debug_protobuffer_title">Log protocol buffer</string>
|
||||||
<string name="revanced_debug_protobuffer_summary_on">Debug logs include proto buffer</string>
|
<string name="revanced_debug_protobuffer_summary_on">Debug logs include proto buffer</string>
|
||||||
<string name="revanced_debug_protobuffer_summary_off">Debug logs do not include proto buffer</string>
|
<string name="revanced_debug_protobuffer_summary_off">Debug logs do not include proto buffer</string>
|
||||||
@@ -190,15 +218,6 @@ However, enabling this will also log some user data such as your IP address."</s
|
|||||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"Turning off error toasts hides all ReVanced error notifications.
|
<string name="revanced_debug_toast_on_error_user_dialog_message">"Turning off error toasts hides all ReVanced error notifications.
|
||||||
|
|
||||||
You will not be notified of any unexpected events."</string>
|
You will not be notified of any unexpected events."</string>
|
||||||
<string name="revanced_debug_export_logs_to_clipboard_title">Export debug logs</string>
|
|
||||||
<string name="revanced_debug_export_logs_to_clipboard_summary">Copies ReVanced debug logs to the clipboard</string>
|
|
||||||
<string name="revanced_debug_logs_disabled">Debug logging is disabled</string>
|
|
||||||
<string name="revanced_debug_logs_none_found">No logs found</string>
|
|
||||||
<string name="revanced_debug_logs_copied_to_clipboard">Logs copied</string>
|
|
||||||
<string name="revanced_debug_logs_failed_to_export">Failed to export logs: %s</string>
|
|
||||||
<string name="revanced_debug_logs_clear_buffer_title">Clear debug logs</string>
|
|
||||||
<string name="revanced_debug_logs_clear_buffer_summary">Clears all stored ReVanced debug logs</string>
|
|
||||||
<string name="revanced_debug_logs_clear_toast">Logs cleared</string>
|
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||||
<string name="revanced_hide_album_cards_title">Hide album cards</string>
|
<string name="revanced_hide_album_cards_title">Hide album cards</string>
|
||||||
@@ -1493,10 +1512,6 @@ Higher video qualities might be unlocked but you may experience video playback s
|
|||||||
Enabling this can unlock higher video qualities"</string>
|
Enabling this can unlock higher video qualities"</string>
|
||||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">Enabling this can cause video playback stuttering, worse battery life, and unknown side effects.</string>
|
<string name="revanced_spoof_device_dimensions_user_dialog_message">Enabling this can cause video playback stuttering, worse battery life, and unknown side effects.</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
|
||||||
<string name="microg_settings_title">GmsCore Settings</string>
|
|
||||||
<string name="microg_settings_summary">Settings for GmsCore</string>
|
|
||||||
</patch>
|
|
||||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||||
<string name="revanced_disable_haptic_feedback_title">Haptic feedback</string>
|
<string name="revanced_disable_haptic_feedback_title">Haptic feedback</string>
|
||||||
<string name="revanced_disable_haptic_feedback_summary">Change haptic feedback</string>
|
<string name="revanced_disable_haptic_feedback_summary">Change haptic feedback</string>
|
||||||
@@ -1610,17 +1625,6 @@ Enabling this can unlock higher video qualities"</string>
|
|||||||
<string name="revanced_slide_to_seek_summary_off">Slide to seek is not enabled</string>
|
<string name="revanced_slide_to_seek_summary_off">Slide to seek is not enabled</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||||
<string name="revanced_spoof_video_streams_screen_title">Spoof video streams</string>
|
|
||||||
<string name="revanced_spoof_video_streams_screen_summary">Spoof the client video streams to prevent playback issues</string>
|
|
||||||
<string name="revanced_spoof_video_streams_title">Spoof video streams</string>
|
|
||||||
<string name="revanced_spoof_video_streams_summary_on">"Video streams are spoofed
|
|
||||||
|
|
||||||
If you are a YouTube Premium user, this setting may not be required"</string>
|
|
||||||
<string name="revanced_spoof_video_streams_summary_off">"Video streams are not spoofed
|
|
||||||
|
|
||||||
Video playback may not work"</string>
|
|
||||||
<string name="revanced_spoof_video_streams_user_dialog_message">Turning off this setting may cause video playback issues.</string>
|
|
||||||
<string name="revanced_spoof_video_streams_client_type_title">Default client</string>
|
|
||||||
<string name="revanced_spoof_video_streams_about_title">Spoofing side effects</string>
|
<string name="revanced_spoof_video_streams_about_title">Spoofing side effects</string>
|
||||||
<string name="revanced_spoof_video_streams_about_android_title">Android spoofing side effects</string>
|
<string name="revanced_spoof_video_streams_about_android_title">Android spoofing side effects</string>
|
||||||
<string name="revanced_spoof_video_streams_about_android_summary">"• Audio track menu is missing
|
<string name="revanced_spoof_video_streams_about_android_summary">"• Audio track menu is missing
|
||||||
@@ -1634,6 +1638,40 @@ Video playback may not work"</string>
|
|||||||
<string name="revanced_spoof_video_streams_language_title">Audio stream language</string>
|
<string name="revanced_spoof_video_streams_language_title">Audio stream language</string>
|
||||||
</patch>
|
</patch>
|
||||||
</app>
|
</app>
|
||||||
|
<app id="music">
|
||||||
|
<patch id="misc.settings.settingsPatch">
|
||||||
|
<string name="revanced_settings_music_screen_0_about_title">About</string>
|
||||||
|
<string name="revanced_settings_music_screen_1_ads_title">Ads</string>
|
||||||
|
<string name="revanced_settings_music_screen_2_general_title">General</string>
|
||||||
|
<string name="revanced_settings_music_screen_3_player_title">Player</string>
|
||||||
|
<string name="revanced_settings_music_screen_4_misc_title">Miscellaneous</string>
|
||||||
|
</patch>
|
||||||
|
<patch id="ad.video.hideVideoAdsPatch">
|
||||||
|
<string name="revanced_music_hide_video_ads_title">Hide video ads</string>
|
||||||
|
<string name="revanced_music_hide_video_ads_summary_on">Video ads are hidden</string>
|
||||||
|
<string name="revanced_music_hide_video_ads_summary_off">Video ads are shown</string>
|
||||||
|
</patch>
|
||||||
|
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||||
|
<string name="revanced_music_play_permanent_repeat_title">Enable permanent repeat</string>
|
||||||
|
<string name="revanced_music_play_permanent_repeat_summary_on">Permanent repeat is enabled</string>
|
||||||
|
<string name="revanced_music_play_permanent_repeat_summary_off">Permanent repeat is disabled</string>
|
||||||
|
</patch>
|
||||||
|
<patch id="layout.compactheader.hideCategoryBar">
|
||||||
|
<string name="revanced_music_hide_category_bar_title">Hide category bar</string>
|
||||||
|
<string name="revanced_music_hide_category_bar_summary_on">Category bar is hidden</string>
|
||||||
|
<string name="revanced_music_hide_category_bar_summary_off">Category bar is shown</string>
|
||||||
|
</patch>
|
||||||
|
<patch id="layout.premium.hideGetPremiumPatch">
|
||||||
|
<string name="revanced_music_hide_get_premium_label_title">Hide \'Get Music Premium\' label</string>
|
||||||
|
<string name="revanced_music_hide_get_premium_label_summary_on">Label is hidden</string>
|
||||||
|
<string name="revanced_music_hide_get_premium_label_summary_off">Label is shown</string>
|
||||||
|
</patch>
|
||||||
|
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||||
|
<string name="revanced_music_hide_upgrade_button_title">Hide upgrade button</string>
|
||||||
|
<string name="revanced_music_hide_upgrade_button_summary_on">Button is hidden</string>
|
||||||
|
<string name="revanced_music_hide_upgrade_button_summary_off">Button is shown</string>
|
||||||
|
</patch>
|
||||||
|
</app>
|
||||||
<app id="twitch">
|
<app id="twitch">
|
||||||
<patch id="ad.audio.audioAdsPatch">
|
<patch id="ad.audio.audioAdsPatch">
|
||||||
<string name="revanced_block_audio_ads_title">Block audio ads</string>
|
<string name="revanced_block_audio_ads_title">Block audio ads</string>
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:transitionGroup="true">
|
||||||
|
|
||||||
|
<!-- Parent container for Toolbar -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/revanced_toolbar_parent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/action_bar_height"
|
||||||
|
android:background="@color/ytm_color_black"
|
||||||
|
android:elevation="0dp">
|
||||||
|
|
||||||
|
<!-- Toolbar -->
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/revanced_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/action_bar_height"
|
||||||
|
android:background="@color/ytm_color_black"
|
||||||
|
app:titleTextColor="?attr/colorOnSurface"
|
||||||
|
app:navigationIcon="@drawable/revanced_settings_toolbar_arrow_left"
|
||||||
|
app:title="@string/revanced_settings_title" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Preference content container -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/revanced_settings_fragments"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/ytm_color_black" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</merge>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="Theme.ReVanced.YouTubeMusic.Settings" parent="@style/Theme.YouTubeMusic">
|
||||||
|
<item name="android:listPreferredItemPaddingStart">@dimen/item_extra_extra_large_spacing</item>
|
||||||
|
<item name="android:listDivider">@null</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
Reference in New Issue
Block a user