From 2a57ffe002a9e7fc5efc6be770db2fc45aae9370 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:10:20 +0900 Subject: [PATCH] feat(YouTube - Seekbar components): Add option to use custom seekbar accent color (Close https://github.com/inotia00/ReVanced_Extended/issues/2738) --- .../patches/player/SeekbarColorPatch.java | 140 +++++++++++------- .../extension/youtube/settings/Settings.java | 5 +- .../youtube/player/seekbar/Fingerprints.kt | 69 +++++---- .../player/seekbar/SeekbarComponentsPatch.kt | 94 ++++++++---- .../utils/resourceid/SharedResourceIdPatch.kt | 6 + .../youtube/settings/host/values/strings.xml | 8 +- .../youtube/settings/xml/revanced_prefs.xml | 7 +- 7 files changed, 213 insertions(+), 116 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/SeekbarColorPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/SeekbarColorPatch.java index 256d19902..8b3b99528 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/SeekbarColorPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/SeekbarColorPatch.java @@ -20,38 +20,53 @@ public class SeekbarColorPatch { private static final boolean CUSTOM_SEEKBAR_COLOR_ENABLED = Settings.ENABLE_CUSTOM_SEEKBAR_COLOR.get(); + private static final boolean HIDE_SEEKBAR_THUMBNAIL_ENABLED = + Settings.HIDE_SEEKBAR_THUMBNAIL.get(); + /** * Default color of the litho seekbar. * Differs slightly from the default custom seekbar color setting. */ private static final int ORIGINAL_SEEKBAR_COLOR = 0xFFFF0000; + /** + * Default accent color of the litho seekbar. + */ + private static final int ORIGINAL_SEEKBAR_COLOR_ACCENT = 0xFFFF2791; + /** * Feed default colors of the gradient seekbar. */ - private static final int[] FEED_ORIGINAL_SEEKBAR_GRADIENT_COLORS = {0xFFFF0033, 0xFFFF2791}; + private static final int[] FEED_ORIGINAL_SEEKBAR_GRADIENT_COLORS = {0xFFFF0033, ORIGINAL_SEEKBAR_COLOR_ACCENT}; /** * Feed default positions of the gradient seekbar. */ private static final float[] FEED_ORIGINAL_SEEKBAR_GRADIENT_POSITIONS = {0.8f, 1.0f}; + /** + * Empty seekbar gradient, if hide seekbar in feed is enabled. + */ + private static final int[] HIDDEN_SEEKBAR_GRADIENT_COLORS = { 0x0, 0x0 }; + /** * Default YouTube seekbar color brightness. */ private static final float ORIGINAL_SEEKBAR_COLOR_BRIGHTNESS; /** - * Empty seekbar gradient, if hide seekbar in feed is enabled. + * If {@link Settings#ENABLE_CUSTOM_SEEKBAR_COLOR} is enabled, + * this is the color value of {@link Settings#CUSTOM_SEEKBAR_COLOR_PRIMARY}. + * Otherwise this is {@link #ORIGINAL_SEEKBAR_COLOR}. */ - private static final int[] HIDDEN_SEEKBAR_GRADIENT_COLORS = {0x00000000, 0x00000000}; + private static int customSeekbarColor = ORIGINAL_SEEKBAR_COLOR; /** * If {@link Settings#ENABLE_CUSTOM_SEEKBAR_COLOR} is enabled, - * this is the color value of {@link Settings#CUSTOM_SEEKBAR_COLOR_VALUE}. - * Otherwise this is {@link #ORIGINAL_SEEKBAR_COLOR}. + * this is the color value of {@link Settings#CUSTOM_SEEKBAR_COLOR_ACCENT}. + * Otherwise this is {@link #ORIGINAL_SEEKBAR_COLOR_ACCENT}. */ - private static int seekbarColor = ORIGINAL_SEEKBAR_COLOR; + private static int customSeekbarColorAccent = ORIGINAL_SEEKBAR_COLOR_ACCENT; /** * Custom seekbar hue, saturation, and brightness values. @@ -61,7 +76,7 @@ public class SeekbarColorPatch { /** * Custom seekbar color, used for linear gradient replacements. */ - private static final int[] customSeekbarColorInt = new int[2]; + private static final int[] customSeekbarColorGradient = new int[2]; static { float[] hsv = new float[3]; @@ -71,33 +86,28 @@ public class SeekbarColorPatch { if (CUSTOM_SEEKBAR_COLOR_ENABLED) { loadCustomSeekbarColor(); } - - Arrays.fill(customSeekbarColorInt, seekbarColor); } private static void loadCustomSeekbarColor() { try { - seekbarColor = Color.parseColor(Settings.CUSTOM_SEEKBAR_COLOR_VALUE.get()); - Color.colorToHSV(seekbarColor, customSeekbarColorHSV); + customSeekbarColor = Color.parseColor(Settings.CUSTOM_SEEKBAR_COLOR_PRIMARY.get()); + Color.colorToHSV(customSeekbarColor, customSeekbarColorHSV); + + customSeekbarColorAccent = Color.parseColor(Settings.CUSTOM_SEEKBAR_COLOR_ACCENT.get()); + customSeekbarColorGradient[0] = customSeekbarColor; + customSeekbarColorGradient[1] = customSeekbarColorAccent; } catch (Exception ex) { - Utils.showToastShort(str("revanced_custom_seekbar_color_value_invalid_invalid_toast")); + Utils.showToastShort(str("revanced_custom_seekbar_color_invalid_toast")); Utils.showToastShort(str("revanced_extended_reset_to_default_toast")); - Settings.CUSTOM_SEEKBAR_COLOR_VALUE.resetToDefault(); + Settings.CUSTOM_SEEKBAR_COLOR_PRIMARY.resetToDefault(); + Settings.CUSTOM_SEEKBAR_COLOR_ACCENT.resetToDefault(); + loadCustomSeekbarColor(); } } public static int getSeekbarColor() { - return seekbarColor; - } - - /** - * Injection point - */ - public static boolean playerSeekbarGradientEnabled(boolean original) { - if (CUSTOM_SEEKBAR_COLOR_ENABLED) return false; - - return original; + return customSeekbarColor; } /** @@ -141,7 +151,7 @@ public class SeekbarColorPatch { // Even if the seekbar color xml value is changed to a completely different color (such as green), // a color filter still cannot be selectively applied when the drawable has more than 1 color. try { - String seekbarStyle = get9BitStyleIdentifier(seekbarColor); + String seekbarStyle = get9BitStyleIdentifier(customSeekbarColor); Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle); final int styleIdentifierDefault = ResourceUtils.getStyleIdentifier(seekbarStyle); @@ -158,6 +168,20 @@ public class SeekbarColorPatch { } } + /** + * Injection point + */ + public static boolean playerSeekbarGradientEnabled(boolean original) { + return CUSTOM_SEEKBAR_COLOR_ENABLED || original; + } + + /** + * Injection point. + */ + public static boolean showWatchHistoryProgressDrawable(boolean original) { + return !HIDE_SEEKBAR_THUMBNAIL_ENABLED && original; + } + /** * Injection point. *
@@ -168,31 +192,21 @@ public class SeekbarColorPatch { */ public static int getLithoColor(int colorValue) { if (colorValue == ORIGINAL_SEEKBAR_COLOR) { - if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) { - return 0x00000000; + if (HIDE_SEEKBAR_THUMBNAIL_ENABLED) { + return 0x0; } - return getSeekbarColorValue(ORIGINAL_SEEKBAR_COLOR); + return customSeekbarColor; } - return colorValue; - } - /** - * Injection point. - */ - public static int[] getLinearGradient(int[] original) { - if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) { - return HIDDEN_SEEKBAR_GRADIENT_COLORS; - } - return CUSTOM_SEEKBAR_COLOR_ENABLED - ? customSeekbarColorInt - : original; + return colorValue; } private static String colorArrayToHex(int[] colors) { final int length = colors.length; - StringBuilder builder = new StringBuilder(length * 10); + StringBuilder builder = new StringBuilder(length * 12); builder.append("["); + int i = 0; for (int color : colors) { builder.append(String.format("#%X", color)); @@ -200,6 +214,7 @@ public class SeekbarColorPatch { builder.append(", "); } } + builder.append("]"); return builder.toString(); } @@ -207,23 +222,31 @@ public class SeekbarColorPatch { /** * Injection point. */ - public static void setLinearGradient(int[] colors, float[] positions) { - final boolean hideSeekbar = Settings.HIDE_SEEKBAR_THUMBNAIL.get(); + public static int[] getPlayerLinearGradient(int[] original) { + return CUSTOM_SEEKBAR_COLOR_ENABLED + ? customSeekbarColorGradient + : original; + } - if (CUSTOM_SEEKBAR_COLOR_ENABLED || hideSeekbar) { + /** + * Injection point. + */ + public static int[] getLithoLinearGradient(int[] colors, float[] positions) { + if (CUSTOM_SEEKBAR_COLOR_ENABLED || HIDE_SEEKBAR_THUMBNAIL_ENABLED) { // Most litho usage of linear gradients is hooked here, // so must only change if the values are those for the seekbar. if ((Arrays.equals(FEED_ORIGINAL_SEEKBAR_GRADIENT_COLORS, colors) && Arrays.equals(FEED_ORIGINAL_SEEKBAR_GRADIENT_POSITIONS, positions))) { - Arrays.fill(colors, hideSeekbar - ? 0x00000000 - : seekbarColor); - return; + return HIDE_SEEKBAR_THUMBNAIL_ENABLED + ? HIDDEN_SEEKBAR_GRADIENT_COLORS + : customSeekbarColorGradient; } Logger.printDebug(() -> "Ignoring gradient colors: " + colorArrayToHex(colors) + " positions: " + Arrays.toString(positions)); } + + return colors; } /** @@ -247,11 +270,20 @@ public class SeekbarColorPatch { * Overrides color used for the video player seekbar. */ public static int getVideoPlayerSeekbarColor(int originalColor) { - if (!CUSTOM_SEEKBAR_COLOR_ENABLED) { - return originalColor; - } + return CUSTOM_SEEKBAR_COLOR_ENABLED + ? getSeekbarColorValue(originalColor) + : originalColor; + } - return getSeekbarColorValue(originalColor); + /** + * Injection point. + *
+ * Overrides color used for the video player seekbar.
+ */
+ public static int getVideoPlayerSeekbarColorAccent(int originalColor) {
+ return CUSTOM_SEEKBAR_COLOR_ENABLED
+ ? customSeekbarColorAccent
+ : originalColor;
}
/**
@@ -260,10 +292,6 @@ public class SeekbarColorPatch {
*/
private static int getSeekbarColorValue(int originalColor) {
try {
- if (!CUSTOM_SEEKBAR_COLOR_ENABLED || originalColor == seekbarColor) {
- return originalColor; // nothing to do
- }
-
final int alphaDifference = Color.alpha(originalColor) - Color.alpha(ORIGINAL_SEEKBAR_COLOR);
// The seekbar uses the same color but different brightness for different situations.
@@ -276,7 +304,7 @@ public class SeekbarColorPatch {
hsv[1] = customSeekbarColorHSV[1];
hsv[2] = clamp(customSeekbarColorHSV[2] + brightnessDifference, 0, 1);
- final int replacementAlpha = clamp(Color.alpha(seekbarColor) + alphaDifference, 0, 255);
+ final int replacementAlpha = clamp(Color.alpha(customSeekbarColor) + alphaDifference, 0, 255);
final int replacementColor = Color.HSVToColor(replacementAlpha, hsv);
Logger.printDebug(() -> String.format("Original color: #%08X replacement color: #%08X",
originalColor, replacementColor));
diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java
index 020847421..ee63c3946 100644
--- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java
+++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java
@@ -419,11 +419,12 @@ public class Settings extends BaseSettings {
public static final BooleanSetting REPLACE_TIME_STAMP_ACTION = new BooleanSetting("revanced_replace_time_stamp_action", TRUE, true, parent(APPEND_TIME_STAMP_INFORMATION));
public static final BooleanSetting DISABLE_SEEKBAR_CHAPTERS = new BooleanSetting("revanced_disable_seekbar_chapters", FALSE, true);
public static final BooleanSetting ENABLE_CUSTOM_SEEKBAR_COLOR = new BooleanSetting("revanced_enable_custom_seekbar_color", FALSE, true);
- public static final StringSetting CUSTOM_SEEKBAR_COLOR_VALUE = new StringSetting("revanced_custom_seekbar_color_value", "#FF0033", true, parent(ENABLE_CUSTOM_SEEKBAR_COLOR));
+ public static final StringSetting CUSTOM_SEEKBAR_COLOR_PRIMARY = new StringSetting("revanced_custom_seekbar_color_primary", "#FF0033", true, parent(ENABLE_CUSTOM_SEEKBAR_COLOR));
+ public static final StringSetting CUSTOM_SEEKBAR_COLOR_ACCENT = new StringSetting("revanced_custom_seekbar_color_accent", "#FF2791", true, parent(ENABLE_CUSTOM_SEEKBAR_COLOR));
public static final BooleanSetting ENABLE_SEEKBAR_TAPPING = new BooleanSetting("revanced_enable_seekbar_tapping", TRUE);
public static final BooleanSetting HIDE_SEEKBAR_CHAPTER_LABEL = new BooleanSetting("revanced_hide_seekbar_chapter_label", FALSE, true);
public static final BooleanSetting HIDE_SEEKBAR = new BooleanSetting("revanced_hide_seekbar", FALSE, true);
- public static final BooleanSetting HIDE_SEEKBAR_THUMBNAIL = new BooleanSetting("revanced_hide_seekbar_thumbnail", FALSE);
+ public static final BooleanSetting HIDE_SEEKBAR_THUMBNAIL = new BooleanSetting("revanced_hide_seekbar_thumbnail", FALSE, true);
public static final BooleanSetting HIDE_TIME_STAMP = new BooleanSetting("revanced_hide_time_stamp", FALSE, true);
public static final BooleanSetting RESTORE_OLD_SEEKBAR_THUMBNAILS = new BooleanSetting("revanced_restore_old_seekbar_thumbnails",
PatchStatus.OldSeekbarThumbnailsDefaultBoolean(), true);
diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt
index d6ce2d8e3..f28ffa716 100644
--- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt
+++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt
@@ -1,12 +1,30 @@
package app.revanced.patches.youtube.player.seekbar
import app.revanced.patches.youtube.utils.resourceid.reelTimeBarPlayedColor
+import app.revanced.patches.youtube.utils.resourceid.ytStaticBrandRed
import app.revanced.patches.youtube.utils.resourceid.ytYoutubeMagenta
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
+import kotlin.collections.listOf
+
+internal val shortsSeekbarColorFingerprint = legacyFingerprint(
+ name = "shortsSeekbarColorFingerprint",
+ returnType = "V",
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
+ literals = listOf(reelTimeBarPlayedColor),
+)
+
+internal val controlsOverlayStyleFingerprint = legacyFingerprint(
+ name = "controlsOverlayStyleFingerprint",
+ opcodes = listOf(Opcode.CONST_HIGH16),
+ strings = listOf("YOUTUBE", "PREROLL", "POSTROLL"),
+ customFingerprint = { method, _ ->
+ method.definingClass.endsWith("/ControlsOverlayStyle;")
+ }
+)
internal const val PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG = 45617850L
@@ -17,6 +35,21 @@ internal val playerSeekbarGradientConfigFingerprint = legacyFingerprint(
literals = listOf(PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG),
)
+internal val playerSeekbarHandleColorFingerprint = legacyFingerprint(
+ name = "playerSeekbarHandleColorFingerprint",
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
+ parameters = listOf("Landroid/content/Context;"),
+ literals = listOf(ytStaticBrandRed),
+)
+
+internal val watchHistoryMenuUseProgressDrawableFingerprint = legacyFingerprint(
+ name = "watchHistoryMenuUseProgressDrawableFingerprint",
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+ returnType = "V",
+ parameters = listOf("L"),
+ literals = listOf(-1712394514),
+)
+
internal val lithoLinearGradientFingerprint = legacyFingerprint(
name = "lithoLinearGradientFingerprint",
accessFlags = AccessFlags.STATIC.value,
@@ -25,11 +58,13 @@ internal val lithoLinearGradientFingerprint = legacyFingerprint(
)
/**
- * YouTube 19.25 - 19.47
+ * YouTube 19.49+
*/
-internal val playerLinearGradientLegacyFingerprint = legacyFingerprint(
- name = "playerLinearGradientLegacyFingerprint",
- returnType = "V",
+internal val playerLinearGradientFingerprint = legacyFingerprint(
+ name = "playerLinearGradientFingerprint",
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
+ parameters = listOf("I", "I", "I", "I", "Landroid/content/Context;", "I"),
+ returnType = "Landroid/graphics/LinearGradient;",
opcodes = listOf(
Opcode.FILLED_NEW_ARRAY,
Opcode.MOVE_RESULT_OBJECT
@@ -38,13 +73,11 @@ internal val playerLinearGradientLegacyFingerprint = legacyFingerprint(
)
/**
- * YouTube 19.49+
+ * YouTube 19.25 - 19.47
*/
-internal val playerLinearGradientFingerprint = legacyFingerprint(
- name = "playerLinearGradientFingerprint",
- returnType = "Landroid/graphics/LinearGradient;",
- accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
- parameters = listOf("I", "I", "I", "I", "Landroid/content/Context;", "I"),
+internal val playerLinearGradientLegacyFingerprint = legacyFingerprint(
+ name = "playerLinearGradientLegacyFingerprint",
+ returnType = "V",
opcodes = listOf(
Opcode.FILLED_NEW_ARRAY,
Opcode.MOVE_RESULT_OBJECT
@@ -67,15 +100,6 @@ internal val launchScreenLayoutTypeFingerprint = legacyFingerprint(
}
)
-internal val controlsOverlayStyleFingerprint = legacyFingerprint(
- name = "controlsOverlayStyleFingerprint",
- opcodes = listOf(Opcode.CONST_HIGH16),
- strings = listOf("YOUTUBE", "PREROLL", "POSTROLL"),
- customFingerprint = { method, _ ->
- method.definingClass.endsWith("/ControlsOverlayStyle;")
- }
-)
-
internal val seekbarTappingFingerprint = legacyFingerprint(
name = "seekbarTappingFingerprint",
returnType = "Z",
@@ -108,13 +132,6 @@ internal val seekbarThumbnailsQualityFingerprint = legacyFingerprint(
literals = listOf(45399684L),
)
-internal val shortsSeekbarColorFingerprint = legacyFingerprint(
- name = "shortsSeekbarColorFingerprint",
- returnType = "V",
- accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
- literals = listOf(reelTimeBarPlayedColor),
-)
-
internal val thumbnailPreviewConfigFingerprint = legacyFingerprint(
name = "thumbnailPreviewConfigFingerprint",
returnType = "Z",
diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt
index fe14c9d11..841804880 100644
--- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt
+++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt
@@ -24,6 +24,7 @@ import app.revanced.patches.youtube.utils.playerButtonsResourcesFingerprint
import app.revanced.patches.youtube.utils.playerButtonsVisibilityFingerprint
import app.revanced.patches.youtube.utils.playerSeekbarColorFingerprint
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
+import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_49_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
@@ -31,6 +32,7 @@ import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarColorizedBarPl
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarPlayedNotHighlightedColor
import app.revanced.patches.youtube.utils.resourceid.reelTimeBarPlayedColor
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
+import app.revanced.patches.youtube.utils.resourceid.ytStaticBrandRed
import app.revanced.patches.youtube.utils.seekbarFingerprint
import app.revanced.patches.youtube.utils.seekbarOnDrawFingerprint
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
@@ -215,14 +217,18 @@ val seekbarComponentsPatch = bytecodePatch(
// region patch for seekbar color
- fun MutableMethod.addColorChangeInstructions(literal: Long) {
- val insertIndex = indexOfFirstLiteralInstructionOrThrow(literal) + 2
- val insertRegister = getInstruction