Skip to content

Commit 42db0c2

Browse files
feat(YouTube - Theme): Add option for black and white splash screen animation (#5119)
1 parent 50b68f0 commit 42db0c2

File tree

7 files changed

+125
-32
lines changed

7 files changed

+125
-32
lines changed

extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static app.revanced.extension.shared.StringRef.str;
44
import static app.revanced.extension.shared.Utils.clamp;
5+
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
56

67
import android.content.res.Resources;
78
import android.graphics.Color;
@@ -173,23 +174,15 @@ public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vector
173174
*/
174175
public static void setSplashAnimationLottie(LottieAnimationView view, int resourceId) {
175176
try {
176-
if (!SEEKBAR_CUSTOM_COLOR_ENABLED) {
177+
SplashScreenAnimationStyle animationStyle = Settings.SPLASH_SCREEN_ANIMATION_STYLE.get();
178+
if (!SEEKBAR_CUSTOM_COLOR_ENABLED
179+
// Black and white animations cannot use color replacements.
180+
|| animationStyle == SplashScreenAnimationStyle.FPS_30_BLACK_AND_WHITE
181+
|| animationStyle == SplashScreenAnimationStyle.FPS_60_BLACK_AND_WHITE) {
177182
view.patch_setAnimation(resourceId);
178183
return;
179184
}
180185

181-
//noinspection ConstantConditions
182-
if (false) { // Set true to force slow animation for development.
183-
final int longAnimation = Utils.getResourceIdentifier(
184-
Utils.isDarkModeEnabled()
185-
? "startup_animation_5s_30fps_dark"
186-
: "startup_animation_5s_30fps_light",
187-
"raw");
188-
if (longAnimation != 0) {
189-
resourceId = longAnimation;
190-
}
191-
}
192-
193186
// Must specify primary key name otherwise the morphing YT logo color is also changed.
194187
String originalKey = "\"k\":";
195188
String originalPrimary = originalKey + "[1,0,0.2,1]";
@@ -199,21 +192,16 @@ public static void setSplashAnimationLottie(LottieAnimationView view, int resour
199192
String replacementAccent = originalKey + getColorStringArray(customSeekbarColorGradient[1]);
200193

201194
String json = loadRawResourceAsString(resourceId);
202-
if (json == null) {
203-
return; // Should never happen.
204-
}
195+
String replacement = json
196+
.replace(originalPrimary, replacementPrimary)
197+
.replace(originalAccent, replacementAccent);
205198

206199
if (BaseSettings.DEBUG.get() && (!json.contains(originalPrimary) || !json.contains(originalAccent))) {
207-
String jsonFinal = json;
208-
Logger.printException(() -> "Could not replace launch animation colors: " + jsonFinal);
200+
Logger.printException(() -> "Could not replace splash animation colors: " + json);
209201
}
210202

211-
Logger.printDebug(() -> "Replacing Lottie animation JSON");
212-
json = json.replace(originalPrimary, replacementPrimary);
213-
json = json.replace(originalAccent, replacementAccent);
214-
215203
// cacheKey is not needed since the animation will not be reused.
216-
view.patch_setAnimation(new ByteArrayInputStream(json.getBytes()), null);
204+
view.patch_setAnimation(new ByteArrayInputStream(replacement.getBytes()), null);
217205
} catch (Exception ex) {
218206
Logger.printException(() -> "setSplashAnimationLottie failure", ex);
219207
}
@@ -234,8 +222,7 @@ private static String loadRawResourceAsString(int resourceId) {
234222
Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
235223
return scanner.next();
236224
} catch (IOException e) {
237-
Logger.printException(() -> "Could not load resource: " + resourceId);
238-
return null;
225+
throw new IllegalStateException("Could not load resource: " + resourceId);
239226
}
240227
}
241228

extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/ThemePatch.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,49 @@
11
package app.revanced.extension.youtube.patches.theme;
22

3+
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle.styleFromOrdinal;
4+
5+
import androidx.annotation.Nullable;
6+
7+
import app.revanced.extension.shared.Logger;
38
import app.revanced.extension.shared.Utils;
49
import app.revanced.extension.youtube.ThemeHelper;
510
import app.revanced.extension.youtube.settings.Settings;
611

712
@SuppressWarnings("unused")
813
public class ThemePatch {
14+
15+
public enum SplashScreenAnimationStyle {
16+
DEFAULT(0),
17+
FPS_60_ONE_SECOND(1),
18+
FPS_60_TWO_SECOND(2),
19+
FPS_60_FIVE_SECOND(3),
20+
FPS_60_BLACK_AND_WHITE(4),
21+
FPS_30_ONE_SECOND(5),
22+
FPS_30_TWO_SECOND(6),
23+
FPS_30_FIVE_SECOND(7),
24+
FPS_30_BLACK_AND_WHITE(8);
25+
// There exists a 10th json style used as the switch statement default,
26+
// but visually it is identical to 60fps one second.
27+
28+
@Nullable
29+
static SplashScreenAnimationStyle styleFromOrdinal(int style) {
30+
// Alternatively can return using values()[style]
31+
for (SplashScreenAnimationStyle value : values()) {
32+
if (value.style == style) {
33+
return value;
34+
}
35+
}
36+
37+
return null;
38+
}
39+
40+
final int style;
41+
42+
SplashScreenAnimationStyle(int style) {
43+
this.style = style;
44+
}
45+
}
46+
947
// color constants used in relation with litho components
1048
private static final int[] WHITE_VALUES = {
1149
-1, // comments chip background
@@ -58,4 +96,22 @@ private static boolean anyEquals(int value, int... of) {
5896
public static boolean gradientLoadingScreenEnabled(boolean original) {
5997
return GRADIENT_LOADING_SCREEN_ENABLED;
6098
}
99+
100+
/**
101+
* Injection point.
102+
*/
103+
public static int getLoadingScreenType(int original) {
104+
SplashScreenAnimationStyle style = Settings.SPLASH_SCREEN_ANIMATION_STYLE.get();
105+
if (style == SplashScreenAnimationStyle.DEFAULT) {
106+
return original;
107+
}
108+
109+
final int replacement = style.style;
110+
if (original != replacement) {
111+
Logger.printDebug(() -> "Overriding splash screen style from: "
112+
+ styleFromOrdinal(original) + " to: " + style);
113+
}
114+
115+
return replacement;
116+
}
61117
}

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,12 @@
2121
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
2222
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
2323
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
24+
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
2425
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
2526
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
2627
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
2728
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE;
2829

29-
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
30-
import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider.SwipeOverlayStyle;
31-
3230
import android.graphics.Color;
3331

3432
import app.revanced.extension.shared.Logger;
@@ -40,12 +38,14 @@
4038
import app.revanced.extension.shared.settings.LongSetting;
4139
import app.revanced.extension.shared.settings.Setting;
4240
import app.revanced.extension.shared.settings.StringSetting;
41+
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
4342
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
4443
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
4544
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
4645
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime;
4746
import app.revanced.extension.youtube.patches.MiniplayerPatch;
4847
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
48+
import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider.SwipeOverlayStyle;
4949

5050
public class Settings extends BaseSettings {
5151
// Video
@@ -226,6 +226,8 @@ public class Settings extends BaseSettings {
226226
public static final EnumSetting<FormFactor> CHANGE_FORM_FACTOR = new EnumSetting<>("revanced_change_form_factor", FormFactor.DEFAULT, true, "revanced_change_form_factor_user_dialog_message");
227227
public static final BooleanSetting BYPASS_IMAGE_REGION_RESTRICTIONS = new BooleanSetting("revanced_bypass_image_region_restrictions", FALSE, true);
228228
public static final BooleanSetting GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_gradient_loading_screen", FALSE, true);
229+
public static final EnumSetting<SplashScreenAnimationStyle> SPLASH_SCREEN_ANIMATION_STYLE = new EnumSetting<>("splash_screen_animation_style", SplashScreenAnimationStyle.FPS_60_ONE_SECOND, true);
230+
229231
public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG = new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE,
230232
"revanced_remove_viewer_discretion_dialog_user_dialog_message");
231233
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");

patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/Fingerprints.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ internal val themeHelperLightColorFingerprint = fingerprint {
4444
}
4545
}
4646

47+
internal const val GRADIENT_LOADING_SCREEN_AB_CONSTANT = 45412406L
48+
4749
internal val useGradientLoadingScreenFingerprint = fingerprint {
4850
literal { GRADIENT_LOADING_SCREEN_AB_CONSTANT }
4951
}
52+
53+
internal const val SPLASH_SCREEN_STYLE_FEATURE_FLAG = 269032877L
54+
55+
internal val splashScreenStyleFingerprint = fingerprint {
56+
returns("V")
57+
parameters("Landroid/os/Bundle;")
58+
literal { SPLASH_SCREEN_STYLE_FEATURE_FLAG }
59+
custom { method, classDef ->
60+
method.name == "onCreate" && classDef.endsWith("/MainActivity;")
61+
}
62+
}

patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
1010
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
1111
import app.revanced.patches.shared.misc.settings.preference.BasePreference
1212
import app.revanced.patches.shared.misc.settings.preference.InputType
13+
import app.revanced.patches.shared.misc.settings.preference.ListPreference
1314
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
1415
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
1516
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
1617
import app.revanced.patches.shared.misc.settings.preference.TextPreference
1718
import app.revanced.patches.youtube.layout.seekbar.seekbarColorPatch
1819
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
1920
import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
21+
import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater
2022
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
2123
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
2224
import app.revanced.patches.youtube.misc.settings.settingsPatch
@@ -27,8 +29,6 @@ import org.w3c.dom.Element
2729
private const val EXTENSION_CLASS_DESCRIPTOR =
2830
"Lapp/revanced/extension/youtube/patches/theme/ThemePatch;"
2931

30-
internal const val GRADIENT_LOADING_SCREEN_AB_CONSTANT = 45412406L
31-
3232
val themePatch = bytecodePatch(
3333
name = "Theme",
3434
description = "Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).",
@@ -232,15 +232,32 @@ val themePatch = bytecodePatch(
232232
addResources("youtube", "layout.theme.themePatch")
233233

234234
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
235-
SwitchPreference("revanced_gradient_loading_screen"),
235+
SwitchPreference("revanced_gradient_loading_screen")
236236
)
237237

238+
if (is_19_47_or_greater) {
239+
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
240+
ListPreference(
241+
key = "splash_screen_animation_style",
242+
summaryKey = null
243+
)
244+
)
245+
}
246+
238247
useGradientLoadingScreenFingerprint.method.insertLiteralOverride(
239248
GRADIENT_LOADING_SCREEN_AB_CONSTANT,
240249
"$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z"
241250
)
242251

243-
mapOf(
252+
if (is_19_47_or_greater) {
253+
// Lottie splash screen exists in earlier versions, but it may not be always on.
254+
splashScreenStyleFingerprint.method.insertLiteralOverride(
255+
SPLASH_SCREEN_STYLE_FEATURE_FLAG,
256+
"$EXTENSION_CLASS_DESCRIPTOR->getLoadingScreenType(I)I"
257+
)
258+
}
259+
260+
arrayOf(
244261
themeHelperLightColorFingerprint to lightThemeBackgroundColor,
245262
themeHelperDarkColorFingerprint to darkThemeBackgroundColor,
246263
).forEach { (fingerprint, color) ->

patches/src/main/resources/addresources/values/arrays.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,21 @@
187187
<item>AUTOMOTIVE</item>
188188
</string-array>
189189
</patch>
190+
<patch id="layout.theme.themePatch">
191+
<!-- Since the 30fps looks bad, and the 2/5 second styles are not useful
192+
(YouTube closes the animation as soon as the feed is loaded),
193+
only the 60fps 1 second styles are exposed in the settings.
194+
Imported settings data can still be manually edited to force the other styles. -->
195+
<string-array name="splash_screen_animation_style_entries">
196+
<item>@string/splash_screen_animation_style_entry_1</item>
197+
<item>@string/splash_screen_animation_style_entry_2</item>
198+
</string-array>
199+
<string-array name="splash_screen_animation_style_entry_values">
200+
<item>FPS_60_ONE_SECOND</item>
201+
<item>FPS_60_BLACK_AND_WHITE</item>
202+
</string-array>
203+
</patch>
204+
190205
<patch id="layout.player.fullscreen.exitFullscreenPatch">
191206
<string-array name="revanced_exit_fullscreen_entries">
192207
<item>@string/revanced_exit_fullscreen_entry_1</item>

patches/src/main/resources/addresources/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,9 @@ Swipe to expand or close"</string>
13231323
<string name="revanced_gradient_loading_screen_title">Enable gradient loading screen</string>
13241324
<string name="revanced_gradient_loading_screen_summary_on">Loading screen will have a gradient background</string>
13251325
<string name="revanced_gradient_loading_screen_summary_off">Loading screen will have a solid background</string>
1326+
<string name="splash_screen_animation_style_title">Splash screen style</string>
1327+
<string name="splash_screen_animation_style_entry_1">Color</string>
1328+
<string name="splash_screen_animation_style_entry_2">Black and white</string>
13261329
<string name="revanced_seekbar_custom_color_title">Enable custom seekbar color</string>
13271330
<string name="revanced_seekbar_custom_color_summary_on">Custom seekbar color is shown</string>
13281331
<string name="revanced_seekbar_custom_color_summary_off">Original seekbar color is shown</string>

0 commit comments

Comments
 (0)