mirror of
https://github.com/meowarex/rl-mobile.git
synced 2026-08-26 22:17:44 +10:00
Integrations UI + Package Name Warnings/Gate <3
This commit is contained in:
+3
-1
@@ -35,12 +35,14 @@ private fun PatchOptionsScreenPreview(
|
|||||||
packageName = parameters.packageName,
|
packageName = parameters.packageName,
|
||||||
packageNameState = parameters.packageNameState,
|
packageNameState = parameters.packageNameState,
|
||||||
setPackageName = {},
|
setPackageName = {},
|
||||||
|
packageNameLocked = parameters.packageName == PatchOptions.Default.packageName,
|
||||||
|
onUnlockPackageName = {},
|
||||||
|
onLockPackageName = {},
|
||||||
customTidalApk = parameters.customTidalApk,
|
customTidalApk = parameters.customTidalApk,
|
||||||
onSelectCustomTidalApk = {},
|
onSelectCustomTidalApk = {},
|
||||||
customPatches = parameters.customPatches,
|
customPatches = parameters.customPatches,
|
||||||
onSelectCustomPatches = {},
|
onSelectCustomPatches = {},
|
||||||
specs = specs,
|
specs = specs,
|
||||||
enabledPatchCount = specs.size,
|
|
||||||
isPatchEnabled = { true },
|
isPatchEnabled = { true },
|
||||||
onTogglePatch = { _, _ -> },
|
onTogglePatch = { _, _ -> },
|
||||||
patchLockState = { PatchLock.Free },
|
patchLockState = { PatchLock.Free },
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ enum class KnownPatch(
|
|||||||
val variants: List<PatchVariant> = emptyList(),
|
val variants: List<PatchVariant> = emptyList(),
|
||||||
val defaultVariantIndex: Int = 0,
|
val defaultVariantIndex: Int = 0,
|
||||||
val advancedOptions: List<PatchOption> = emptyList(),
|
val advancedOptions: List<PatchOption> = emptyList(),
|
||||||
|
val category: String = PatchSpec.CATEGORY_PATCH,
|
||||||
|
val pathLocked: Boolean = false,
|
||||||
) {
|
) {
|
||||||
LyricsDisableCover(
|
LyricsDisableCover(
|
||||||
order = 41,
|
order = 41,
|
||||||
@@ -140,6 +142,8 @@ enum class KnownPatch(
|
|||||||
titleRes = R.string.patch_waze_integration_title,
|
titleRes = R.string.patch_waze_integration_title,
|
||||||
descRes = R.string.patch_waze_integration_desc,
|
descRes = R.string.patch_waze_integration_desc,
|
||||||
default = Disabled,
|
default = Disabled,
|
||||||
|
category = PatchSpec.CATEGORY_INTEGRATION,
|
||||||
|
pathLocked = true,
|
||||||
advancedOptions = listOf(
|
advancedOptions = listOf(
|
||||||
PatchOption.Choice(
|
PatchOption.Choice(
|
||||||
key = "browse_root",
|
key = "browse_root",
|
||||||
|
|||||||
+27
-5
@@ -43,6 +43,24 @@ class PatchOptionsModel(
|
|||||||
fetchPkgNameStateDebounced()
|
fetchPkgNameStateDebounced()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Patches flagged [PatchSpec.pathLocked] only work under the stock package name. */
|
||||||
|
fun isBlockedByPackageName(spec: PatchSpec): Boolean =
|
||||||
|
spec.pathLocked && packageName != PatchOptions.Default.packageName
|
||||||
|
|
||||||
|
/** The package-name field starts locked & editing requires confirming the unlock dialog */
|
||||||
|
var packageNameLocked by mutableStateOf(prefilledOptions.packageName == PatchOptions.Default.packageName)
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun unlockPackageName() {
|
||||||
|
packageNameLocked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Re-locking snaps the package name back to the stock default */
|
||||||
|
fun lockPackageName() {
|
||||||
|
packageNameLocked = true
|
||||||
|
changePackageName(PatchOptions.Default.packageName)
|
||||||
|
}
|
||||||
|
|
||||||
var appName by mutableStateOf(prefilledOptions.appName)
|
var appName by mutableStateOf(prefilledOptions.appName)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -83,7 +101,7 @@ class PatchOptionsModel(
|
|||||||
.coerceIn(0, spec.variants.lastIndex.coerceAtLeast(0))
|
.coerceIn(0, spec.variants.lastIndex.coerceAtLeast(0))
|
||||||
|
|
||||||
fun isPatchEnabled(spec: PatchSpec): Boolean =
|
fun isPatchEnabled(spec: PatchSpec): Boolean =
|
||||||
patchStates[spec.id] ?: spec.defaultEnabled
|
!isBlockedByPackageName(spec) && (patchStates[spec.id] ?: spec.defaultEnabled)
|
||||||
|
|
||||||
fun setPatchEnabled(spec: PatchSpec, enabled: Boolean) {
|
fun setPatchEnabled(spec: PatchSpec, enabled: Boolean) {
|
||||||
val byId = specs.associateBy { it.id }
|
val byId = specs.associateBy { it.id }
|
||||||
@@ -190,6 +208,7 @@ class PatchOptionsModel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun lockState(spec: PatchSpec): PatchLock {
|
fun lockState(spec: PatchSpec): PatchLock {
|
||||||
|
if (isBlockedByPackageName(spec)) return PatchLock.RequiresDefaultPackage
|
||||||
if (spec.variants.isNotEmpty()) return PatchLock.Free
|
if (spec.variants.isNotEmpty()) return PatchLock.Free
|
||||||
|
|
||||||
val byId = specs.associateBy { it.id }
|
val byId = specs.associateBy { it.id }
|
||||||
@@ -216,9 +235,6 @@ class PatchOptionsModel(
|
|||||||
return PatchLock.Free
|
return PatchLock.Free
|
||||||
}
|
}
|
||||||
|
|
||||||
val enabledPatchCount: Int
|
|
||||||
get() = specs.count { isPatchEnabled(it) }
|
|
||||||
|
|
||||||
var customTidalApk by mutableStateOf<PatchComponent?>(null)
|
var customTidalApk by mutableStateOf<PatchComponent?>(null)
|
||||||
private set
|
private set
|
||||||
var customPatches by mutableStateOf<PatchComponent?>(null)
|
var customPatches by mutableStateOf<PatchComponent?>(null)
|
||||||
@@ -333,7 +349,10 @@ class PatchOptionsModel(
|
|||||||
debuggable = debuggable,
|
debuggable = debuggable,
|
||||||
customTidalApk = customTidalApk,
|
customTidalApk = customTidalApk,
|
||||||
customPatches = customPatches,
|
customPatches = customPatches,
|
||||||
patchStates = patchStates,
|
// Hard-disable package-name-bound patches so the patcher can't apply
|
||||||
|
patchStates = patchStates.toMutableMap().apply {
|
||||||
|
specs.filter { isBlockedByPackageName(it) }.forEach { this[it.id] = false }
|
||||||
|
},
|
||||||
selectedVariants = selectedVariants,
|
selectedVariants = selectedVariants,
|
||||||
optionFloats = optionFloats,
|
optionFloats = optionFloats,
|
||||||
optionBools = optionBools,
|
optionBools = optionBools,
|
||||||
@@ -395,4 +414,7 @@ sealed class PatchLock {
|
|||||||
data object Free : PatchLock()
|
data object Free : PatchLock()
|
||||||
data class LockedOn(val by: PatchSpec) : PatchLock()
|
data class LockedOn(val by: PatchSpec) : PatchLock()
|
||||||
data class LockedOff(val by: PatchSpec) : PatchLock()
|
data class LockedOff(val by: PatchSpec) : PatchLock()
|
||||||
|
|
||||||
|
/** Locked off because the install uses a non-default package name */
|
||||||
|
data object RequiresDefaultPackage : PatchLock()
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-6
@@ -19,7 +19,9 @@ import com.meowarex.rlmobile.R
|
|||||||
import com.meowarex.rlmobile.ui.components.*
|
import com.meowarex.rlmobile.ui.components.*
|
||||||
import com.meowarex.rlmobile.ui.screens.componentopts.PatchComponent
|
import com.meowarex.rlmobile.ui.screens.componentopts.PatchComponent
|
||||||
import com.meowarex.rlmobile.ui.screens.patching.PatchingScreen
|
import com.meowarex.rlmobile.ui.screens.patching.PatchingScreen
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.components.PackageNameStateLabel
|
import com.meowarex.rlmobile.ui.screens.patchopts.components.PackageNameStateLabel
|
||||||
|
import com.meowarex.rlmobile.ui.screens.patchopts.components.PackageNameUnlockDialog
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.components.PatchOptionsAppBar
|
import com.meowarex.rlmobile.ui.screens.patchopts.components.PatchOptionsAppBar
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.components.PatchSelectionAccordion
|
import com.meowarex.rlmobile.ui.screens.patchopts.components.PatchSelectionAccordion
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.components.options.*
|
import com.meowarex.rlmobile.ui.screens.patchopts.components.options.*
|
||||||
@@ -55,13 +57,16 @@ class PatchOptionsScreen(
|
|||||||
packageNameState = model.packageNameState,
|
packageNameState = model.packageNameState,
|
||||||
setPackageName = model::changePackageName,
|
setPackageName = model::changePackageName,
|
||||||
|
|
||||||
|
packageNameLocked = model.packageNameLocked,
|
||||||
|
onUnlockPackageName = model::unlockPackageName,
|
||||||
|
onLockPackageName = model::lockPackageName,
|
||||||
|
|
||||||
customTidalApk = model.customTidalApk,
|
customTidalApk = model.customTidalApk,
|
||||||
customPatches = model.customPatches,
|
customPatches = model.customPatches,
|
||||||
onSelectCustomTidalApk = { model.selectCustomTidalApk(navigator) },
|
onSelectCustomTidalApk = { model.selectCustomTidalApk(navigator) },
|
||||||
onSelectCustomPatches = { model.selectCustomPatches(navigator) },
|
onSelectCustomPatches = { model.selectCustomPatches(navigator) },
|
||||||
|
|
||||||
specs = model.specs,
|
specs = model.specs,
|
||||||
enabledPatchCount = model.enabledPatchCount,
|
|
||||||
isPatchEnabled = model::isPatchEnabled,
|
isPatchEnabled = model::isPatchEnabled,
|
||||||
onTogglePatch = model::setPatchEnabled,
|
onTogglePatch = model::setPatchEnabled,
|
||||||
patchLockState = model::lockState,
|
patchLockState = model::lockState,
|
||||||
@@ -93,13 +98,16 @@ fun PatchOptionsScreenContent(
|
|||||||
packageNameState: PackageNameState,
|
packageNameState: PackageNameState,
|
||||||
setPackageName: (String) -> Unit,
|
setPackageName: (String) -> Unit,
|
||||||
|
|
||||||
|
packageNameLocked: Boolean,
|
||||||
|
onUnlockPackageName: () -> Unit,
|
||||||
|
onLockPackageName: () -> Unit,
|
||||||
|
|
||||||
customTidalApk: PatchComponent?,
|
customTidalApk: PatchComponent?,
|
||||||
onSelectCustomTidalApk: () -> Unit,
|
onSelectCustomTidalApk: () -> Unit,
|
||||||
customPatches: PatchComponent?,
|
customPatches: PatchComponent?,
|
||||||
onSelectCustomPatches: () -> Unit,
|
onSelectCustomPatches: () -> Unit,
|
||||||
|
|
||||||
specs: List<PatchSpec>,
|
specs: List<PatchSpec>,
|
||||||
enabledPatchCount: Int,
|
|
||||||
isPatchEnabled: (PatchSpec) -> Boolean,
|
isPatchEnabled: (PatchSpec) -> Boolean,
|
||||||
onTogglePatch: (PatchSpec, Boolean) -> Unit,
|
onTogglePatch: (PatchSpec, Boolean) -> Unit,
|
||||||
patchLockState: (PatchSpec) -> PatchLock,
|
patchLockState: (PatchSpec) -> PatchLock,
|
||||||
@@ -110,6 +118,18 @@ fun PatchOptionsScreenContent(
|
|||||||
isConfigValid: Boolean,
|
isConfigValid: Boolean,
|
||||||
onInstall: () -> Unit,
|
onInstall: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
var showPkgUnlockDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
|
if (showPkgUnlockDialog) {
|
||||||
|
PackageNameUnlockDialog(
|
||||||
|
blockedTitles = specs.filter { it.pathLocked }.map { it.title },
|
||||||
|
onConfirm = {
|
||||||
|
showPkgUnlockDialog = false
|
||||||
|
onUnlockPackageName()
|
||||||
|
},
|
||||||
|
onDismiss = { showPkgUnlockDialog = false },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { PatchOptionsAppBar(isUpdate = isUpdate) },
|
topBar = { PatchOptionsAppBar(isUpdate = isUpdate) },
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@@ -159,6 +179,10 @@ fun PatchOptionsScreenContent(
|
|||||||
valueIsDefault = packageNameIsDefault,
|
valueIsDefault = packageNameIsDefault,
|
||||||
onValueChange = setPackageName,
|
onValueChange = setPackageName,
|
||||||
onValueReset = { setPackageName(PatchOptions.Default.packageName) },
|
onValueReset = { setPackageName(PatchOptions.Default.packageName) },
|
||||||
|
locked = packageNameLocked,
|
||||||
|
onLockClick = {
|
||||||
|
if (packageNameLocked) showPkgUnlockDialog = true else onLockPackageName()
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
PackageNameStateLabel(
|
PackageNameStateLabel(
|
||||||
state = packageNameState,
|
state = packageNameState,
|
||||||
@@ -167,17 +191,40 @@ fun PatchOptionsScreenContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val (integrations, patches) = remember(specs) { specs.partition { it.isIntegration } }
|
||||||
|
|
||||||
|
if (integrations.isNotEmpty()) {
|
||||||
|
PatchSelectionAccordion(
|
||||||
|
iconRes = R.drawable.ic_extension,
|
||||||
|
titleRes = R.string.patchopts_integrations_title,
|
||||||
|
descriptionRes = R.string.patchopts_integrations_desc,
|
||||||
|
specs = integrations,
|
||||||
|
enabledCount = integrations.count(isPatchEnabled),
|
||||||
|
totalCount = integrations.size,
|
||||||
|
isEnabled = isPatchEnabled,
|
||||||
|
onToggle = onTogglePatch,
|
||||||
|
lockState = patchLockState,
|
||||||
|
variantIndex = variantIndex,
|
||||||
|
onSelectVariant = onSelectVariant,
|
||||||
|
optionState = optionState,
|
||||||
|
modifier = Modifier.padding(top = 4.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
PatchSelectionAccordion(
|
PatchSelectionAccordion(
|
||||||
specs = specs,
|
iconRes = R.drawable.ic_healing,
|
||||||
enabledCount = enabledPatchCount,
|
titleRes = R.string.patchopts_patches_title,
|
||||||
totalCount = specs.size,
|
descriptionRes = R.string.patchopts_patches_desc,
|
||||||
|
specs = patches,
|
||||||
|
enabledCount = patches.count(isPatchEnabled),
|
||||||
|
totalCount = patches.size,
|
||||||
isEnabled = isPatchEnabled,
|
isEnabled = isPatchEnabled,
|
||||||
onToggle = onTogglePatch,
|
onToggle = onTogglePatch,
|
||||||
lockState = patchLockState,
|
lockState = patchLockState,
|
||||||
variantIndex = variantIndex,
|
variantIndex = variantIndex,
|
||||||
onSelectVariant = onSelectVariant,
|
onSelectVariant = onSelectVariant,
|
||||||
optionState = optionState,
|
optionState = optionState,
|
||||||
modifier = Modifier.padding(top = 4.dp),
|
modifier = if (integrations.isEmpty()) Modifier.padding(top = 4.dp) else Modifier,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isDevMode) {
|
if (isDevMode) {
|
||||||
|
|||||||
+12
-1
@@ -29,7 +29,16 @@ data class PatchSpec(
|
|||||||
val variants: List<VariantSpec> = emptyList(),
|
val variants: List<VariantSpec> = emptyList(),
|
||||||
val defaultVariantIndex: Int = 0,
|
val defaultVariantIndex: Int = 0,
|
||||||
val advancedOptions: List<OptionSpec> = emptyList(),
|
val advancedOptions: List<OptionSpec> = emptyList(),
|
||||||
)
|
val category: String = CATEGORY_PATCH,
|
||||||
|
val pathLocked: Boolean = false,
|
||||||
|
) {
|
||||||
|
val isIntegration: Boolean get() = category == CATEGORY_INTEGRATION
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CATEGORY_PATCH = "patch"
|
||||||
|
const val CATEGORY_INTEGRATION = "integration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@Serializable
|
@Serializable
|
||||||
@@ -163,6 +172,8 @@ fun builtinPatchSpecs(resolve: (Int) -> String): List<PatchSpec> =
|
|||||||
variants = patch.variants.map { VariantSpec(resolve(it.titleRes), it.fileNames, it.extensionFiles) },
|
variants = patch.variants.map { VariantSpec(resolve(it.titleRes), it.fileNames, it.extensionFiles) },
|
||||||
defaultVariantIndex = patch.defaultVariantIndex,
|
defaultVariantIndex = patch.defaultVariantIndex,
|
||||||
advancedOptions = patch.advancedOptions.map { it.toSpec(resolve) },
|
advancedOptions = patch.advancedOptions.map { it.toSpec(resolve) },
|
||||||
|
category = patch.category,
|
||||||
|
pathLocked = patch.pathLocked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
package com.meowarex.rlmobile.ui.screens.patchopts.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.BasicAlertDialog
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.fromHtml
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.meowarex.rlmobile.R
|
||||||
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms unlocking the package-name field, warning that a custom name
|
||||||
|
* blocks the listed patches/integrations from working.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun PackageNameUnlockDialog(
|
||||||
|
blockedTitles: List<String>,
|
||||||
|
onConfirm: () -> Unit,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
) {
|
||||||
|
BasicAlertDialog(onDismissRequest = onDismiss) {
|
||||||
|
Surface(
|
||||||
|
shape = MaterialTheme.shapes.large,
|
||||||
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
|
tonalElevation = 6.dp,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(start = 24.dp, end = 12.dp, top = 20.dp, bottom = 8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.patchopts_pkgname_warning_title),
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = AnnotatedString.fromHtml(
|
||||||
|
stringResource(R.string.patchopts_pkgname_warning_msg, PatchOptions.Default.packageName),
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
)
|
||||||
|
if (blockedTitles.isNotEmpty()) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
|
modifier = Modifier.padding(start = 4.dp),
|
||||||
|
) {
|
||||||
|
for (title in blockedTitles) {
|
||||||
|
Text(
|
||||||
|
text = "• $title",
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.patchopts_pkgname_warning_permanent),
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
)
|
||||||
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Row(modifier = Modifier.align(Alignment.CenterEnd)) {
|
||||||
|
TextButton(onClick = onDismiss) {
|
||||||
|
Text(stringResource(R.string.action_cancel))
|
||||||
|
}
|
||||||
|
TextButton(onClick = onConfirm) {
|
||||||
|
Text(stringResource(R.string.action_continue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-3
@@ -1,6 +1,8 @@
|
|||||||
package com.meowarex.rlmobile.ui.screens.patchopts.components
|
package com.meowarex.rlmobile.ui.screens.patchopts.components
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -27,6 +29,7 @@ import com.meowarex.rlmobile.R
|
|||||||
import com.meowarex.rlmobile.ui.screens.patchopts.OptionSpec
|
import com.meowarex.rlmobile.ui.screens.patchopts.OptionSpec
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchLock
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchLock
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionState
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionState
|
||||||
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchSpec
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchSpec
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.effectiveVariants
|
import com.meowarex.rlmobile.ui.screens.patchopts.effectiveVariants
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.resolveVariantIndex
|
import com.meowarex.rlmobile.ui.screens.patchopts.resolveVariantIndex
|
||||||
@@ -35,6 +38,9 @@ private data class LockInfo(val patch: PatchSpec, val lock: PatchLock)
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PatchSelectionAccordion(
|
fun PatchSelectionAccordion(
|
||||||
|
@DrawableRes iconRes: Int,
|
||||||
|
@StringRes titleRes: Int,
|
||||||
|
@StringRes descriptionRes: Int,
|
||||||
specs: List<PatchSpec>,
|
specs: List<PatchSpec>,
|
||||||
enabledCount: Int,
|
enabledCount: Int,
|
||||||
totalCount: Int,
|
totalCount: Int,
|
||||||
@@ -69,12 +75,17 @@ fun PatchSelectionAccordion(
|
|||||||
.clickable(role = Role.Button) { expanded = !expanded }
|
.clickable(role = Role.Button) { expanded = !expanded }
|
||||||
.padding(horizontal = 16.dp, vertical = 14.dp),
|
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||||
) {
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(iconRes),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.patchopts_patches_title),
|
text = stringResource(titleRes),
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
@@ -106,7 +117,7 @@ fun PatchSelectionAccordion(
|
|||||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.patchopts_patches_desc),
|
text = stringResource(descriptionRes),
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.alpha(.7f)
|
.alpha(.7f)
|
||||||
@@ -372,6 +383,11 @@ private fun PatchLockDialog(
|
|||||||
R.string.patch_lock_blocked_msg,
|
R.string.patch_lock_blocked_msg,
|
||||||
lock.by.title,
|
lock.by.title,
|
||||||
)
|
)
|
||||||
|
PatchLock.RequiresDefaultPackage -> Triple(
|
||||||
|
R.string.patch_lock_pkgname_title,
|
||||||
|
R.string.patch_lock_pkgname_msg,
|
||||||
|
PatchOptions.Default.packageName,
|
||||||
|
)
|
||||||
PatchLock.Free -> return
|
PatchLock.Free -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +407,7 @@ private fun PatchLockDialog(
|
|||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = AnnotatedString.fromHtml(stringResource(msgRes, blockerTitle)),
|
text = AnnotatedString.fromHtml(stringResource(msgRes, blockerTitle)),
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
)
|
)
|
||||||
Box(modifier = Modifier.fillMaxWidth()) {
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|||||||
+35
-4
@@ -3,8 +3,12 @@ package com.meowarex.rlmobile.ui.screens.patchopts.components.options
|
|||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.meowarex.rlmobile.R
|
||||||
import com.meowarex.rlmobile.ui.components.Label
|
import com.meowarex.rlmobile.ui.components.Label
|
||||||
import com.meowarex.rlmobile.ui.components.ResetToDefaultButton
|
import com.meowarex.rlmobile.ui.components.ResetToDefaultButton
|
||||||
|
|
||||||
@@ -18,6 +22,8 @@ fun TextPatchOption(
|
|||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
onValueReset: () -> Unit,
|
onValueReset: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
locked: Boolean? = null,
|
||||||
|
onLockClick: () -> Unit = {},
|
||||||
extra: (@Composable ColumnScope.() -> Unit)? = null,
|
extra: (@Composable ColumnScope.() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
Label(
|
Label(
|
||||||
@@ -30,16 +36,41 @@ fun TextPatchOption(
|
|||||||
onValueChange = onValueChange,
|
onValueChange = onValueChange,
|
||||||
isError = valueIsError,
|
isError = valueIsError,
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
|
enabled = locked != true,
|
||||||
colors = OutlinedTextFieldDefaults.colors(
|
colors = OutlinedTextFieldDefaults.colors(
|
||||||
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||||
focusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
focusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||||
errorContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
errorContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||||
|
disabledContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||||
),
|
),
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
ResetToDefaultButton(
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
enabled = !valueIsDefault,
|
if (locked != true) {
|
||||||
onClick = onValueReset,
|
ResetToDefaultButton(
|
||||||
)
|
enabled = !valueIsDefault,
|
||||||
|
onClick = onValueReset,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (locked != null) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onLockClick,
|
||||||
|
modifier = Modifier.size(32.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(
|
||||||
|
if (locked) R.drawable.ic_lock else R.drawable.ic_lock_open,
|
||||||
|
),
|
||||||
|
contentDescription = stringResource(
|
||||||
|
if (locked) R.string.patchopts_field_unlock else R.string.patchopts_field_lock,
|
||||||
|
),
|
||||||
|
tint = if (locked) MaterialTheme.colorScheme.primary
|
||||||
|
else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.size(18.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="#e8eaed"
|
||||||
|
android:pathData="M218,856L104,742Q81,719 81,686Q81,653 104,630L630,104Q653,81 686,81Q719,81 742,104L856,218Q879,241 879,274Q879,307 856,330L330,856Q307,879 274,879Q241,879 218,856ZM508,734L734,508L856,630Q879,653 879,686Q879,719 856,742L742,856Q719,879 686,879Q653,879 630,856L508,734ZM480,600Q497,600 508.5,588.5Q520,577 520,560Q520,543 508.5,531.5Q497,520 480,520Q463,520 451.5,531.5Q440,543 440,560Q440,577 451.5,588.5Q463,600 480,600ZM400,520Q417,520 428.5,508.5Q440,497 440,480Q440,463 428.5,451.5Q417,440 400,440Q383,440 371.5,451.5Q360,463 360,480Q360,497 371.5,508.5Q383,520 400,520ZM560,520Q577,520 588.5,508.5Q600,497 600,480Q600,463 588.5,451.5Q577,440 560,440Q543,440 531.5,451.5Q520,463 520,480Q520,497 531.5,508.5Q543,520 560,520ZM225,451L104,330Q81,307 81,274Q81,241 104,218L218,104Q241,81 274,81Q307,81 330,104L452,226L225,451ZM480,440Q497,440 508.5,428.5Q520,417 520,400Q520,383 508.5,371.5Q497,360 480,360Q463,360 451.5,371.5Q440,383 440,400Q440,417 451.5,428.5Q463,440 480,440Z" />
|
||||||
|
</vector>
|
||||||
@@ -252,9 +252,16 @@
|
|||||||
<string name="patchopts_patches_title">Patches</string>
|
<string name="patchopts_patches_title">Patches</string>
|
||||||
<string name="patchopts_patches_desc">Toggle which patches are applied during installation. Unchecked patches are skipped entirely.</string>
|
<string name="patchopts_patches_desc">Toggle which patches are applied during installation. Unchecked patches are skipped entirely.</string>
|
||||||
<string name="patchopts_patches_summary">%1$d of %2$d enabled</string>
|
<string name="patchopts_patches_summary">%1$d of %2$d enabled</string>
|
||||||
|
<string name="patchopts_integrations_title">Integrations</string>
|
||||||
|
<string name="patchopts_integrations_desc">Connect TIDAL to other systems/apps</string>
|
||||||
|
<string name="patchopts_pkgname_warning_title">Custom Package Name</string>
|
||||||
|
<string name="patchopts_pkgname_warning_msg">Installing under a package name other than <b>%s</b> will block the following from working:</string>
|
||||||
|
<string name="patchopts_pkgname_warning_permanent">The package name is permanent once installed (requires a fresh install)</string>
|
||||||
<string name="patchopts_advanced_button">Advanced Options</string>
|
<string name="patchopts_advanced_button">Advanced Options</string>
|
||||||
<string name="patchopts_advanced_sheet_label">Advanced Options</string>
|
<string name="patchopts_advanced_sheet_label">Advanced Options</string>
|
||||||
<string name="patchopts_toggle_snap">Toggle snapping to steps</string>
|
<string name="patchopts_toggle_snap">Toggle snapping to steps</string>
|
||||||
|
<string name="patchopts_field_unlock">Unlock editing</string>
|
||||||
|
<string name="patchopts_field_lock">Lock and reset to default</string>
|
||||||
|
|
||||||
<string name="patch_lyrics_disable_cover_title">Disable Lyrics Cover</string>
|
<string name="patch_lyrics_disable_cover_title">Disable Lyrics Cover</string>
|
||||||
<string name="patch_lyrics_disable_cover_desc">Removes the mini track cover from the lyrics screen.</string>
|
<string name="patch_lyrics_disable_cover_desc">Removes the mini track cover from the lyrics screen.</string>
|
||||||
@@ -333,6 +340,8 @@
|
|||||||
<string name="patch_lock_blocked_title">Patch Blocked!</string>
|
<string name="patch_lock_blocked_title">Patch Blocked!</string>
|
||||||
<string name="patch_lock_required_msg">Patch Required by <b>%s</b>.</string>
|
<string name="patch_lock_required_msg">Patch Required by <b>%s</b>.</string>
|
||||||
<string name="patch_lock_blocked_msg">Patch Blocked by <b>%s</b>.</string>
|
<string name="patch_lock_blocked_msg">Patch Blocked by <b>%s</b>.</string>
|
||||||
|
<string name="patch_lock_pkgname_title">Original Package Name Invalid!</string>
|
||||||
|
<string name="patch_lock_pkgname_msg">This only works while the app keeps its original <b>%s</b> package name. Reset the Package Name option to enable it.<br/><br/>An existing install can\'t be renamed (requires a fresh install)</string>
|
||||||
<string name="patch_opt_lock_title">Option Locked</string>
|
<string name="patch_opt_lock_title">Option Locked</string>
|
||||||
<string name="patch_opt_lock_needs_variant">Requires the <b>%s</b> style.</string>
|
<string name="patch_opt_lock_needs_variant">Requires the <b>%s</b> style.</string>
|
||||||
<string name="patch_opt_lock_needs_option">Requires the <b>%s</b> option.</string>
|
<string name="patch_opt_lock_needs_option">Requires the <b>%s</b> option.</string>
|
||||||
|
|||||||
@@ -215,6 +215,8 @@
|
|||||||
{
|
{
|
||||||
"id": "WazeIntegration",
|
"id": "WazeIntegration",
|
||||||
"order": 90,
|
"order": 90,
|
||||||
|
"category": "integration",
|
||||||
|
"pathLocked": true,
|
||||||
"fileNames": ["waze-media-browser.patch"],
|
"fileNames": ["waze-media-browser.patch"],
|
||||||
"extensionFiles": ["radiant/WazeInitReceiver.smali", "radiant/WazeServiceConnection.smali"],
|
"extensionFiles": ["radiant/WazeInitReceiver.smali", "radiant/WazeServiceConnection.smali"],
|
||||||
"title": "Waze Integration",
|
"title": "Waze Integration",
|
||||||
|
|||||||
Reference in New Issue
Block a user