Skip to content

Commit a569569

Browse files
LisoUseInAIKyriosoSumAtrIX
authored andcommitted
feat(YouTube - Miniplayer): Add horizontal drag gesture (#3859)
1 parent 577b187 commit a569569

File tree

11 files changed

+149
-74
lines changed

11 files changed

+149
-74
lines changed

extensions/shared/src/main/java/app/revanced/extension/youtube/patches/EnableDebuggingPatch.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,44 @@
1010
public final class EnableDebuggingPatch {
1111

1212
private static final ConcurrentMap<Long, Boolean> featureFlags
13-
= new ConcurrentHashMap<>(150, 0.75f, 1);
13+
= new ConcurrentHashMap<>(300, 0.75f, 1);
1414

15-
public static boolean isFeatureFlagEnabled(long flag, boolean value) {
15+
/**
16+
* Injection point.
17+
*/
18+
public static boolean isBooleanFeatureFlagEnabled(boolean value, long flag) {
1619
if (value && BaseSettings.DEBUG.get()) {
1720
if (featureFlags.putIfAbsent(flag, true) == null) {
18-
Logger.printDebug(() -> "feature is enabled: " + flag);
21+
Logger.printDebug(() -> "boolean feature is enabled: " + flag);
22+
}
23+
}
24+
25+
return value;
26+
}
27+
28+
/**
29+
* Injection point.
30+
*/
31+
public static double isDoubleFeatureFlagEnabled(double value, long flag, double defaultValue) {
32+
if (defaultValue != value && BaseSettings.DEBUG.get()) {
33+
if (featureFlags.putIfAbsent(flag, true) == null) {
34+
// Align the log outputs to make post processing easier.
35+
Logger.printDebug(() -> " double feature is enabled: " + flag
36+
+ " value: " + value + (defaultValue == 0 ? "" : " default: " + defaultValue));
37+
}
38+
}
39+
40+
return value;
41+
}
42+
43+
/**
44+
* Injection point.
45+
*/
46+
public static long isLongFeatureFlagEnabled(long value, long flag, long defaultValue) {
47+
if (defaultValue != value && BaseSettings.DEBUG.get()) {
48+
if (featureFlags.putIfAbsent(flag, true) == null) {
49+
Logger.printDebug(() -> " long feature is enabled: " + flag
50+
+ " value: " + value + (defaultValue == 0 ? "" : " default: " + defaultValue));
1951
}
2052
}
2153

extensions/shared/src/main/java/app/revanced/extension/youtube/patches/MiniplayerPatch.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ public boolean isModern() {
122122
private static final boolean MINIPLAYER_ROUNDED_CORNERS_ENABLED =
123123
Settings.MINIPLAYER_ROUNDED_CORNERS.get();
124124

125+
private static final boolean MINIPLAYER_HORIZONTAL_DRAG_ENABLED =
126+
DRAG_AND_DROP_ENABLED && Settings.MINIPLAYER_HORIZONTAL_DRAG.get();
127+
125128
/**
126129
* Remove a broken and always present subtitle text that is only
127130
* present with {@link MiniplayerType#MODERN_2}. Bug was fixed in 19.21.
@@ -131,6 +134,13 @@ public boolean isModern() {
131134

132135
private static final int OPACITY_LEVEL;
133136

137+
public static final class MiniplayerHorizontalDragAvailability implements Setting.Availability {
138+
@Override
139+
public boolean isAvailable() {
140+
return Settings.MINIPLAYER_TYPE.get().isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
141+
}
142+
}
143+
134144
public static final class MiniplayerHideExpandCloseAvailability implements Setting.Availability {
135145
@Override
136146
public boolean isAvailable() {
@@ -248,21 +258,15 @@ public static int setMiniplayerDefaultSize(int original) {
248258
return original;
249259
}
250260

251-
/**
252-
* Injection point.
253-
*/
254-
public static float setMovementBoundFactor(float original) {
255-
// Not clear if customizing this is useful or not.
256-
// So for now just log this and use the original value.
257-
if (original != 1.0) Logger.printDebug(() -> "setMovementBoundFactor original: " + original);
258-
259-
return original;
260-
}
261261

262262
/**
263263
* Injection point.
264264
*/
265-
public static boolean setDropShadow(boolean original) {
265+
public static boolean setHorizontalDrag(boolean original) {
266+
if (CURRENT_TYPE.isModern()) {
267+
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
268+
}
269+
266270
return original;
267271
}
268272

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static app.revanced.extension.shared.settings.Setting.*;
66
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
77
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideExpandCloseAvailability;
8+
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
89
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
910
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.*;
1011
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
@@ -138,6 +139,7 @@ public class Settings extends BaseSettings {
138139
private static final Availability MINIPLAYER_ANY_MODERN = MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3, MODERN_4);
139140
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN);
140141
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN);
142+
public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerHorizontalDragAvailability());
141143
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", FALSE, true, new MiniplayerHideExpandCloseAvailability());
142144
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
143145
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1));

patches/api/patches.api

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,17 +1133,6 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
11331133
public static final fun getHideTimestampPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
11341134
}
11351135

