Skip to content

Commit

Permalink
feat(YouTube - Miniplayer): Add horizontal drag gesture (#3859)
Browse files Browse the repository at this point in the history
  • Loading branch information
LisoUseInAIKyrios authored Nov 5, 2024
1 parent 39b6c04 commit d36ede0
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,44 @@
public final class EnableDebuggingPatch {

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

public static boolean isFeatureFlagEnabled(long flag, boolean value) {
/**
* Injection point.
*/
public static boolean isBooleanFeatureFlagEnabled(boolean value, long flag) {
if (value && BaseSettings.DEBUG.get()) {
if (featureFlags.putIfAbsent(flag, true) == null) {
Logger.printDebug(() -> "feature is enabled: " + flag);
Logger.printDebug(() -> "boolean feature is enabled: " + flag);
}
}

return value;
}

/**
* Injection point.
*/
public static double isDoubleFeatureFlagEnabled(double value, long flag, double defaultValue) {
if (defaultValue != value && BaseSettings.DEBUG.get()) {
if (featureFlags.putIfAbsent(flag, true) == null) {
// Align the log outputs to make post processing easier.
Logger.printDebug(() -> " double feature is enabled: " + flag
+ " value: " + value + (defaultValue == 0 ? "" : " default: " + defaultValue));
}
}

return value;
}

/**
* Injection point.
*/
public static long isLongFeatureFlagEnabled(long value, long flag, long defaultValue) {
if (defaultValue != value && BaseSettings.DEBUG.get()) {
if (featureFlags.putIfAbsent(flag, true) == null) {
Logger.printDebug(() -> " long feature is enabled: " + flag
+ " value: " + value + (defaultValue == 0 ? "" : " default: " + defaultValue));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ public boolean isModern() {
private static final boolean MINIPLAYER_ROUNDED_CORNERS_ENABLED =
Settings.MINIPLAYER_ROUNDED_CORNERS.get();

private static final boolean MINIPLAYER_HORIZONTAL_DRAG_ENABLED =
DRAG_AND_DROP_ENABLED && Settings.MINIPLAYER_HORIZONTAL_DRAG.get();

/**
* Remove a broken and always present subtitle text that is only
* present with {@link MiniplayerType#MODERN_2}. Bug was fixed in 19.21.
Expand All @@ -131,6 +134,13 @@ public boolean isModern() {

private static final int OPACITY_LEVEL;

public static final class MiniplayerHorizontalDragAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
return Settings.MINIPLAYER_TYPE.get().isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
}
}

public static final class MiniplayerHideExpandCloseAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
Expand Down Expand Up @@ -248,21 +258,15 @@ public static int setMiniplayerDefaultSize(int original) {
return original;
}

/**
* Injection point.
*/
public static float setMovementBoundFactor(float original) {
// Not clear if customizing this is useful or not.
// So for now just log this and use the original value.
if (original != 1.0) Logger.printDebug(() -> "setMovementBoundFactor original: " + original);

return original;
}

/**
* Injection point.
*/
public static boolean setDropShadow(boolean original) {
public static boolean setHorizontalDrag(boolean original) {
if (CURRENT_TYPE.isModern()) {
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
}

return original;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static app.revanced.extension.shared.settings.Setting.*;
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideExpandCloseAvailability;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.*;
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
Expand Down Expand Up @@ -138,6 +139,7 @@ public class Settings extends BaseSettings {
private static final Availability MINIPLAYER_ANY_MODERN = MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3, MODERN_4);
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN);
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN);
public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerHorizontalDragAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", FALSE, true, new MiniplayerHideExpandCloseAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1));
Expand Down
19 changes: 0 additions & 19 deletions patches/api/patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -1133,17 +1133,6 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
public static final fun getHideTimestampPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/youtube/layout/miniplayer/FingerprintsKt {
public static final field ANIMATION_INTERPOLATION_FEATURE_KEY J
public static final field DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL J
public static final field DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL J
public static final field DROP_SHADOW_FEATURE_KEY J
public static final field INITIAL_SIZE_FEATURE_KEY_LITERAL J
public static final field MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL J
public static final field MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY J
public static final field ROUNDED_CORNERS_FEATURE_KEY J
}

public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatchKt {
public static final fun getFloatyBarButtonTopMargin ()J
public static final fun getMiniplayerMaxSize ()J
Expand Down Expand Up @@ -1188,10 +1177,6 @@ public final class app/revanced/patches/youtube/layout/searchbar/WideSearchbarPa
public static final fun getWideSearchbarPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/youtube/layout/seekbar/FingerprintsKt {
public static final field PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG J
}

public final class app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatchKt {
public static final fun getSeekbarColorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
Expand Down Expand Up @@ -1274,10 +1259,6 @@ public final class app/revanced/patches/youtube/misc/extension/SharedExtensionPa
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/youtube/misc/fix/cairo/FingerprintsKt {
public static final field CAIRO_CONFIG_LITERAL_VALUE J
}

public final class app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatchKt {
public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("SpellCheckingInspection")

package app.revanced.patches.youtube.layout.miniplayer

import app.revanced.patcher.fingerprint
Expand Down Expand Up @@ -33,16 +35,14 @@ internal val miniplayerModernCloseButtonFingerprint = fingerprint {
literal { modernMiniplayerClose }
}

const val MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL = 45622882L

internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
// In later targets this feature flag does nothing and is dead code.
const val MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY = 45630429L
const val DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL = 45628823L
const val DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL = 45628752L
const val INITIAL_SIZE_FEATURE_KEY_LITERAL = 45640023L
const val ANIMATION_INTERPOLATION_FEATURE_KEY = 45647018L
const val DROP_SHADOW_FEATURE_KEY = 45652223L
const val ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L

internal val miniplayerModernConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("SpellCheckingInspection")

package app.revanced.patches.youtube.layout.miniplayer

import app.revanced.patcher.Match
Expand Down Expand Up @@ -204,6 +206,10 @@ val miniplayerPatch = bytecodePatch(
preferences += SwitchPreference("revanced_miniplayer_drag_and_drop")
}

if (is_19_43_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_horizontal_drag")
}

if (is_19_36_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_rounded_corners")
}
Expand Down Expand Up @@ -291,7 +297,7 @@ val miniplayerPatch = bytecodePatch(
addInstructions(
targetIndex + 1,
"""
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(F)F
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(F)F
move-result v$register
""",
)
Expand All @@ -302,13 +308,13 @@ val miniplayerPatch = bytecodePatch(
* Adds an override to specify which modern miniplayer is used.
*/
fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
val targetInstruction = getInstruction<TwoRegisterInstruction>(iPutIndex)
val register = getInstruction<TwoRegisterInstruction>(iPutIndex).registerA

addInstructionsAtControlFlowLabel(
iPutIndex,
"""
invoke-static { v${targetInstruction.registerA} }, $EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
move-result v${targetInstruction.registerA}
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
move-result v$register
""",
)
}
Expand Down Expand Up @@ -378,32 +384,39 @@ val miniplayerPatch = bytecodePatch(

if (is_19_23_or_greater) {
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL,
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
"enableMiniplayerDragAndDrop",
)
}

if (is_19_43_or_greater) {
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"setHorizontalDrag",
)
}

if (is_19_25_or_greater) {
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY,
MINIPLAYER_MODERN_FEATURE_LEGACY_KEY,
"getModernMiniplayerOverride",
)

miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL,
MINIPLAYER_MODERN_FEATURE_KEY,
"getModernFeatureFlagsActiveOverride",
)

miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL,
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
"enableMiniplayerDoubleTapAction",
)
}

if (is_19_26_or_greater) {
miniplayerModernConstructorMatch.mutableMethod.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(
INITIAL_SIZE_FEATURE_KEY_LITERAL,
MINIPLAYER_INITIAL_SIZE_FEATURE_KEY,
)
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT)

Expand All @@ -418,7 +431,7 @@ val miniplayerPatch = bytecodePatch(
)
}

// Override a mininimum miniplayer size constant.
// Override a minimum size constant.
miniplayerMinimumSizeMatch.mutableMethod.apply {
val index = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_16 && (this as NarrowLiteralInstruction).narrowLiteral == 192
Expand All @@ -432,22 +445,9 @@ val miniplayerPatch = bytecodePatch(
}
}

if (is_19_32_or_greater) {
// Feature is not exposed in the settings, and currently only for debugging.
miniplayerModernConstructorMatch.insertLiteralValueFloatOverride(
ANIMATION_INTERPOLATION_FEATURE_KEY,
"setMovementBoundFactor",
)
}

if (is_19_36_or_greater) {
miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
DROP_SHADOW_FEATURE_KEY,
"setDropShadow",
)

miniplayerModernConstructorMatch.insertLiteralValueBooleanOverride(
ROUNDED_CORNERS_FEATURE_KEY,
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
"setRoundedCorners",
)
}
Expand Down Expand Up @@ -551,9 +551,9 @@ val miniplayerPatch = bytecodePatch(
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
""",
"""
)
},
}
)

// endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal val shortsSeekbarColorFingerprint = fingerprint {
literal { reelTimeBarPlayedColorId }
}

const val PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG = 45617850L
internal const val PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG = 45617850L

internal val playerSeekbarGradientConfigFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,62 @@ val enableDebuggingPatch = bytecodePatch(
),
)

