Skip to content

Commit 5e20bd8

Browse files
feat(YouTube Music): Add Settings patch (#5838)
Co-authored-by: LisoUseInAIKyrios <[email protected]>
1 parent f304c17 commit 5e20bd8

File tree

35 files changed

+1207
-295
lines changed

35 files changed

+1207
-295
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import app.revanced.extension.music.settings.Settings;
4+
5+
@SuppressWarnings("unused")
6+
public class HideCategoryBarPatch {
7+
8+
/**
9+
* Injection point
10+
*/
11+
public static boolean hideCategoryBar() {
12+
return Settings.HIDE_CATEGORY_BAR.get();
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import app.revanced.extension.music.settings.Settings;
4+
5+
@SuppressWarnings("unused")
6+
public class HideGetPremiumPatch {
7+
8+
/**
9+
* Injection point
10+
*/
11+
public static boolean hideGetPremiumLabel() {
12+
return Settings.HIDE_GET_PREMIUM_LABEL.get();
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import app.revanced.extension.music.settings.Settings;
4+
5+
@SuppressWarnings("unused")
6+
public class HideUpgradeButtonPatch {
7+
8+
/**
9+
* Injection point
10+
*/
11+
public static boolean hideUpgradeButton() {
12+
return Settings.HIDE_UPGRADE_BUTTON.get();
13+
}
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import app.revanced.extension.music.settings.Settings;
4+
5+
@SuppressWarnings("unused")
6+
public class HideVideoAdsPatch {
7+
8+
/**
9+
* Injection point
10+
*/
11+
public static boolean showVideoAds(boolean original) {
12+
if (Settings.HIDE_VIDEO_ADS.get()) {
13+
return false;
14+
}
15+
return original;
16+
}
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import app.revanced.extension.music.settings.Settings;
4+
5+
@SuppressWarnings("unused")
6+
public class PermanentRepeatPatch {
7+
8+
/**
9+
* Injection point
10+
*/
11+
public static boolean permanentRepeat() {
12+
return Settings.PERMANENT_REPEAT.get();
13+
}
14+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package app.revanced.extension.music.settings;
2+
3+
import android.app.Activity;
4+
import android.graphics.PorterDuff;
5+
import android.graphics.drawable.Drawable;
6+
import android.preference.PreferenceFragment;
7+
import android.view.View;
8+
9+
import app.revanced.extension.music.settings.preference.ReVancedPreferenceFragment;
10+
import app.revanced.extension.shared.Logger;
11+
import app.revanced.extension.shared.Utils;
12+
import app.revanced.extension.shared.settings.BaseActivityHook;
13+
14+
/**
15+
* Hooks GoogleApiActivity to inject a custom ReVancedPreferenceFragment with a toolbar.
16+
*/
17+
public class GoogleApiActivityHook extends BaseActivityHook {
18+
/**
19+
* Injection point
20+
* <p>
21+
* Creates an instance of GoogleApiActivityHook for use in static initialization.
22+
*/
23+
@SuppressWarnings("unused")
24+
public static GoogleApiActivityHook createInstance() {
25+
// Must touch the Music settings to ensure the class is loaded and
26+
// the values can be found when setting the UI preferences.
27+
// Logging anything under non debug ensures this is set.
28+
Logger.printInfo(() -> "Permanent repeat enabled: " + Settings.PERMANENT_REPEAT.get());
29+
30+
return new GoogleApiActivityHook();
31+
}
32+
33+
/**
34+
* Sets the fixed theme for the activity.
35+
*/
36+
@Override
37+
protected void customizeActivityTheme(Activity activity) {
38+
// Override the default YouTube Music theme to increase start padding of list items.
39+
// Custom style located in resources/music/values/style.xml
40+
activity.setTheme(Utils.getResourceIdentifier("Theme.ReVanced.YouTubeMusic.Settings", "style"));
41+
}
42+
43+
/**
44+
* Returns the resource ID for the YouTube Music settings layout.
45+
*/
46+
@Override
47+
protected int getContentViewResourceId() {
48+
return Utils.getResourceIdentifier("revanced_music_settings_with_toolbar", "layout");
49+
}
50+
51+
/**
52+
* Returns the fixed background color for the toolbar.
53+
*/
54+
@Override
55+
protected int getToolbarBackgroundColor() {
56+
return Utils.getResourceColor("ytm_color_black");
57+
}
58+
59+
/**
60+
* Returns the navigation icon with a color filter applied.
61+
*/
62+
@Override
63+
protected Drawable getNavigationIcon() {
64+
Drawable navigationIcon = ReVancedPreferenceFragment.getBackButtonDrawable();
65+
navigationIcon.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN);
66+
return navigationIcon;
67+
}
68+
69+
/**
70+
* Returns the click listener that finishes the activity when the navigation icon is clicked.
71+
*/
72+
@Override
73+
protected View.OnClickListener getNavigationClickListener(Activity activity) {
74+
return view -> activity.finish();
75+
}
76+
77+
/**
78+
* Creates a new ReVancedPreferenceFragment for the activity.
79+
*/
80+
@Override
81+
protected PreferenceFragment createPreferenceFragment() {
82+
return new ReVancedPreferenceFragment();
83+
}
84+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package app.revanced.extension.music.settings;
2+
3+
import static java.lang.Boolean.FALSE;
4+
import static java.lang.Boolean.TRUE;
5+
6+
import app.revanced.extension.shared.settings.BaseSettings;
7+
import app.revanced.extension.shared.settings.BooleanSetting;
8+
9+
public class Settings extends BaseSettings {
10+
11+
// Ads
12+
public static final BooleanSetting HIDE_VIDEO_ADS = new BooleanSetting("revanced_music_hide_video_ads", TRUE, true);
13+
public static final BooleanSetting HIDE_GET_PREMIUM_LABEL = new BooleanSetting("revanced_music_hide_get_premium_label", TRUE, true);
14+
public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true);
15+
16+
// General
17+
public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true);
18+
19+
// Player
20+
public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true);
21+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package app.revanced.extension.music.settings.preference;
2+
3+
import android.widget.Toolbar;
4+
5+
import app.revanced.extension.music.settings.GoogleApiActivityHook;
6+
import app.revanced.extension.shared.Logger;
7+
import app.revanced.extension.shared.Utils;
8+
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
9+
10+
/**
11+
* Preference fragment for ReVanced settings.
12+
*/
13+
@SuppressWarnings({"deprecation", "NewApi"})
14+
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
15+
16+
/**
17+
* Initializes the preference fragment.
18+
*/
19+
@Override
20+
protected void initialize() {
21+
super.initialize();
22+
23+
try {
24+
Utils.sortPreferenceGroups(getPreferenceScreen());
25+
setPreferenceScreenToolbar(getPreferenceScreen());
26+
} catch (Exception ex) {
27+
Logger.printException(() -> "initialize failure", ex);
28+
}
29+
}
30+
31+
/**
32+
* Sets toolbar for all nested preference screens.
33+
*/
34+
@Override
35+
protected void customizeToolbar(Toolbar toolbar) {
36+
GoogleApiActivityHook.setToolbarLayoutParams(toolbar);
37+
}
38+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package app.revanced.extension.shared.settings;
2+
3+
import android.annotation.SuppressLint;
4+
import android.app.Activity;
5+
import android.graphics.drawable.Drawable;
6+
import android.preference.PreferenceFragment;
7+
import android.util.TypedValue;
8+
import android.view.View;
9+
import android.view.ViewGroup;
10+
import android.widget.TextView;
11+
import android.widget.Toolbar;
12+
13+
import app.revanced.extension.shared.Logger;
14+
import app.revanced.extension.shared.Utils;
15+
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
16+
17+
/**
18+
* Base class for hooking activities to inject a custom PreferenceFragment with a toolbar.
19+
* Provides common logic for initializing the activity and setting up the toolbar.
20+
*/
21+
@SuppressWarnings({"deprecation", "NewApi"})
22+
public abstract class BaseActivityHook extends Activity {
23+
24+
/**
25+
* Layout parameters for the toolbar, extracted from the dummy toolbar.
26+
*/
27+
protected static ViewGroup.LayoutParams toolbarLayoutParams;
28+
29+
/**
30+
* Sets the layout parameters for the toolbar.
31+
*/
32+
public static void setToolbarLayoutParams(Toolbar toolbar) {
33+
if (toolbarLayoutParams != null) {
34+
toolbar.setLayoutParams(toolbarLayoutParams);
35+
}
36+
}
37+
38+
/**
39+
* Initializes the activity by setting the theme, content view and injecting a PreferenceFragment.
40+
*/
41+
public static void initialize(BaseActivityHook hook, Activity activity) {
42+
try {
43+
hook.customizeActivityTheme(activity);
44+
activity.setContentView(hook.getContentViewResourceId());
45+
46+
// Sanity check.
47+
String dataString = activity.getIntent().getDataString();
48+
if (!"revanced_settings_intent".equals(dataString)) {
49+
Logger.printException(() -> "Unknown intent: " + dataString);
50+
return;
51+
}
52+
53+
PreferenceFragment fragment = hook.createPreferenceFragment();
54+
hook.createToolbar(activity, fragment);
55+
56+
activity.getFragmentManager()
57+
.beginTransaction()
58+
.replace(Utils.getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
59+
.commit();
60+
} catch (Exception ex) {
61+
Logger.printException(() -> "initialize failure", ex);
62+
}
63+
}
64+
65+
/**
66+
* Creates and configures a toolbar for the activity, replacing a dummy placeholder.
67+
*/
68+
@SuppressLint("UseCompatLoadingForDrawables")
69+
protected void createToolbar(Activity activity, PreferenceFragment fragment) {
70+
// Replace dummy placeholder toolbar.
71+
// This is required to fix submenu title alignment issue with Android ASOP 15+
72+
ViewGroup toolBarParent = activity.findViewById(
73+
Utils.getResourceIdentifier("revanced_toolbar_parent", "id"));
74+
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
75+
toolbarLayoutParams = dummyToolbar.getLayoutParams();
76+
toolBarParent.removeView(dummyToolbar);
77+
78+
// Sets appropriate system navigation bar color for the activity.
79+
ToolbarPreferenceFragment.setNavigationBarColor(activity.getWindow());
80+
81+
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
82+
toolbar.setBackgroundColor(getToolbarBackgroundColor());
83+
toolbar.setNavigationIcon(getNavigationIcon());
84+
toolbar.setNavigationOnClickListener(getNavigationClickListener(activity));
85+
toolbar.setTitle(Utils.getResourceIdentifier("revanced_settings_title", "string"));
86+
87+
final int margin = Utils.dipToPixels(16);
88+
toolbar.setTitleMarginStart(margin);
89+
toolbar.setTitleMarginEnd(margin);
90+
TextView toolbarTextView = Utils.getChildView(toolbar, false, view -> view instanceof TextView);
91+
if (toolbarTextView != null) {
92+
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
93+
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
94+
}
95+
setToolbarLayoutParams(toolbar);
96+
97+
onPostToolbarSetup(activity, toolbar, fragment);
98+
99+
toolBarParent.addView(toolbar, 0);
100+
}
101+
102+
/**
103+
* Customizes the activity's theme.
104+
*/
105+
protected abstract void customizeActivityTheme(Activity activity);
106+
107+
/**
108+
* Returns the resource ID for the content view layout.
109+
*/
110+
protected abstract int getContentViewResourceId();
111+
112+
/**
113+
* Returns the background color for the toolbar.
114+
*/
115+
protected abstract int getToolbarBackgroundColor();
116+
117+
/**
118+
* Returns the navigation icon drawable for the toolbar.
119+
*/
120+
protected abstract Drawable getNavigationIcon();
121+
122+
/**
123+
* Returns the click listener for the toolbar's navigation icon.
124+
*/
125+
protected abstract View.OnClickListener getNavigationClickListener(Activity activity);
126+
127+
/**
128+
* Creates the PreferenceFragment to be injected into the activity.
129+
*/
130+
protected PreferenceFragment createPreferenceFragment() {
131+
return new ToolbarPreferenceFragment();
132+
}
133+
134+
/**
135+
* Performs additional setup after the toolbar is configured.
136+
*
137+
* @param activity The activity hosting the toolbar.
138+
* @param toolbar The configured toolbar.
139+
* @param fragment The PreferenceFragment associated with the activity.
140+
*/
141+
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {}
142+
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
package app.revanced.extension.youtube.settings.preference;
1+
package app.revanced.extension.shared.settings.preference;
22

33
import android.content.Context;
44
import android.util.AttributeSet;
55
import android.preference.Preference;
6-
import app.revanced.extension.shared.settings.preference.LogBufferManager;
76

87
/**
98
* A custom preference that clears the ReVanced debug log buffer when clicked.

0 commit comments

Comments
 (0)