feat(YouTube/Shorts components): add Double-tap animation settings

This commit is contained in:
inotia00 2024-06-27 23:47:32 +09:00
parent df97e5340a
commit 17dc2fdde6
16 changed files with 194 additions and 68 deletions

View File

@ -1,33 +0,0 @@
package app.revanced.patches.youtube.layout.animated
import app.revanced.patcher.data.ResourceContext
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.patch.BaseResourcePatch
@Suppress("unused")
object AnimatedButtonBackgroundPatch : BaseResourcePatch(
name = "Hide animated button background",
description = "Removes, at compile time, the background of the animated pause and play buttons in the Shorts player.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE,
use = false
) {
override fun execute(context: ResourceContext) {
/**
* Copy json
*/
context.copyResources(
"youtube/shorts/animated",
ResourceGroup(
"raw",
"pause_tap_feedback.json",
"play_tap_feedback.json"
)
)
SettingsPatch.updatePatchStatus(this)
}
}

View File

@ -1,33 +0,0 @@
package app.revanced.patches.youtube.layout.animated
import app.revanced.patcher.data.ResourceContext
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.patch.BaseResourcePatch
@Suppress("unused")
object AnimatedLikePatch : BaseResourcePatch(
name = "Hide double tap to like animations",
description = "Removes, at compile time, the like animations that appear when double-tapping in the Shorts player.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE,
use = false
) {
override fun execute(context: ResourceContext) {
/**
* Copy json
*/
context.copyResources(
"youtube/shorts/animated",
ResourceGroup(
"raw",
"like_tap_feedback.json"
)
)
SettingsPatch.updatePatchStatus(this)
}
}

View File

@ -0,0 +1,77 @@
package app.revanced.patches.youtube.shorts.components
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.youtube.shorts.components.fingerprints.ReelFeedbackFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.SHORTS_PATH
import app.revanced.patches.youtube.utils.lottie.LottieAnimationViewHookPatch
import app.revanced.patches.youtube.utils.lottie.fingerprints.SetAnimationFingerprint.LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelFeedbackLike
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelFeedbackPause
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelFeedbackPlay
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
@Patch(dependencies = [LottieAnimationViewHookPatch::class])
object ShortsAnimationPatch : BytecodePatch(
setOf(ReelFeedbackFingerprint)
) {
private const val INTEGRATION_CLASS_DESCRIPTOR =
"$SHORTS_PATH/AnimationFeedbackPatch;"
override fun execute(context: BytecodeContext) {
ReelFeedbackFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
mapOf(
ReelFeedbackLike to "setShortsLikeFeedback",
ReelFeedbackPause to "setShortsPauseFeedback",
ReelFeedbackPlay to "setShortsPlayFeedback",
).forEach { (literal, methodName) ->
val literalIndex = getWideLiteralInstructionIndex(literal)
val viewIndex = indexOfFirstInstructionOrThrow(literalIndex) {
opcode == Opcode.CHECK_CAST
&& (this as? ReferenceInstruction)?.reference?.toString() == LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR
}
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
val methodCall = "invoke-static {v$viewRegister}, " +
INTEGRATION_CLASS_DESCRIPTOR +
"->" +
methodName +
"($LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR)V"
addInstruction(
viewIndex + 1,
methodCall
)
}
}
}
/**
* Copy json
*/
contexts.copyResources(
"youtube/shorts/feedback",
ResourceGroup(
"raw",
"like_tap_feedback_cairo.json",
"like_tap_feedback_heart.json",
"like_tap_feedback_heart_tint.json",
"like_tap_feedback_hidden.json",
"pause_tap_feedback_hidden.json",
"play_tap_feedback_hidden.json"
)
)
}
}

View File

