feat(YouTube Music): Add Settings patch (#5838)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
parent
f304c178e2
commit
5e20bd80f1
35 changed files with 1207 additions and 295 deletions
|
|
@ -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) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.preference.Preference;
|
||||
|
||||
/**
|
||||
* A custom preference that clears the ReVanced debug log buffer when clicked.
|
||||
* Invokes the {@link LogBufferManager#clearLogBuffer} method.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ClearLogBufferPreference extends Preference {
|
||||
|
||||
{
|
||||
setOnPreferenceClickListener(pref -> {
|
||||
LogBufferManager.clearLogBuffer();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public ClearLogBufferPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
public ClearLogBufferPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public ClearLogBufferPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public ClearLogBufferPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.preference.Preference;
|
||||
|
||||
/**
|
||||
* A custom preference that triggers exporting ReVanced debug logs to the clipboard when clicked.
|
||||
* Invokes the {@link LogBufferManager#exportToClipboard} method.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "unused"})
|
||||
public class ExportLogToClipboardPreference extends Preference {
|
||||
|
||||
{
|
||||
setOnPreferenceClickListener(pref -> {
|
||||
LogBufferManager.exportToClipboard();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public ExportLogToClipboardPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
public ExportLogToClipboardPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public ExportLogToClipboardPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public ExportLogToClipboardPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue