mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-03 21:32:53 +01:00
feat(youtube/theme): change seekbar color via preference
This commit is contained in:
parent
feceb1c056
commit
9b465d9588
@ -0,0 +1,25 @@
|
||||
package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint.indexOfInstructionWithSeekbarId
|
||||
import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.Method
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
|
||||
object CreateDarkThemeSeekbarFingerprint : MethodFingerprint(
|
||||
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
customFingerprint = { method -> method.indexOfInstructionWithSeekbarId != -1 },
|
||||
) {
|
||||
/**
|
||||
* The index of the instruction that loads the resource id of the seekbar.
|
||||
*/
|
||||
internal val Method.indexOfInstructionWithSeekbarId
|
||||
get() = implementation?.let {
|
||||
it.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == ThemeResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package app.revanced.patches.youtube.layout.theme.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint
|
||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint.indexOfInstructionWithSeekbarId
|
||||
import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
@Patch
|
||||
@Name("theme")
|
||||
@Description("Applies a custom theme.")
|
||||
@DependsOn([ThemeLithoComponentsPatch::class, ThemeResourcePatch::class, IntegrationsPatch::class])
|
||||
@ThemeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ThemeBytecodePatch : BytecodePatch(listOf(CreateDarkThemeSeekbarFingerprint)) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
CreateDarkThemeSeekbarFingerprint.result?.let {
|
||||
val putColorValueIndex = it.method.indexOfInstructionWithSeekbarId!! + 3
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val overrideRegister = (instruction(putColorValueIndex) as TwoRegisterInstruction).registerA
|
||||
|
||||
addInstructions(
|
||||
putColorValueIndex,
|
||||
"""
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue()I
|
||||
move-result v$overrideRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return CreateDarkThemeSeekbarFingerprint.toErrorResult()
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemePatch;"
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package app.revanced.patches.youtube.layout.theme.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
||||
import app.revanced.patches.youtube.layout.theme.fingerprints.LithoThemeFingerprint
|
||||
|
||||
@Name("theme-litho-components")
|
||||
@Description("Applies a custom theme to Litho components.")
|
||||
@ThemeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ThemeLithoComponentsPatch : BytecodePatch(listOf(LithoThemeFingerprint)) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
LithoThemeFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val patchIndex = it.scanResult.patternScanResult!!.endIndex - 1
|
||||
|
||||
addInstructions(
|
||||
patchIndex,
|
||||
"""
|
||||
invoke-static {p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->getValue(I)I
|
||||
move-result p1
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return LithoThemeFingerprint.toErrorResult()
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemeLithoComponentsPatch;"
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.theme.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
||||
import app.revanced.patches.youtube.layout.theme.fingerprints.LithoThemeFingerprint
|
||||
|
||||
@Name("litho-components-theme")
|
||||
@Description("Applies a custom theme to litho components.")
|
||||
@ThemeCompatibility
|
||||
@Version("0.0.1")
|
||||
class LithoThemePatch : BytecodePatch(
|
||||
listOf(
|
||||
LithoThemeFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val result = LithoThemeFingerprint.result!!
|
||||
val method = result.mutableMethod
|
||||
val patchIndex = result.scanResult.patternScanResult!!.endIndex - 1
|
||||
|
||||
method.addInstructions(
|
||||
patchIndex, """
|
||||
invoke-static {p1}, Lapp/revanced/integrations/patches/LithoThemePatch;->applyLithoTheme(I)I
|
||||
move-result p1
|
||||
"""
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,29 +1,45 @@
|
||||
package app.revanced.patches.youtube.layout.theme.patch
|
||||
package app.revanced.patches.youtube.layout.theme.resource
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.*
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
||||
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||
import app.revanced.patches.shared.settings.preference.impl.InputType
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.TextPreference
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Patch
|
||||
@DependsOn([LithoThemePatch::class])
|
||||
@Name("theme")
|
||||
@Description("Applies a custom theme.")
|
||||
@ThemeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ThemePatch : ResourcePatch {
|
||||
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||
class ThemeResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
TextPreference(
|
||||
"revanced_seekbar_color",
|
||||
StringResource("revanced_seekbar_color_title", "Seekbar color"),
|
||||
InputType.STRING,
|
||||
"#ffff0000",
|
||||
StringResource(
|
||||
"revanced_seekbar_color_summary",
|
||||
"The color of the seekbar for the dark theme."
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
// Edit theme colors via bytecode.
|
||||
// For that the resource id is used in a bytecode patch to change the color.
|
||||
|
||||
inlineTimeBarColorizedBarPlayedColorDarkId = ResourceMappingPatch.resourceMappings
|
||||
.find { it.name == "inline_time_bar_colorized_bar_played_color_dark" }?.id
|
||||
?: return PatchResultError("Could not find seekbar resource")
|
||||
|
||||
|
||||
val darkThemeBackgroundColor = darkThemeBackgroundColor!!
|
||||
val lightThemeBackgroundColor = lightThemeBackgroundColor!!
|
||||
val darkThemeSeekbarColor = darkThemeSeekbarColor!!
|
||||
|
||||
// Edit theme colors via resources.
|
||||
context.xmlEditor["res/values/colors.xml"].use { editor ->
|
||||
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
|
||||
|
||||
@ -31,18 +47,19 @@ class ThemePatch : ResourcePatch {
|
||||
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
|
||||
|
||||
node.textContent = when (node.getAttribute("name")) {
|
||||
"yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3", "yt_black4", "yt_status_bar_background_dark", "material_grey_850" -> darkThemeBackgroundColor
|
||||
"yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3",
|
||||
"yt_black4", "yt_status_bar_background_dark", "material_grey_850" -> darkThemeBackgroundColor
|
||||
|
||||
"yt_white1", "yt_white1_opacity95", "yt_white1_opacity98", "yt_white2", "yt_white3", "yt_white4",
|
||||
"yt_white1", "yt_white1_opacity95", "yt_white1_opacity98",
|
||||
"yt_white2", "yt_white3", "yt_white4",
|
||||
-> lightThemeBackgroundColor
|
||||
|
||||
"inline_time_bar_colorized_bar_played_color_dark" -> darkThemeSeekbarColor
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copies the resource file to change the splash screen color
|
||||
// Copy the resource file to change the splash screen color.
|
||||
context.copyResources(
|
||||
"theme", ResourceUtils.ResourceGroup("values-night-v31", "styles.xml")
|
||||
)
|
||||
@ -51,6 +68,8 @@ class ThemePatch : ResourcePatch {
|
||||
}
|
||||
|
||||
companion object : OptionsContainer() {
|
||||
internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L
|
||||
|
||||
var darkThemeBackgroundColor: String? by option(
|
||||
PatchOption.StringOption(
|
||||
key = "darkThemeBackgroundColor",
|
||||
@ -68,14 +87,5 @@ class ThemePatch : ResourcePatch {
|
||||
description = "The background color of the light theme. Can be a hex color or a resource reference.",
|
||||
)
|
||||
)
|
||||
|
||||
var darkThemeSeekbarColor: String? by option(
|
||||
PatchOption.StringOption(
|
||||
key = "darkThemeSeekbarColor",
|
||||
default = "#ffff0000",
|
||||
title = "Dark theme seekbar color",
|
||||
description = "The background color of the seekbar of the dark theme. Leave empty for default color.",
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user