// Hook the method that looks up if a feature flag is active or not.
experimentalFeatureFlagFingerprint.applyMatch(
// Hook the methods that look up if a feature flag is active.

experimentalBooleanFeatureFlagFingerprint.applyMatch(
context,
experimentalFeatureFlagParentMatch
).mutableMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)

// It appears that all usage of this method has a default of 'false',
// so there's no need to pass in the default.
addInstructions(
insertIndex,
"""
move-result v0
invoke-static { p1, p2, v0 }, $EXTENSION_CLASS_DESCRIPTOR->isFeatureFlagEnabled(JZ)Z
invoke-static { v0, p1, p2 }, $EXTENSION_CLASS_DESCRIPTOR->isBooleanFeatureFlagEnabled(ZJ)Z
move-result v0
return v0
"""
)
}

experimentalDoubleFeatureFlagFingerprint.applyMatch(
context,
experimentalFeatureFlagParentMatch
).mutableMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)

addInstructions(
insertIndex,
"""
move-result-wide v0 # Also clobbers v1 (p0) since result is wide.
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isDoubleFeatureFlagEnabled(DJD)D
move-result-wide v0
return-wide v0
"""
)
}

experimentalLongFeatureFlagFingerprint.applyMatch(
context,
experimentalFeatureFlagParentMatch
).mutableMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)

addInstructions(
insertIndex,
"""
move-result-wide v0
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isLongFeatureFlagEnabled(JJJ)J
move-result-wide v0
return-wide v0
"""
)
}

// There exists other experimental accessor methods for String, byte[], and wrappers for obfuscated classes,
// but currently none of those are hooked.
}
}
Loading

0 comments on commit d36ede0

Please sign in to comment.