1136-
public final class app/revanced/patches/youtube/layout/miniplayer/FingerprintsKt {
1137-
public static final field ANIMATION_INTERPOLATION_FEATURE_KEY J
1138-
public static final field DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL J
1139-
public static final field DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL J
1140-
public static final field DROP_SHADOW_FEATURE_KEY J
1141-
public static final field INITIAL_SIZE_FEATURE_KEY_LITERAL J
1142-
public static final field MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL J
1143-
public static final field MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY J
1144-
public static final field ROUNDED_CORNERS_FEATURE_KEY J
1145-
}
1146-
11471136
public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatchKt {
11481137
public static final fun getFloatyBarButtonTopMargin ()J
11491138
public static final fun getMiniplayerMaxSize ()J
@@ -1188,10 +1177,6 @@ public final class app/revanced/patches/youtube/layout/searchbar/WideSearchbarPa
11881177
public static final fun getWideSearchbarPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
11891178
}
11901179

1191-
public final class app/revanced/patches/youtube/layout/seekbar/FingerprintsKt {
1192-
public static final field PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG J
1193-
}
1194-
11951180
public final class app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatchKt {
11961181
public static final fun getSeekbarColorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
11971182
}
@@ -1274,10 +1259,6 @@ public final class app/revanced/patches/youtube/misc/extension/SharedExtensionPa
12741259
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
12751260
}
12761261

1277-
public final class app/revanced/patches/youtube/misc/fix/cairo/FingerprintsKt {
1278-
public static final field CAIRO_CONFIG_LITERAL_VALUE J
1279-
}
1280-
12811262
public final class app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatchKt {
12821263
public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
12831264
}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@file:Suppress("SpellCheckingInspection")
2+
13
package app.revanced.patches.youtube.layout.miniplayer
24

35
import app.revanced.patcher.fingerprint
@@ -33,16 +35,14 @@ internal val miniplayerModernCloseButtonFingerprint = fingerprint {
3335
literal { modernMiniplayerClose }
3436
}
3537

36-
const val MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL = 45622882L
37-
38+
internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
3839
// In later targets this feature flag does nothing and is dead code.
39-
const val MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY = 45630429L
40-
const val DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL = 45628823L
41-
const val DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL = 45628752L
42-
const val INITIAL_SIZE_FEATURE_KEY_LITERAL = 45640023L
43-
const val ANIMATION_INTERPOLATION_FEATURE_KEY = 45647018L
44-
const val DROP_SHADOW_FEATURE_KEY = 45652223L
45-
const val ROUNDED_CORNERS_FEATURE_KEY = 45652224L
40+
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
41+
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
42+
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
43+
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
44+
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
45+
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
4646

4747
internal val miniplayerModernConstructorFingerprint = fingerprint {
4848
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)

patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@file:Suppress("SpellCheckingInspection")
2+
13
package app.revanced.patches.youtube.layout.miniplayer
24

35
import app.revanced.patcher.Match
@@ -204,6 +206,10 @@ val miniplayerPatch = bytecodePatch(
204206
preferences += SwitchPreference("revanced_miniplayer_drag_and_drop")
205207
}
206208

209+
if (is_19_43_or_greater) {
210+
preferences += SwitchPreference("revanced_miniplayer_horizontal_drag")
211+
}
212+
207213
if (is_19_36_or_greater) {
208214
preferences += SwitchPreference("revanced_miniplayer_rounded_corners")
209215
}
@@ -291,7 +297,7 @@ val miniplayerPatch = bytecodePatch(
291297
addInstructions(
292298
targetIndex + 1,
293299
"""
294-
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(F)F
300+
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(F)F
295301
move-result v$register
296302
""",
297303
)
@@ -302,13 +308,13 @@ val miniplayerPatch = bytecodePatch(
302308
* Adds an override to specify which modern miniplayer is used.
303309
*/
304310
fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
305-
val targetInstruction = getInstruction<TwoRegisterInstruction>(iPutIndex)
311+
val register = getInstruction<TwoRegisterInstruction>(iPutIndex).registerA
306312

307313
addInstructionsAtControlFlowLabel(
308314
iPutIndex,
309315
"""
310-
invoke-static { v${targetInstruction.registerA} }, $EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
311-
move-result v${targetInstruction.registerA}
316+
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
317+
move-result v$register
312318
""",
313319
)
314320
}
@@ -378,32 +384,39 @@ val miniplayerPatch = bytecodePatch(
378384

379385
if (is_19_23_or_greater) {
380386
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
381-
DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL,
387+
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
382388
"enableMiniplayerDragAndDrop",
383389
)
384390
}
385391

392+
if (is_19_43_or_greater) {
393+
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
394+
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
395+
"setHorizontalDrag",
396+
)
397+
}
398+
386399
if (is_19_25_or_greater) {
387400
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
388-
MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY,
401+
MINIPLAYER_MODERN_FEATURE_LEGACY_KEY,
389402
"getModernMiniplayerOverride",
390403
)
391404

