mirror of
https://github.com/meowarex/rl-mobile.git
synced 2026-08-27 06:27:46 +10:00
feat(patch): mini player gestures patch + patch suboptions
This commit is contained in:
+7
@@ -42,6 +42,8 @@ class SmaliPatchStep(
|
||||
val patches = mutableListOf<LoadedPatch>()
|
||||
val localsBumps = mutableMapOf<Pair<String, String>, Int>()
|
||||
val disabledFiles = options.disabledPatchFiles()
|
||||
val knownExtensionFiles = options.knownExtensionFiles()
|
||||
val enabledExtensionFiles = options.enabledExtensionFiles()
|
||||
|
||||
// Load and parse all the patches from the smali archive.
|
||||
container.log("Loading patches from smali patch archive: ${patchesZip.absolutePath}")
|
||||
@@ -54,6 +56,11 @@ class SmaliPatchStep(
|
||||
|
||||
if (patchFile.endsWith(".smali") && patchFile.startsWith("extension/")) {
|
||||
val relative = patchFile.removePrefix("extension/")
|
||||
if (relative in knownExtensionFiles && relative !in enabledExtensionFiles) {
|
||||
container.log("Skipping disabled extension smali: $relative")
|
||||
continue
|
||||
}
|
||||
|
||||
val out = smaliDir.resolve(relative)
|
||||
// Guard against zip-slip: a crafted entry could otherwise escape smaliDir.
|
||||
val baseCanonical = smaliDir.canonicalPath + File.separator
|
||||
|
||||
+2
@@ -40,6 +40,8 @@ private fun PatchOptionsScreenPreview(
|
||||
patchLockState = { PatchLock.Free },
|
||||
variantIndex = { 0 },
|
||||
onSelectVariant = { _, _ -> },
|
||||
isSubOptionEnabled = { _, _ -> true },
|
||||
onToggleSubOption = { _, _, _ -> },
|
||||
isConfigValid = parameters.isConfigValid,
|
||||
onInstall = {},
|
||||
)
|
||||
|
||||
@@ -8,12 +8,23 @@ import com.meowarex.rlmobile.ui.screens.patchopts.PatchDefault.Enabled
|
||||
data class PatchVariant(
|
||||
@StringRes val titleRes: Int,
|
||||
val fileNames: List<String>,
|
||||
val extensionFileNames: List<String> = emptyList(),
|
||||
)
|
||||
|
||||
data class PatchSubOption(
|
||||
val key: String,
|
||||
@StringRes val titleRes: Int,
|
||||
@StringRes val descRes: Int,
|
||||
val fileNames: List<String>,
|
||||
val default: PatchDefault,
|
||||
val extensionFileNames: List<String> = emptyList(),
|
||||
)
|
||||
|
||||
|
||||
enum class KnownPatch(
|
||||
val order: Int, // Patch order in the UI List (lower = higher up) [Main Patches: multiples of 10 | Sub Patches: multiples of 1]
|
||||
val fileNames: List<String>,
|
||||
val extensionFileNames: List<String> = emptyList(),
|
||||
@StringRes val titleRes: Int,
|
||||
@StringRes val descRes: Int,
|
||||
val default: PatchDefault, // Default state of the patch in the UI List (enabled/disabled)
|
||||
@@ -21,6 +32,7 @@ enum class KnownPatch(
|
||||
val disables: List<KnownPatch> = emptyList(),
|
||||
val variants: List<PatchVariant> = emptyList(),
|
||||
val defaultVariantIndex: Int = 0,
|
||||
val subOptions: List<PatchSubOption> = emptyList(),
|
||||
) {
|
||||
LyricsDisableCover(
|
||||
order = 41,
|
||||
@@ -135,6 +147,33 @@ enum class KnownPatch(
|
||||
),
|
||||
),
|
||||
),
|
||||
MiniPlayerGestures(
|
||||
order = 51,
|
||||
fileNames = listOf("mini-player-gestures.patch"),
|
||||
extensionFileNames = listOf(
|
||||
"radiant/MiniPlayerGestures.smali",
|
||||
"radiant/MiniPlayerGestures\$Gesture.smali",
|
||||
"radiant/MiniPlayerGestures\$RootGesture.smali",
|
||||
"radiant/MiniPlayerGestures\$ApplyPending.smali",
|
||||
),
|
||||
titleRes = R.string.patch_mini_player_gestures_title,
|
||||
descRes = R.string.patch_mini_player_gestures_desc,
|
||||
default = Enabled,
|
||||
subOptions = listOf(
|
||||
PatchSubOption(
|
||||
key = "MiniPlayerGestures.LeftRight",
|
||||
titleRes = R.string.patch_mini_player_left_right_gestures_title,
|
||||
descRes = R.string.patch_mini_player_left_right_gestures_desc,
|
||||
fileNames = listOf("mini-player-gestures-left-right.patch"),
|
||||
default = Disabled,
|
||||
extensionFileNames = listOf(
|
||||
"radiant/MiniPlayerTrackGestures.smali",
|
||||
"radiant/MiniPlayerTrackGestures\$Gesture.smali",
|
||||
"com/tidal/android/feature/appscaffold/ui/q\$c.smali",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
EnableLegacyUi(
|
||||
order = 10,
|
||||
fileNames = listOf("enable-legacy-ui.patch"),
|
||||
@@ -152,6 +191,7 @@ enum class KnownPatch(
|
||||
QualityBadgeColors,
|
||||
LyricsProgressPill,
|
||||
CoverEverywhere,
|
||||
MiniPlayerGestures,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
+32
@@ -40,6 +40,9 @@ data class PatchOptions(
|
||||
fun isEnabled(patch: KnownPatch): Boolean =
|
||||
patchStates[patch.name] ?: patch.default.isEnabled
|
||||
|
||||
fun isEnabled(subOption: PatchSubOption): Boolean =
|
||||
patchStates[subOption.key] ?: subOption.default.isEnabled
|
||||
|
||||
fun disabledPatchFiles(): Set<String> = buildSet<String> {
|
||||
for (patch in KnownPatch.All) {
|
||||
val enabled = isEnabled(patch)
|
||||
@@ -52,6 +55,35 @@ data class PatchOptions(
|
||||
if (!enabled || index != selected) addAll(variant.fileNames)
|
||||
}
|
||||
}
|
||||
for (subOption in patch.subOptions) {
|
||||
if (!enabled || !isEnabled(subOption)) addAll(subOption.fileNames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun knownExtensionFiles(): Set<String> = buildSet {
|
||||
for (patch in KnownPatch.All) {
|
||||
addAll(patch.extensionFileNames)
|
||||
patch.variants.forEach { addAll(it.extensionFileNames) }
|
||||
patch.subOptions.forEach { addAll(it.extensionFileNames) }
|
||||
}
|
||||
}
|
||||
|
||||
fun enabledExtensionFiles(): Set<String> = buildSet {
|
||||
for (patch in KnownPatch.All) {
|
||||
if (!isEnabled(patch)) continue
|
||||
|
||||
addAll(patch.extensionFileNames)
|
||||
|
||||
if (patch.variants.isNotEmpty()) {
|
||||
val selected = (selectedVariants[patch.name] ?: patch.defaultVariantIndex)
|
||||
.coerceIn(0, patch.variants.lastIndex)
|
||||
addAll(patch.variants[selected].extensionFileNames)
|
||||
}
|
||||
|
||||
for (subOption in patch.subOptions) {
|
||||
if (isEnabled(subOption)) addAll(subOption.extensionFileNames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -60,6 +60,14 @@ class PatchOptionsModel(
|
||||
fun isPatchEnabled(patch: KnownPatch): Boolean =
|
||||
patchStates[patch.name] ?: patch.default.isEnabled
|
||||
|
||||
fun isSubOptionEnabled(patch: KnownPatch, subOption: PatchSubOption): Boolean =
|
||||
isPatchEnabled(patch) && (patchStates[subOption.key] ?: subOption.default.isEnabled)
|
||||
|
||||
fun setSubOptionEnabled(patch: KnownPatch, subOption: PatchSubOption, enabled: Boolean) {
|
||||
if (subOption !in patch.subOptions) return
|
||||
patchStates = patchStates + (subOption.key to enabled)
|
||||
}
|
||||
|
||||
fun setPatchEnabled(patch: KnownPatch, enabled: Boolean) {
|
||||
fun closure(seed: KnownPatch, step: (KnownPatch) -> List<KnownPatch>): Set<KnownPatch> =
|
||||
buildSet {
|
||||
|
||||
+6
@@ -66,6 +66,8 @@ class PatchOptionsScreen(
|
||||
patchLockState = model::lockState,
|
||||
variantIndex = model::variantIndex,
|
||||
onSelectVariant = model::selectVariant,
|
||||
isSubOptionEnabled = model::isSubOptionEnabled,
|
||||
onToggleSubOption = model::setSubOptionEnabled,
|
||||
|
||||
isConfigValid = model.isConfigValid,
|
||||
onInstall = {
|
||||
@@ -102,6 +104,8 @@ fun PatchOptionsScreenContent(
|
||||
patchLockState: (KnownPatch) -> PatchLock,
|
||||
variantIndex: (KnownPatch) -> Int,
|
||||
onSelectVariant: (KnownPatch, Int) -> Unit,
|
||||
isSubOptionEnabled: (KnownPatch, PatchSubOption) -> Boolean,
|
||||
onToggleSubOption: (KnownPatch, PatchSubOption, Boolean) -> Unit,
|
||||
|
||||
isConfigValid: Boolean,
|
||||
onInstall: () -> Unit,
|
||||
@@ -171,6 +175,8 @@ fun PatchOptionsScreenContent(
|
||||
lockState = patchLockState,
|
||||
variantIndex = variantIndex,
|
||||
onSelectVariant = onSelectVariant,
|
||||
isSubOptionEnabled = isSubOptionEnabled,
|
||||
onToggleSubOption = onToggleSubOption,
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
)
|
||||
|
||||
|
||||
+26
@@ -24,6 +24,7 @@ import androidx.compose.ui.unit.dp
|
||||
import com.meowarex.rlmobile.R
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.KnownPatch
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchLock
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchSubOption
|
||||
|
||||
private data class LockInfo(val patch: KnownPatch, val lock: PatchLock)
|
||||
|
||||
@@ -36,6 +37,8 @@ fun PatchSelectionAccordion(
|
||||
lockState: (KnownPatch) -> PatchLock,
|
||||
variantIndex: (KnownPatch) -> Int,
|
||||
onSelectVariant: (KnownPatch, Int) -> Unit,
|
||||
isSubOptionEnabled: (KnownPatch, PatchSubOption) -> Boolean,
|
||||
onToggleSubOption: (KnownPatch, PatchSubOption, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
@@ -131,6 +134,29 @@ fun PatchSelectionAccordion(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (patch.subOptions.isNotEmpty()) {
|
||||
AnimatedVisibility(visible = checked) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 12.dp, end = 4.dp, top = 4.dp, bottom = 4.dp),
|
||||
) {
|
||||
for (subOption in patch.subOptions) key(subOption) {
|
||||
PatchSwitchRow(
|
||||
title = stringResource(subOption.titleRes),
|
||||
description = stringResource(subOption.descRes),
|
||||
checked = isSubOptionEnabled(patch, subOption),
|
||||
lock = PatchLock.Free,
|
||||
onCheckedChange = {
|
||||
onToggleSubOption(patch, subOption, it)
|
||||
},
|
||||
onLockedTap = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user