diff --git a/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCastButtonPatch.java b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCastButtonPatch.java new file mode 100644 index 000000000..d694891ab --- /dev/null +++ b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCastButtonPatch.java @@ -0,0 +1,24 @@ +package app.revanced.extension.music.patches; + +import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition; + +import android.view.View; +import app.revanced.extension.music.settings.Settings; + +@SuppressWarnings("unused") +public class HideCastButtonPatch { + + /** + * Injection point + */ + public static int hideCastButton(int original) { + return Settings.HIDE_CAST_BUTTON.get() ? View.GONE : original; + } + + /** + * Injection point + */ + public static void hideCastButton(View view) { + hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view); + } +} diff --git a/extensions/music/src/main/java/app/revanced/extension/music/patches/NavigationBarPatch.java b/extensions/music/src/main/java/app/revanced/extension/music/patches/NavigationBarPatch.java new file mode 100644 index 000000000..511e50304 --- /dev/null +++ b/extensions/music/src/main/java/app/revanced/extension/music/patches/NavigationBarPatch.java @@ -0,0 +1,74 @@ +package app.revanced.extension.music.patches; + +import static app.revanced.extension.shared.Utils.hideViewUnderCondition; + +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import app.revanced.extension.music.settings.Settings; + +@SuppressWarnings("unused") +public class NavigationBarPatch { + @NonNull + private static String lastYTNavigationEnumName = ""; + + public static void setLastAppNavigationEnum(@Nullable Enum ytNavigationEnumName) { + if (ytNavigationEnumName != null) { + lastYTNavigationEnumName = ytNavigationEnumName.name(); + } + } + + public static void hideNavigationLabel(TextView textview) { + hideViewUnderCondition(Settings.HIDE_NAVIGATION_BAR_LABEL.get(), textview); + } + + public static void hideNavigationButton(@NonNull View view) { + // Hide entire navigation bar. + if (Settings.HIDE_NAVIGATION_BAR.get() && view.getParent() != null) { + hideViewUnderCondition(true, (View) view.getParent()); + return; + } + + // Hide navigation buttons based on their type. + for (NavigationButton button : NavigationButton.values()) { + if (button.ytEnumNames.equals(lastYTNavigationEnumName)) { + hideViewUnderCondition(button.hidden, view); + break; + } + } + } + + private enum NavigationButton { + HOME( + "TAB_HOME", + Settings.HIDE_NAVIGATION_BAR_HOME_BUTTON.get() + ), + SAMPLES( + "TAB_SAMPLES", + Settings.HIDE_NAVIGATION_BAR_SAMPLES_BUTTON.get() + ), + EXPLORE( + "TAB_EXPLORE", + Settings.HIDE_NAVIGATION_BAR_EXPLORE_BUTTON.get() + ), + LIBRARY( + "LIBRARY_MUSIC", + Settings.HIDE_NAVIGATION_BAR_LIBRARY_BUTTON.get() + ), + UPGRADE( + "TAB_MUSIC_PREMIUM", + Settings.HIDE_NAVIGATION_BAR_UPGRADE_BUTTON.get() + ); + + private final String ytEnumNames; + private final boolean hidden; + + NavigationButton(@NonNull String ytEnumNames, boolean hidden) { + this.ytEnumNames = ytEnumNames; + this.hidden = hidden; + } + } +} diff --git a/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java index f793eef0f..b120672c5 100644 --- a/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -18,7 +18,15 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true); // General + public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_music_hide_cast_button", FALSE, false); public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR_HOME_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_home_button", FALSE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR_SAMPLES_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_samples_button", FALSE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR_EXPLORE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_explore_button", FALSE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR_LIBRARY_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_library_button", FALSE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_upgrade_button", TRUE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_music_hide_navigation_bar", FALSE, true); + public static final BooleanSetting HIDE_NAVIGATION_BAR_LABEL = new BooleanSetting("revanced_music_hide_navigation_bar_labels", FALSE, true); // Player public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true); diff --git a/patches/api/patches.api b/patches/api/patches.api index f54cb57e8..69db9f4de 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -372,10 +372,18 @@ public final class app/revanced/patches/music/interaction/permanentshuffle/Perma public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt { + public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/music/layout/compactheader/HideCategoryBarKt { public static final fun getHideCategoryBar ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/music/layout/navigationbar/NavigationBarPatchKt { + public static final fun getNavigationBarPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/music/layout/premium/HideGetPremiumPatchKt { public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/Fingerprints.kt new file mode 100644 index 000000000..718d49479 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/Fingerprints.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.music.layout.castbutton + +import com.android.tools.smali.dexlib2.AccessFlags +import app.revanced.patcher.fingerprint +import app.revanced.util.literal + +internal val mediaRouteButtonFingerprint = fingerprint { + accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) + returns("Z") + strings("MediaRouteButton") +} + +internal val playerOverlayChipFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + literal { playerOverlayChip } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt new file mode 100644 index 000000000..4e18e6305 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt @@ -0,0 +1,70 @@ +package app.revanced.patches.music.layout.castbutton + +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.music.misc.extension.sharedExtensionPatch +import app.revanced.patches.music.misc.settings.PreferenceScreen +import app.revanced.patches.music.misc.settings.settingsPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstLiteralInstructionOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction + +internal var playerOverlayChip = -1L + private set + +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCastButtonPatch;" + +@Suppress("unused") +val hideCastButton = bytecodePatch( + name = "Hide cast button", + description = "Adds an option to hide the cast button." +) { + dependsOn( + sharedExtensionPatch, + settingsPatch, + addResourcesPatch, + ) + + compatibleWith( + "com.google.android.apps.youtube.music"( + "7.29.52" + ) + ) + + execute { + addResources("music", "layout.castbutton.hideCastButton") + + PreferenceScreen.GENERAL.addPreferences( + SwitchPreference("revanced_music_hide_cast_button"), + ) + + mediaRouteButtonFingerprint.classDef.apply { + val setVisibilityMethod = methods.first { method -> method.name == "setVisibility" } + + setVisibilityMethod.addInstructions( + 0, + """ + invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(I)I + move-result p1 + """ + ) + } + + playerOverlayChipFingerprint.method.apply { + val resourceIndex = indexOfFirstLiteralInstructionOrThrow(playerOverlayChip) + val targetIndex = indexOfFirstInstructionOrThrow(resourceIndex, Opcode.MOVE_RESULT) + val targetRegister = getInstruction(targetIndex).registerA + + addInstruction( + targetIndex + 1, + "invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(Landroid/view/View;)V" + ) + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/Fingerprints.kt new file mode 100644 index 000000000..ab4fb3a8b --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/Fingerprints.kt @@ -0,0 +1,36 @@ +package app.revanced.patches.music.layout.navigationbar + +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.AccessFlags +import app.revanced.patcher.fingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import app.revanced.util.literal +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +internal val tabLayoutTextFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("L") + opcodes( + Opcode.IGET, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT + ) + strings("FEmusic_search") + literal { text1 } + custom { method, _ -> + indexOfGetVisibilityInstruction(method) >= 0 + } +} + +internal fun indexOfGetVisibilityInstruction(method: Method) = + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "getVisibility" + } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt new file mode 100644 index 000000000..d3af09f24 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt @@ -0,0 +1,110 @@ +package app.revanced.patches.music.layout.navigationbar + +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.music.misc.extension.sharedExtensionPatch +import app.revanced.patches.music.misc.settings.PreferenceScreen +import app.revanced.patches.music.misc.settings.settingsPatch +import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.resourceMappingPatch +import app.revanced.patches.shared.misc.mapping.resourceMappings +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstLiteralInstructionOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction + +internal var text1 = -1L + private set + +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/NavigationBarPatch;" + +@Suppress("unused") +val navigationBarPatch = bytecodePatch( + name = "Navigation bar", + description = "Adds options to hide navigation bar, labels and buttons." +) { + dependsOn( + resourceMappingPatch, + sharedExtensionPatch, + settingsPatch, + addResourcesPatch + ) + + compatibleWith( + "com.google.android.apps.youtube.music"( + "7.29.52" + ) + ) + + execute { + text1 = resourceMappings[ + "id", + "text1", + ] + + addResources("music", "layout.navigationbar.navigationBarPatch") + + PreferenceScreen.GENERAL.addPreferences( + PreferenceScreenPreference( + key = "revanced_music_navigation_bar_screen", + sorting = PreferenceScreenPreference.Sorting.UNSORTED, + preferences = setOf( + SwitchPreference("revanced_music_hide_navigation_bar_home_button"), + SwitchPreference("revanced_music_hide_navigation_bar_samples_button"), + SwitchPreference("revanced_music_hide_navigation_bar_explore_button"), + SwitchPreference("revanced_music_hide_navigation_bar_library_button"), + SwitchPreference("revanced_music_hide_navigation_bar_upgrade_button"), + + SwitchPreference("revanced_music_hide_navigation_bar"), + SwitchPreference("revanced_music_hide_navigation_bar_labels"), + ) + ) + ) + + tabLayoutTextFingerprint.method.apply { + /** + * Hide navigation labels. + */ + val constIndex = indexOfFirstLiteralInstructionOrThrow(text1) + val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST) + val targetParameter = getInstruction(targetIndex).reference + val targetRegister = getInstruction(targetIndex).registerA + + if (!targetParameter.toString().endsWith("Landroid/widget/TextView;")) + throw PatchException("Method signature parameter did not match: $targetParameter") + + addInstruction( + targetIndex + 1, + "invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationLabel(Landroid/widget/TextView;)V" + ) + + /** + * Set navigation enum and hide navigation buttons. + */ + val enumIndex = tabLayoutTextFingerprint.patternMatch!!.startIndex + 3 + val enumRegister = getInstruction(enumIndex).registerA + val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2 + + val pivotTabIndex = indexOfGetVisibilityInstruction(this) + val pivotTabRegister = getInstruction(pivotTabIndex).registerC + + addInstruction( + pivotTabIndex, + "invoke-static { v$pivotTabRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationButton(Landroid/view/View;)V" + ) + + addInstruction( + insertEnumIndex, + "invoke-static { v$enumRegister }, $EXTENSION_CLASS_DESCRIPTOR->setLastAppNavigationEnum(Ljava/lang/Enum;)V" + ) + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatch.kt index b54e4f2b6..f06eda341 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatch.kt @@ -21,9 +21,9 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;" +@Deprecated("This patch will be removed in the future.") @Suppress("unused") val hideUpgradeButton = bytecodePatch( - name = "Hide upgrade button", description = "Hides the upgrade tab from the pivot bar.", ) { dependsOn( diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 1d86f2421..86d617500 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1663,11 +1663,46 @@ Enabling this can unlock higher video qualities" Permanent repeat is enabled Permanent repeat is disabled + + Hide cast button + Cast button is hidden + Cast button is shown + Hide category bar Category bar is hidden Category bar is shown + + Navigation bar + Hide or change navigation bar buttons + + Hide Home button + Home button is hidden + Home button is shown + + Hide Samples button + Samples button is hidden + Samples button is shown + + Hide Explore button + Explore button is hidden + Explore button is shown + + Hide Library button + Library button is hidden + Library button is shown + + Hide Upgrade button + Upgrade button is hidden + Upgrade button is shown + Hide navigation bar + Navigation bar is hidden + Navigation bar is shown + Hide navigation button labels + Labels are hidden + Labels are shown + Hide \'Get Music Premium\' label Label is hidden