392405
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
393-
MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL,
406+
MINIPLAYER_MODERN_FEATURE_KEY,
394407
"getModernFeatureFlagsActiveOverride",
395408
)
396409

397410
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
398-
DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL,
411+
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
399412
"enableMiniplayerDoubleTapAction",
400413
)
401414
}
402415

403416
if (is_19_26_or_greater) {
404417
miniplayerModernConstructorMatch.mutableMethod.apply {
405418
val literalIndex = indexOfFirstLiteralInstructionOrThrow(
406-
INITIAL_SIZE_FEATURE_KEY_LITERAL,
419+
MINIPLAYER_INITIAL_SIZE_FEATURE_KEY,
407420
)
408421
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT)
409422

@@ -418,7 +431,7 @@ val miniplayerPatch = bytecodePatch(
418431
)
419432
}
420433

421-
// Override a mininimum miniplayer size constant.
434+
// Override a minimum size constant.
422435
miniplayerMinimumSizeMatch.mutableMethod.apply {
423436
val index = indexOfFirstInstructionOrThrow {
424437
opcode == Opcode.CONST_16 && (this as NarrowLiteralInstruction).narrowLiteral == 192
@@ -432,22 +445,9 @@ val miniplayerPatch = bytecodePatch(
432445
}
433446
}
434447

435-
if (is_19_32_or_greater) {
436-
// Feature is not exposed in the settings, and currently only for debugging.
437-
miniplayerModernConstructorMatch.insertLiteralValueFloatOverride(
438-
ANIMATION_INTERPOLATION_FEATURE_KEY,
439-
"setMovementBoundFactor",
440-
)
441-
}
442-
443448
if (is_19_36_or_greater) {
444449
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
445-
DROP_SHADOW_FEATURE_KEY,
446-
"setDropShadow",
447-
)
448-
449-
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
450-
ROUNDED_CORNERS_FEATURE_KEY,
450+
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
451451
"setRoundedCorners",
452452
)
453453
}
@@ -551,9 +551,9 @@ val miniplayerPatch = bytecodePatch(
551551
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
552552
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
553553
return-void
554-
""",
554+
"""
555555
)
556-
},
556+
}
557557
)
558558

559559
// endregion

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ internal val shortsSeekbarColorFingerprint = fingerprint {
3434
literal { reelTimeBarPlayedColorId }
3535
}
3636

37-
const val PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG = 45617850L
37+
internal const val PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG = 45617850L
3838

3939
internal val playerSeekbarGradientConfigFingerprint = fingerprint {
4040
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)

patches/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/EnableDebuggingPatch.kt

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,62 @@ val enableDebuggingPatch = bytecodePatch(
5757
),
5858
)
5959

60-
// Hook the method that looks up if a feature flag is active or not.
61-
experimentalFeatureFlagFingerprint.applyMatch(
60+
// Hook the methods that look up if a feature flag is active.
61+
62+
experimentalBooleanFeatureFlagFingerprint.applyMatch(
6263
context,
6364
experimentalFeatureFlagParentMatch
6465
).mutableMethod.apply {
6566
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)
6667

68+
// It appears that all usage of this method has a default of 'false',
69+
// so there's no need to pass in the default.
6770
addInstructions(
6871
insertIndex,
6972
"""
7073
move-result v0
71-
invoke-static { p1, p2, v0 }, $EXTENSION_CLASS_DESCRIPTOR->isFeatureFlagEnabled(JZ)Z
74+
invoke-static { v0, p1, p2 }, $EXTENSION_CLASS_DESCRIPTOR->isBooleanFeatureFlagEnabled(ZJ)Z
7275
move-result v0
7376
return v0
7477
"""
7578
)
7679
}
80+
81+
experimentalDoubleFeatureFlagFingerprint.applyMatch(
82+
context,
83+
experimentalFeatureFlagParentMatch
84+
).mutableMethod.apply {
85+
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
86+
87+
addInstructions(
88+
insertIndex,
89+
"""
90+
move-result-wide v0 # Also clobbers v1 (p0) since result is wide.
91+
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isDoubleFeatureFlagEnabled(DJD)D
92+
move-result-wide v0
93+
return-wide v0
94+
"""
95+
)
96+
}
97+
98+
experimentalLongFeatureFlagFingerprint.applyMatch(
99+
context,
100+
experimentalFeatureFlagParentMatch
101+
).mutableMethod.apply {
102+
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
103+
104+
addInstructions(
105+
insertIndex,
106+
"""
107+
move-result-wide v0
108+
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isLongFeatureFlagEnabled(JJJ)J
109+
move-result-wide v0
110+
return-wide v0
111+
"""
112+
)
113+
}
114+
115+
// There exists other experimental accessor methods for String, byte[], and wrappers for obfuscated classes,
116+
// but currently none of those are hooked.
77117
}
78118
}

0 commit comments

Comments
 (0)