1
mirror of https://github.com/revanced/revanced-patches synced 2024-11-19 03:57:27 +01:00

feat(YouTube - Miniplayer): Add horizontal drag gesture (#3859)

This commit is contained in:
LisoUseInAIKyrios 2024-11-04 22:17:04 -04:00 committed by oSumAtrIX
parent e377b1e6ad
commit e32b19e170
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
11 changed files with 149 additions and 74 deletions

View File

@ -10,12 +10,44 @@ import app.revanced.extension.shared.settings.BaseSettings;
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));
}
}

View File

@ -122,6 +122,9 @@ public final class MiniplayerPatch {
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.
@ -131,6 +134,13 @@ public final class MiniplayerPatch {
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() {
@ -248,21 +258,15 @@ public final class MiniplayerPatch {
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;
}

View File

@ -5,6 +5,7 @@ import static java.lang.Boolean.TRUE;
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;
@ -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));

View File

@ -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
@ -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;
}
@ -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;
}

View File

@ -1,3 +1,5 @@
@file:Suppress("SpellCheckingInspection")
package app.revanced.patches.youtube.layout.miniplayer
import app.revanced.patcher.fingerprint
@ -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)

View File

@ -1,3 +1,5 @@
@file:Suppress("SpellCheckingInspection")
package app.revanced.patches.youtube.layout.miniplayer
import app.revanced.patcher.Match
@ -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")
}
@ -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
""",
)
@ -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
""",
)
}
@ -378,24 +384,31 @@ 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",
)
}
@ -403,7 +416,7 @@ val miniplayerPatch = bytecodePatch(
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)
@ -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
@ -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",
)
}
@ -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

View File

@ -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)

View File

@ -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.
}
}

View File

@ -10,8 +10,21 @@ internal val experimentalFeatureFlagParentFingerprint = fingerprint {
strings("Unable to parse proto typed experiment flag: ")
}
internal val experimentalFeatureFlagFingerprint = fingerprint {
internal val experimentalBooleanFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
parameters("J", "Z")
}
internal val experimentalDoubleFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("D")
parameters("J", "D")
}
internal val experimentalLongFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("J")
parameters("J", "J")
}

View File

@ -10,7 +10,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
* When this value is true, Cairo Fragment is used.
* In this case, some of the patches may be broken, so set this value to FALSE.
*/
const val CAIRO_CONFIG_LITERAL_VALUE = 45532100L
internal const val CAIRO_CONFIG_LITERAL_VALUE = 45532100L
internal val cairoFragmentConfigFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)

View File

@ -1035,6 +1035,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_miniplayer_drag_and_drop_title">Enable drag and drop</string>
<string name="revanced_miniplayer_drag_and_drop_summary_on">Drag and drop is enabled\n\nMiniplayer can be dragged to any corner of the screen</string>
<string name="revanced_miniplayer_drag_and_drop_summary_off">Drag and drop is disabled</string>
<string name="revanced_miniplayer_horizontal_drag_title">Enable horizontal drag gesture</string>
<string name="revanced_miniplayer_horizontal_drag_summary_on">Horizontal drag gesture enabled\n\nMiniplayer can be dragged off screen to the left or right</string>
<string name="revanced_miniplayer_horizontal_drag_summary_off">Horizontal drag gesture disabled</string>
<string name="revanced_miniplayer_hide_expand_close_title">Hide close button</string>
<string name="revanced_miniplayer_hide_expand_close_summary_on">Close button is hidden</string>
<string name="revanced_miniplayer_hide_expand_close_summary_off">Close button is shown</string>