fix(YouTube - Settings): Use an overlay to show search results (#5806)

Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
MarcaD
2025-09-21 17:19:29 +04:00
committed by GitHub
co-authored by LisoUseInAIKyrios
parent ebb446b22a
commit ece8076f7c
104 changed files with 6066 additions and 3453 deletions
@@ -1,6 +1,5 @@
package app.revanced.patches.music.misc.settings
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
@@ -10,20 +9,19 @@ import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.InputType
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.misc.settings.preference.TextPreference
import app.revanced.patches.shared.misc.settings.settingsPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.patches.youtube.misc.settings.modifyActivityForSettingsInjection
import app.revanced.util.copyXmlNode
import app.revanced.util.inputStreamFromBundledResource
import com.android.tools.smali.dexlib2.util.MethodUtil
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
private const val GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/settings/GoogleApiActivityHook;"
"Lapp/revanced/extension/music/settings/MusicActivityHook;"
private val preferences = mutableSetOf<BasePreference>()
@@ -31,26 +29,19 @@ private val settingsResourcePatch = resourcePatch {
dependsOn(
resourceMappingPatch,
settingsPatch(
IntentPreference(
titleKey = "revanced_settings_title",
summaryKey = null,
intent = newIntent("revanced_settings_intent"),
) to "settings_headers",
listOf(
IntentPreference(
titleKey = "revanced_settings_title",
summaryKey = null,
intent = newIntent("revanced_settings_intent"),
) to "settings_headers",
),
preferences
)
)
execute {
// TODO: Remove this when search will be abstract.
copyResources(
"settings",
ResourceGroup(
"layout",
"revanced_music_settings_with_toolbar.xml"
)
)
val targetResource = "values/styles.xml"
inputStreamFromBundledResource(
"settings/music",
@@ -98,24 +89,25 @@ val settingsPatch = bytecodePatch(
selectable = true,
)
// Modify GoogleApiActivity and remove all existing layout code.
// Must modify an existing activity and cannot add a new activity to the manifest,
// as that fails for root installations.
googleApiActivityFingerprint.method.addInstructions(
1,
"""
invoke-static { }, $GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/music/settings/GoogleApiActivityHook;
move-result-object v0
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
return-void
"""
PreferenceScreen.GENERAL.addPreferences(
SwitchPreference("revanced_settings_search_history")
)
// Remove other methods as they will break as the onCreate method is modified above.
googleApiActivityFingerprint.classDef.apply {
methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
}
PreferenceScreen.MISC.addPreferences(
TextPreference(
key = null,
titleKey = "revanced_pref_import_export_title",
summaryKey = "revanced_pref_import_export_summary",
inputType = InputType.TEXT_MULTI_LINE,
tag = "app.revanced.extension.shared.settings.preference.ImportExportPreference",
)
)
modifyActivityForSettingsInjection(
googleApiActivityFingerprint.classDef,
googleApiActivityFingerprint.method,
GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR
)
}
finalize {
@@ -65,14 +65,15 @@ fun settingsPatch (
copyResources(
"settings",
ResourceGroup("xml", "revanced_prefs.xml", "revanced_prefs_icons.xml"),
ResourceGroup("menu", "revanced_search_menu.xml"),
ResourceGroup("drawable",
// CustomListPreference resources.
"revanced_ic_dialog_alert.xml",
"revanced_settings_arrow_time.xml",
"revanced_settings_circle_background.xml",
"revanced_settings_cursor.xml",
"revanced_settings_custom_checkmark.xml",
"revanced_settings_search_icon.xml",
"revanced_settings_search_remove.xml",
"revanced_settings_toolbar_arrow_left.xml",
),
ResourceGroup("layout",
@@ -80,6 +81,16 @@ fun settingsPatch (
// Color picker.
"revanced_color_dot_widget.xml",
"revanced_color_picker.xml",
// Search.
"revanced_preference_search_history_item.xml",
"revanced_preference_search_history_screen.xml",
"revanced_preference_search_no_result.xml",
"revanced_preference_search_result_color.xml",
"revanced_preference_search_result_group_header.xml",
"revanced_preference_search_result_list.xml",
"revanced_preference_search_result_regular.xml",
"revanced_preference_search_result_switch.xml",
"revanced_settings_with_toolbar.xml"
)
)
@@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tiktok/settings/AdPersonalizationActivityHook;"
"Lapp/revanced/extension/tiktok/settings/TikTokActivityHook;"
val settingsPatch = bytecodePatch(
name = "Settings",
@@ -29,7 +29,7 @@ private const val MENU_DISMISS_EVENT_CLASS_DESCRIPTOR =
"Ltv/twitch/android/feature/settings/menu/SettingsMenuViewDelegate\$Event\$OnDismissClicked;"
private const val EXTENSION_PACKAGE = "app/revanced/extension/twitch"
private const val ACTIVITY_HOOKS_CLASS_DESCRIPTOR = "L$EXTENSION_PACKAGE/settings/AppCompatActivityHook;"
private const val ACTIVITY_HOOKS_CLASS_DESCRIPTOR = "L$EXTENSION_PACKAGE/settings/TwitchActivityHook;"
private const val UTILS_CLASS_DESCRIPTOR = "L$EXTENSION_PACKAGE/Utils;"
private val preferences = mutableSetOf<BasePreference>()
@@ -46,10 +46,10 @@ private val swipeControlsResourcePatch = resourcePatch {
ListPreference("revanced_swipe_overlay_style"),
TextPreference("revanced_swipe_overlay_background_opacity", inputType = InputType.NUMBER),
TextPreference("revanced_swipe_overlay_progress_brightness_color",
tag = "app.revanced.extension.shared.settings.preference.ColorPickerPreference",
tag = "app.revanced.extension.shared.settings.preference.ColorPickerWithOpacitySliderPreference",
inputType = InputType.TEXT_CAP_CHARACTERS),
TextPreference("revanced_swipe_overlay_progress_volume_color",
tag = "app.revanced.extension.shared.settings.preference.ColorPickerPreference",
tag = "app.revanced.extension.shared.settings.preference.ColorPickerWithOpacitySliderPreference",
inputType = InputType.TEXT_CAP_CHARACTERS),
TextPreference("revanced_swipe_text_overlay_size", inputType = InputType.NUMBER),
TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER),
@@ -189,7 +189,10 @@ val hideLayoutComponentsPatch = bytecodePatch(
SwitchPreference("revanced_hide_keyword_content_subscriptions"),
SwitchPreference("revanced_hide_keyword_content_search"),
TextPreference("revanced_hide_keyword_content_phrases", inputType = InputType.TEXT_MULTI_LINE),
NonInteractivePreference("revanced_hide_keyword_content_about"),
NonInteractivePreference(
key = "revanced_hide_keyword_content_about",
tag = "app.revanced.extension.shared.settings.preference.BulletPointPreference"
),
NonInteractivePreference(
key = "revanced_hide_keyword_content_about_whole_words",
tag = "app.revanced.extension.youtube.settings.preference.HtmlPreference",
@@ -223,7 +226,10 @@ val hideLayoutComponentsPatch = bytecodePatch(
SwitchPreference("revanced_hide_chips_shelf"),
SwitchPreference("revanced_hide_expandable_card"),
SwitchPreference("revanced_hide_floating_microphone_button"),
SwitchPreference("revanced_hide_horizontal_shelves"),
SwitchPreference(
key = "revanced_hide_horizontal_shelves",
tag = "app.revanced.extension.shared.settings.preference.BulletPointSwitchPreference"
),
SwitchPreference("revanced_hide_image_shelf"),
SwitchPreference("revanced_hide_latest_posts"),
SwitchPreference("revanced_hide_mix_playlists"),
@@ -4,6 +4,8 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
@@ -31,8 +33,8 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
private const val LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/settings/LicenseActivityHook;"
private const val YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/settings/YouTubeActivityHook;"
internal var appearanceStringId = -1L
private set
@@ -73,7 +75,8 @@ private val settingsResourcePatch = resourcePatch {
// Use same colors as stock YouTube.
overrideThemeColors("@color/yt_white1", "@color/yt_black3")
arrayOf(
copyResources(
"settings",
ResourceGroup("drawable",
"revanced_settings_icon.xml",
"revanced_settings_screen_00_about.xml",
@@ -89,23 +92,15 @@ private val settingsResourcePatch = resourcePatch {
"revanced_settings_screen_10_sponsorblock.xml",
"revanced_settings_screen_11_misc.xml",
"revanced_settings_screen_12_video.xml",
),
ResourceGroup("layout",
"revanced_preference_with_icon_no_search_result.xml",
"revanced_search_suggestion_item.xml",
"revanced_settings_with_toolbar.xml"
),
ResourceGroup("menu", "revanced_search_menu.xml")
).forEach { resourceGroup ->
copyResources("settings", resourceGroup)
}
)
)
// Copy style properties used to fix over-sized copy menu that appear in EditTextPreference.
// For a full explanation of how this fixes the issue, see the comments in this style file
// and the comments in the extension code.
val targetResource = "values/styles.xml"
inputStreamFromBundledResource(
"settings/host",
"settings/youtube",
targetResource,
)!!.let { inputStream ->
"resources".copyXmlNode(
@@ -215,92 +210,6 @@ val settingsPatch = bytecodePatch(
)
)
// Modify the license activity and remove all existing layout code.
// Must modify an existing activity and cannot add a new activity to the manifest,
// as that fails for root installations.
licenseActivityOnCreateFingerprint.method.addInstructions(
1,
"""
invoke-static {}, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/youtube/settings/LicenseActivityHook;
move-result-object v0
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
return-void
"""
)
// Remove other methods as they will break as the onCreate method is modified above.
licenseActivityOnCreateFingerprint.classDef.apply {
methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
}
licenseActivityOnCreateFingerprint.classDef.apply {
// Add attachBaseContext method to override the context for setting a specific language.
ImmutableMethod(
type,
"attachBaseContext",
listOf(ImmutableMethodParameter("Landroid/content/Context;", null, null)),
"V",
AccessFlags.PROTECTED.value,
null,
null,
MutableMethodImplementation(3),
).toMutable().apply {
addInstructions(
"""
invoke-static { p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
move-result-object p1
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
return-void
"""
)
}.let(methods::add)
// Add onBackPressed method to handle back button presses, delegating to SearchViewController.
ImmutableMethod(
type,
"onBackPressed",
emptyList(),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(3),
).toMutable().apply {
addInstructions(
"""
invoke-static {}, Lapp/revanced/extension/youtube/settings/SearchViewController;->handleBackPress()Z
move-result v0
if-nez v0, :search_handled
invoke-virtual { p0 }, Landroid/app/Activity;->finish()V
:search_handled
return-void
"""
)
}.let(methods::add)
// Add onConfigurationChanged method to handle configuration changes (e.g., screen orientation).
ImmutableMethod(
type,
"onConfigurationChanged",
listOf(ImmutableMethodParameter("Landroid/content/res/Configuration;", null, null)),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(3)
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1 }, Landroid/app/Activity;->onConfigurationChanged(Landroid/content/res/Configuration;)V
invoke-static { p0, p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V
return-void
"""
)
}.let(methods::add)
}
// Update shared dark mode status based on YT theme.
// This is needed because YT allows forcing light/dark mode
// which then differs from the system dark mode status.
@@ -309,7 +218,7 @@ val settingsPatch = bytecodePatch(
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructionsAtControlFlowLabel(
index,
"invoke-static { v$register }, ${LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
"invoke-static { v$register }, ${YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
)
}
}
@@ -317,7 +226,13 @@ val settingsPatch = bytecodePatch(
// Add setting to force Cairo settings fragment on/off.
cairoFragmentConfigFingerprint.method.insertLiteralOverride(
CAIRO_CONFIG_LITERAL_VALUE,
"$LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
"$YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
)
modifyActivityForSettingsInjection(
licenseActivityOnCreateFingerprint.classDef,
licenseActivityOnCreateFingerprint.method,
YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR
)
}
@@ -326,6 +241,76 @@ val settingsPatch = bytecodePatch(
}
}
/**
* Modifies the activity to show ReVanced settings instead of it's original purpose.
*/
internal fun modifyActivityForSettingsInjection(
activityOnCreateClass: MutableClass,
activityOnCreateMethod: MutableMethod,
extensionClassType: String
) {
// Modify Activity and remove all existing layout code.
// Must modify an existing activity and cannot add a new activity to the manifest,
// as that fails for root installations.
activityOnCreateMethod.addInstructions(
1,
"""
invoke-static { p0 }, $extensionClassType->initialize(Landroid/app/Activity;)V
return-void
"""
)
// Remove other methods as they will break as the onCreate method is modified above.
activityOnCreateClass.apply {
methods.removeIf { it != activityOnCreateMethod && !MethodUtil.isConstructor(it) }
}
// Override base context to allow using ReVanced specific settings.
ImmutableMethod(
activityOnCreateClass.type,
"attachBaseContext",
listOf(ImmutableMethodParameter("Landroid/content/Context;", null, null)),
"V",
AccessFlags.PROTECTED.value,
null,
null,
MutableMethodImplementation(3),
).toMutable().apply {
addInstructions(
"""
invoke-static { p1 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
move-result-object p1
invoke-super { p0, p1 }, ${activityOnCreateClass.superclass}->attachBaseContext(Landroid/content/Context;)V
return-void
"""
)
}.let(activityOnCreateClass.methods::add)
// Override finish() to intercept back gesture.
ImmutableMethod(
activityOnCreateClass.type,
"finish",
emptyList(),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(3),
).toMutable().apply {
addInstructions(
"""
invoke-static {}, $extensionClassType->handleFinish()Z
move-result v0
if-nez v0, :search_handled
invoke-super { p0 }, Landroid/app/Activity;->finish()V
return-void
:search_handled
return-void
"""
)
}.let(activityOnCreateClass.methods::add)
}
/**
* Creates an intent to open ReVanced settings.
*/
@@ -17,7 +17,7 @@ internal val settingsMenuVideoSpeedGroup = mutableSetOf<BasePreference>()
@Suppress("unused")
val playbackSpeedPatch = bytecodePatch(
name = "Playback speed",
description = "Adds options to customize available playback speeds, set default a playback speed, " +
description = "Adds options to customize available playback speeds, set a default playback speed, " +
"and show a speed dialog button in the video player.",
) {
dependsOn(