@ -57,6 +57,7 @@ object ShortsComponentPatch : BaseBytecodePatch(
PlayerTypeHookPatch::class,
SettingsPatch::class,
SharedResourceIdPatch::class,
ShortsAnimationPatch::class,
ShortsNavigationBarPatch::class,
ShortsToolBarPatch::class,
VideoInformationPatch::class

View File

@ -0,0 +1,16 @@
package app.revanced.patches.youtube.shorts.components.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelFeedbackLike
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelFeedbackPause
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelFeedbackPlay
import app.revanced.util.containsWideLiteralInstructionIndex
internal object ReelFeedbackFingerprint : MethodFingerprint(
returnType = "V",
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(ReelFeedbackLike)
&& methodDef.containsWideLiteralInstructionIndex(ReelFeedbackPause)
&& methodDef.containsWideLiteralInstructionIndex(ReelFeedbackPlay)
},
)

View File

@ -0,0 +1,40 @@
package app.revanced.patches.youtube.utils.lottie
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
import app.revanced.patches.youtube.utils.lottie.fingerprints.SetAnimationFingerprint
import app.revanced.patches.youtube.utils.lottie.fingerprints.SetAnimationFingerprint.LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR
import app.revanced.util.resultOrThrow
@Patch(
description = "Hook YouTube to use LottieAnimationView.setAnimation in the integration.",
)
object LottieAnimationViewHookPatch : BytecodePatch(
setOf(SetAnimationFingerprint)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$UTILS_PATH/LottieAnimationViewPatch;"
override fun execute(context: BytecodeContext) {
val setAnimationMethodName = SetAnimationFingerprint.resultOrThrow().mutableMethod.name
val setAnimationCall = "invoke-virtual {p0, p1}, " +
LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR +
"->" +
setAnimationMethodName +
"(I)V"
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)
?.mutableClass
?.methods
?.first { method -> method.name == "setAnimation" }
?.addInstruction(
0,
setAnimationCall
)?: throw PatchException("Could not find setAnimation method")
}
}

View File

@ -0,0 +1,24 @@
package app.revanced.patches.youtube.utils.lottie.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.lottie.fingerprints.SetAnimationFingerprint.LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object SetAnimationFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("I"),
opcodes = listOf(
Opcode.IF_EQZ,
Opcode.NEW_INSTANCE,
Opcode.NEW_INSTANCE,
),
customFingerprint = { methodDef, _ ->
methodDef.definingClass == LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR
}
) {
const val LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR =
"Lcom/airbnb/lottie/LottieAnimationView;"
}

View File

@ -138,6 +138,22 @@
<item>PHONE</item>
<item>TABLET</item>
</string-array>
<string-array name="revanced_shorts_double_tap_to_like_animation_entries">
<item>@string/revanced_shorts_double_tap_to_like_animation_entry_1</item>
<item>@string/revanced_shorts_double_tap_to_like_animation_entry_2</item>
<item>@string/revanced_shorts_double_tap_to_like_animation_entry_3</item>
<item>@string/revanced_shorts_double_tap_to_like_animation_entry_4</item>
<item>@string/revanced_shorts_double_tap_to_like_animation_entry_5</item>
<item>@string/revanced_shorts_double_tap_to_like_animation_entry_6</item>
</string-array>
<string-array name="revanced_shorts_double_tap_to_like_animation_entry_values">
<item>ORIGINAL</item>
<item>THUMBS_UP</item>
<item>THUMBS_UP_CAIRO</item>
<item>HEART</item>
<item>HEART_TINT</item>
<item>HIDDEN</item>
</string-array>
<string-array name="revanced_spoof_client_general_options_entries">
<item>@string/revanced_spoof_client_options_entry_ios</item>
<item>@string/revanced_spoof_client_options_entry_android_testsuite</item>

View File

