mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-12 00:57:50 +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.data.ResourceContext
|
||||||
import app.revanced.patcher.patch.*
|
import app.revanced.patcher.patch.*
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
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
|
||||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
@Patch
|
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||||
@DependsOn([LithoThemePatch::class])
|
class ThemeResourcePatch : ResourcePatch {
|
||||||
@Name("theme")
|
|
||||||
@Description("Applies a custom theme.")
|
|
||||||
@ThemeCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class ThemePatch : ResourcePatch {
|
|
||||||
override fun execute(context: ResourceContext): PatchResult {
|
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 darkThemeBackgroundColor = darkThemeBackgroundColor!!
|
||||||
val lightThemeBackgroundColor = lightThemeBackgroundColor!!
|
val lightThemeBackgroundColor = lightThemeBackgroundColor!!
|
||||||
val darkThemeSeekbarColor = darkThemeSeekbarColor!!
|
|
||||||
|
|
||||||
|
// Edit theme colors via resources.
|
||||||
context.xmlEditor["res/values/colors.xml"].use { editor ->
|
context.xmlEditor["res/values/colors.xml"].use { editor ->
|
||||||
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
|
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
|
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
|
||||||
|
|
||||||
node.textContent = when (node.getAttribute("name")) {
|
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
|
-> lightThemeBackgroundColor
|
||||||
|
|
||||||
"inline_time_bar_colorized_bar_played_color_dark" -> darkThemeSeekbarColor
|
|
||||||
else -> continue
|
else -> continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copies the resource file to change the splash screen color
|
// Copy the resource file to change the splash screen color.
|
||||||
context.copyResources(
|
context.copyResources(
|
||||||
"theme", ResourceUtils.ResourceGroup("values-night-v31", "styles.xml")
|
"theme", ResourceUtils.ResourceGroup("values-night-v31", "styles.xml")
|
||||||
)
|
)
|
||||||
@ -51,6 +68,8 @@ class ThemePatch : ResourcePatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : OptionsContainer() {
|
companion object : OptionsContainer() {
|
||||||
|
internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L
|
||||||
|
|
||||||
var darkThemeBackgroundColor: String? by option(
|
var darkThemeBackgroundColor: String? by option(
|
||||||
PatchOption.StringOption(
|
PatchOption.StringOption(
|
||||||
key = "darkThemeBackgroundColor",
|
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.",
|
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