fix(YouTube - Wide search bar): Do not force phone layout for tablet devices (#4827)

This commit is contained in:
LisoUseInAIKyrios 2025-04-19 18:33:12 +02:00 committed by GitHub
parent 3e64a4c18f
commit 0cb38f9f36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 137 additions and 56 deletions

View File

@ -1,11 +1,48 @@
package app.revanced.extension.youtube.patches;
import android.content.res.Resources;
import android.util.TypedValue;
import android.view.View;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public final class WideSearchbarPatch {
private static final Boolean WIDE_SEARCHBAR_ENABLED = Settings.WIDE_SEARCHBAR.get();
/**
* Injection point.
*/
public static boolean enableWideSearchbar(boolean original) {
return Settings.WIDE_SEARCHBAR.get() || original;
return WIDE_SEARCHBAR_ENABLED || original;
}
/**
* Injection point.
*/
public static void setActionBar(View view) {
try {
if (!WIDE_SEARCHBAR_ENABLED) return;
View searchBarView = Utils.getChildViewByResourceName(view, "search_bar");
final int paddingLeft = searchBarView.getPaddingLeft();
final int paddingRight = searchBarView.getPaddingRight();
final int paddingTop = searchBarView.getPaddingTop();
final int paddingBottom = searchBarView.getPaddingBottom();
final int paddingStart = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
8, Resources.getSystem().getDisplayMetrics());
if (Utils.isRightToLeftTextLayout()) {
searchBarView.setPadding(paddingLeft, paddingTop, paddingStart, paddingBottom);
} else {
searchBarView.setPadding(paddingStart, paddingTop, paddingRight, paddingBottom);
}
} catch (Exception ex) {
Logger.printException(() -> "setActionBar failure", ex);
}
}
}

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.hide.general
import app.revanced.patcher.fingerprint
import app.revanced.patches.youtube.layout.searchbar.wideSearchbarLayoutFingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@ -67,6 +68,9 @@ internal val showWatermarkFingerprint = fingerprint {
parameters("L", "L")
}
/**
* Matches same method as [wideSearchbarLayoutFingerprint].
*/
internal val yoodlesImageViewFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/view/View;")

View File

@ -44,14 +44,12 @@ var crowdfundingBoxId = -1L
private set
var youTubeLogo = -1L
private set
var filterBarHeightId = -1L
private set
var relatedChipCloudMarginId = -1L
private set
var barContainerHeightId = -1L
private set
var fabButtonId = -1L
private set

View File

@ -1,31 +1,27 @@
package app.revanced.patches.youtube.layout.searchbar
import app.revanced.patcher.fingerprint
import app.revanced.patches.youtube.layout.hide.general.yoodlesImageViewFingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val createSearchSuggestionsFingerprint = fingerprint {
opcodes(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.CONST_4,
)
strings("ss_rds")
}
internal val setWordmarkHeaderFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("Landroid/widget/ImageView;")
opcodes(
Opcode.IGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
Opcode.IGET_BOOLEAN,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.CONST,
null, // invoke-static or invoke-virtual.
)
custom { methodDef, _ ->
methodDef.containsLiteralInstruction(ytWordmarkHeaderId) &&
methodDef.containsLiteralInstruction(ytPremiumWordmarkHeaderId)
}
}
/**
* Matches the same method as [yoodlesImageViewFingerprint].
*/
internal val wideSearchbarLayoutFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/view/View;")
parameters("L", "L")
literal { actionBarRingoId }
}

View File

@ -1,30 +1,68 @@
package app.revanced.patches.youtube.layout.searchbar
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
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.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
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
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/WideSearchbarPatch;"
internal var ytWordmarkHeaderId = -1L
private set
internal var ytPremiumWordmarkHeaderId = -1L
private set
internal var actionBarRingoId = -1L
private set
private val wideSearchbarResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
execute {
ytWordmarkHeaderId = resourceMappings[
"attr",
"ytWordmarkHeader",
]
ytPremiumWordmarkHeaderId = resourceMappings[
"attr",
"ytPremiumWordmarkHeader",
]
actionBarRingoId = resourceMappings[
"layout",
"action_bar_ringo_background",
]
}
}
val wideSearchbarPatch = bytecodePatch(
name = "Wide search bar",
description = "Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.",
description = "Adds an option to replace the search icon with a wide search bar. " +
"This will hide the YouTube logo when active.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
wideSearchbarResourcePatch,
)
compatibleWith(
@ -46,37 +84,45 @@ val wideSearchbarPatch = bytecodePatch(
SwitchPreference("revanced_wide_searchbar"),
)
/**
* Navigate a fingerprints method at a given index mutably.
*
* @param index The index to navigate to.
* @param from The fingerprint to navigate the method on.
* @return The [MutableMethod] which was navigated on.
*/
fun BytecodePatchContext.walkMutable(index: Int, from: Fingerprint) =
navigate(from.originalMethod).to(index).stop()
setWordmarkHeaderFingerprint.let {
// Navigate to the method that checks if the YT logo is shown beside the search bar.
val shouldShowLogoMethod = with(it.originalMethod) {
val invokeStaticIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_STATIC &&
getReference<MethodReference>()?.returnType == "Z"
}
navigate(this).to(invokeStaticIndex).stop()
}
/**
* Injects instructions required for certain methods.
*/
fun MutableMethod.injectSearchBarHook() {
val insertIndex = implementation!!.instructions.size - 1
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
shouldShowLogoMethod.apply {
findInstructionIndicesReversedOrThrow(Opcode.RETURN).forEach { index ->
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
insertIndex,
addInstructionsAtControlFlowLabel(
index,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->enableWideSearchbar(Z)Z
move-result v$register
"""
invoke-static {v$insertRegister}, $EXTENSION_CLASS_DESCRIPTOR->enableWideSearchbar(Z)Z
move-result v$insertRegister
""",
)
}
}
}
mapOf(
setWordmarkHeaderFingerprint to 1,
createSearchSuggestionsFingerprint to createSearchSuggestionsFingerprint.patternMatch!!.startIndex,
).forEach { (fingerprint, callIndex) ->
walkMutable(callIndex, fingerprint).injectSearchBarHook()
// Fix missing left padding when using wide searchbar.
wideSearchbarLayoutFingerprint.method.apply {
val layoutIndex = indexOfFirstLiteralInstructionOrThrow(actionBarRingoId)
val inflateIndex = indexOfFirstInstructionOrThrow(layoutIndex) {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/view/LayoutInflater;"
&& reference.name == "inflate"
}
val register = getInstruction<OneRegisterInstruction>(inflateIndex + 1).registerA
addInstruction(
inflateIndex + 2,
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setActionBar(Landroid/view/View;)V"
)
}
}
}