@ -1090,6 +1090,19 @@ Side effect: Official headers in search results will be hidden."</string>
<string name="revanced_hide_shorts_sound_button_summary_on">Sound button is hidden.</string>
<string name="revanced_hide_shorts_sound_button_summary_off">Sound button is shown.</string>
<!-- PreferenceScreen: Shorts, PreferenceCategory: Shorts, PreferenceScreen: Shorts player, PreferenceCategory: Animation / Feedback -->
<string name="revanced_preference_category_animation_feedback">Animation / Feedback</string>
<string name="revanced_hide_shorts_play_pause_button_background_title">Hide Play &amp; Pause button background</string>
<string name="revanced_hide_shorts_play_pause_button_background_summary_on">Button background is hidden.</string>
<string name="revanced_hide_shorts_play_pause_button_background_summary_off">Button background is shown.</string>
<string name="revanced_shorts_double_tap_to_like_animation_title">Double-tap animation</string>
<string name="revanced_shorts_double_tap_to_like_animation_entry_1">Original</string>
<string name="revanced_shorts_double_tap_to_like_animation_entry_2">Thumbs up</string>
<string name="revanced_shorts_double_tap_to_like_animation_entry_3">Thumbs up (Cairo)</string>
<string name="revanced_shorts_double_tap_to_like_animation_entry_4">Heart</string>
<string name="revanced_shorts_double_tap_to_like_animation_entry_5">Heart (Tint)</string>
<string name="revanced_shorts_double_tap_to_like_animation_entry_6">Hidden</string>
<!-- PreferenceScreen: Shorts, PreferenceCategory: Shorts, PreferenceScreen: Shorts player, PreferenceCategory: Experimental Flags -->
<string name="revanced_hide_shorts_toolbar_title">Hide toolbar</string>
<string name="revanced_hide_shorts_toolbar_summary_on">Toolbar is hidden.</string>

View File

@ -478,6 +478,10 @@
<SwitchPreference android:title="@string/revanced_hide_shorts_share_button_title" android:key="revanced_hide_shorts_share_button" android:summaryOn="@string/revanced_hide_shorts_share_button_summary_on" android:summaryOff="@string/revanced_hide_shorts_share_button_summary_off" />
<SwitchPreference android:title="@string/revanced_hide_shorts_sound_button_title" android:key="revanced_hide_shorts_sound_button" android:summaryOn="@string/revanced_hide_shorts_sound_button_summary_on" android:summaryOff="@string/revanced_hide_shorts_sound_button_summary_off" />
<PreferenceCategory android:title="@string/revanced_preference_category_animation_feedback" android:layout="@layout/revanced_settings_preferences_category"/>
<SwitchPreference android:title="@string/revanced_hide_shorts_play_pause_button_background_title" android:key="revanced_hide_shorts_play_pause_button_background" android:summaryOn="@string/revanced_hide_shorts_play_pause_button_background_summary_on" android:summaryOff="@string/revanced_hide_shorts_play_pause_button_background_summary_off" />
<ListPreference android:entries="@array/revanced_shorts_double_tap_to_like_animation_entries" android:title="@string/revanced_shorts_double_tap_to_like_animation_title" android:key="revanced_shorts_double_tap_to_like_animation" android:entryValues="@array/revanced_shorts_double_tap_to_like_animation_entry_values" />
<PreferenceCategory android:title="@string/revanced_preference_category_experimental_flag" android:layout="@layout/revanced_settings_preferences_category"/>
<SwitchPreference android:title="@string/revanced_hide_shorts_toolbar_title" android:key="revanced_hide_shorts_toolbar" android:summaryOn="@string/revanced_hide_shorts_toolbar_summary_on" android:summaryOff="@string/revanced_hide_shorts_toolbar_summary_off" />
<SwitchPreference android:title="@string/revanced_hide_shorts_navigation_bar_title" android:key="revanced_hide_shorts_navigation_bar" android:summaryOn="@string/revanced_hide_shorts_navigation_bar_summary_on" android:summaryOff="@string/revanced_hide_shorts_navigation_bar_summary_off" />
@ -709,8 +713,6 @@
<Preference android:title="Custom double tap length" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Custom Shorts action buttons" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="GmsCore support" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Hide animated button background" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Hide double tap to like animations" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Hide Shorts dimming" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Icon" android:summary="@string/revanced_icon_default" android:selectable="false"/>
<Preference android:title="Label" android:summary="@string/revanced_label_default" android:selectable="false"/>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long