diff --git a/app/src/main/java/app/revanced/integrations/patches/theme/ProgressBarDrawable.java b/app/src/main/java/app/revanced/integrations/patches/theme/ProgressBarDrawable.java new file mode 100644 index 00000000..890fc44c --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/patches/theme/ProgressBarDrawable.java @@ -0,0 +1,47 @@ +package app.revanced.integrations.patches.theme; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import app.revanced.integrations.patches.HideSeekbarPatch; +import app.revanced.integrations.settings.SettingsEnum; + +/** + * Used by {@link SeekbarColorPatch} change the color of the seekbar. + * and {@link HideSeekbarPatch} to hide the seekbar of the feed and watch history. + */ +public class ProgressBarDrawable extends Drawable { + + private final Paint paint = new Paint(); + + @Override + public void draw(@NonNull Canvas canvas) { + if (SettingsEnum.HIDE_SEEKBAR.getBoolean()) { + return; + } + paint.setColor(SeekbarColorPatch.getCustomSeekbarColor()); + canvas.drawRect(getBounds(), paint); + } + + @Override + public void setAlpha(int alpha) { + paint.setAlpha(alpha); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + paint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + +} diff --git a/app/src/main/java/app/revanced/integrations/patches/theme/SeekbarColorPatch.java b/app/src/main/java/app/revanced/integrations/patches/theme/SeekbarColorPatch.java new file mode 100644 index 00000000..1505732d --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/patches/theme/SeekbarColorPatch.java @@ -0,0 +1,111 @@ +package app.revanced.integrations.patches.theme; + +import android.graphics.Color; + +import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.utils.LogHelper; +import app.revanced.integrations.utils.ReVancedUtils; + +public final class SeekbarColorPatch { + + /** + * Default color of seekbar. + */ + private static final int ORIGINAL_SEEKBAR_COLOR = 0xFFFF0000; + + /** + * Default YouTube seekbar color brightness. + */ + private static final float ORIGINAL_SEEKBAR_COLOR_BRIGHTNESS; + + /** + * Color value of {@link SettingsEnum#SEEKBAR_COLOR} + */ + private static int customSeekbarColor; + + /** + * Custom seekbar hue, saturation, and brightness values. + */ + private static final float[] customSeekbarColorHSV = new float[3]; + + static { + float[] hsv = new float[3]; + Color.colorToHSV(ORIGINAL_SEEKBAR_COLOR, hsv); + ORIGINAL_SEEKBAR_COLOR_BRIGHTNESS = hsv[2]; + + loadCustomSeekbarColorHSV(); + } + + private static void loadCustomSeekbarColorHSV() { + try { + customSeekbarColor = Color.parseColor(SettingsEnum.SEEKBAR_COLOR.getString()); + Color.colorToHSV(customSeekbarColor, customSeekbarColorHSV); + } catch (Exception ex) { + ReVancedUtils.showToastShort("Invalid seekbar color value. Using default value."); + SettingsEnum.SEEKBAR_COLOR.saveValue(SettingsEnum.SEEKBAR_COLOR.defaultValue); + loadCustomSeekbarColorHSV(); + } + } + + public static int getCustomSeekbarColor() { + return customSeekbarColor; + } + + /** + * Injection point. + * + * Overrides color when seekbar is clicked, and all Litho components that use the YouTube seekbar color. + */ + public static int getSeekbarColorOverride(int colorValue) { + return colorValue == ORIGINAL_SEEKBAR_COLOR + ? getSeekbarColorValue(ORIGINAL_SEEKBAR_COLOR) + : colorValue; + } + + /** + * Injection point. + * + * If {@link SettingsEnum#HIDE_SEEKBAR} is enabled, this returns a fully transparent color. + * + * Otherwise the original color is changed to the custom seekbar color, while retaining + * the brightness and alpha changes of the parameter value compared to the original seekbar color. + */ + public static int getSeekbarColorValue(int originalColor) { + try { + if (SettingsEnum.HIDE_SEEKBAR.getBoolean()) { + return 0x00000000; + } + if (customSeekbarColor == ORIGINAL_SEEKBAR_COLOR) { + 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. + float[] hsv = new float[3]; + Color.colorToHSV(originalColor, hsv); + final float brightnessDifference = hsv[2] - ORIGINAL_SEEKBAR_COLOR_BRIGHTNESS; + + // Apply the brightness difference to the custom seekbar color. + hsv[0] = customSeekbarColorHSV[0]; + hsv[1] = customSeekbarColorHSV[1]; + hsv[2] = clamp(customSeekbarColorHSV[2] + brightnessDifference, 0, 1); + + final int replacementAlpha = clamp(Color.alpha(customSeekbarColor) + alphaDifference, 0, 255); + final int replacementColor = Color.HSVToColor(replacementAlpha, hsv); + LogHelper.printDebug(() -> String.format("Original color: #%08X replacement color: #%08X", + originalColor, replacementColor)); + return replacementColor; + } catch (Exception ex) { + LogHelper.printException(() -> "getSeekbarColorValue failure", ex); + return originalColor; + } + } + + static int clamp(int value, int lower, int upper) { + return Math.max(lower, Math.min(value, upper)); + } + + static float clamp(float value, float lower, float upper) { + return Math.max(lower, Math.min(value, upper)); + } +} diff --git a/app/src/main/java/app/revanced/integrations/patches/theme/ThemePatch.java b/app/src/main/java/app/revanced/integrations/patches/theme/ThemePatch.java deleted file mode 100644 index 6a13c6e6..00000000 --- a/app/src/main/java/app/revanced/integrations/patches/theme/ThemePatch.java +++ /dev/null @@ -1,32 +0,0 @@ -package app.revanced.integrations.patches.theme; - -import android.graphics.Color; - -import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.utils.ReVancedUtils; - -public final class ThemePatch { - private static final int ORIGINAL_SEEKBAR_CLICKED_COLOR = -65536; - - private static void resetSeekbarColor() { - ReVancedUtils.showToastShort("Invalid seekbar color value. Using default value."); - SettingsEnum.SEEKBAR_COLOR.saveValue(SettingsEnum.SEEKBAR_COLOR.defaultValue); - } - - /** - * Injection point. - */ - public static int getSeekbarClickedColorValue(final int colorValue) { - // YouTube uses a specific color when the seekbar is clicked. Override in that case. - return colorValue == ORIGINAL_SEEKBAR_CLICKED_COLOR ? getSeekbarColorValue() : colorValue; - } - - public static int getSeekbarColorValue() { - try { - return Color.parseColor(SettingsEnum.SEEKBAR_COLOR.getString()); - } catch (Exception exception) { - resetSeekbarColor(); - return getSeekbarColorValue(); - } - } -} diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 8b65f085..f2e79ffb 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -3,7 +3,6 @@ package app.revanced.integrations.settings; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import app.revanced.integrations.utils.StringRef; -import app.revanced.integrations.patches.theme.ThemePatch; import java.util.Objects; @@ -95,7 +94,7 @@ public enum SettingsEnum { HIDE_PLAYER_BUTTONS("revanced_hide_player_buttons", BOOLEAN, FALSE), HIDE_PLAYER_OVERLAY("revanced_hide_player_overlay", BOOLEAN, FALSE, true), HIDE_PREVIEW_COMMENT("revanced_hide_preview_comment", BOOLEAN, FALSE, true), - HIDE_SEEKBAR("revanced_hide_seekbar", BOOLEAN, FALSE), + HIDE_SEEKBAR("revanced_hide_seekbar", BOOLEAN, FALSE, true), HIDE_HOME_BUTTON("revanced_hide_home_button", BOOLEAN, FALSE, true), HIDE_SHORTS_BUTTON("revanced_hide_shorts_button", BOOLEAN, TRUE, true), HIDE_SUBSCRIPTIONS_BUTTON("revanced_hide_subscriptions_button", BOOLEAN, FALSE, true),