mirror of
https://github.com/meowarex/rl-mobile.git
synced 2026-08-27 06:27:46 +10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
191dcca239 | ||
|
|
08aee155c9 | ||
|
|
47c9c37236 | ||
|
|
50b99b6193 | ||
|
|
03271bf26d | ||
|
|
75f8187526 | ||
|
|
523f0a342b | ||
|
|
fb4c776c61 | ||
|
|
cbf04d9fa7 | ||
|
|
266cd184dd | ||
|
|
04ea66acdb | ||
|
|
22526f4e0b | ||
|
|
5a3ad2df7a | ||
|
|
fa99d10134 | ||
|
|
4e8af5960c | ||
|
|
09f6e8d34f | ||
|
|
160be11ac4 | ||
|
|
4486e52117 |
+5
@@ -6,6 +6,7 @@ import com.meowarex.rlmobile.patcher.steps.StepGroup
|
||||
import com.meowarex.rlmobile.patcher.steps.base.Step
|
||||
import com.meowarex.rlmobile.patcher.steps.download.CopyDependenciesStep
|
||||
import com.meowarex.rlmobile.patcher.util.ManifestPatcher
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.KnownPatch
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
||||
import com.github.diamondminer88.zip.ZipReader
|
||||
import com.github.diamondminer88.zip.ZipWriter
|
||||
@@ -26,11 +27,15 @@ class PatchManifestStep(private val options: PatchOptions) : Step() {
|
||||
?: throw IllegalArgumentException("No manifest found in APK")
|
||||
|
||||
container.log("Patching manifest")
|
||||
val enableWazeIntegration =
|
||||
options.patchStates[KnownPatch.WazeIntegration.name] ?: KnownPatch.WazeIntegration.default.isEnabled
|
||||
|
||||
val patchedManifest = ManifestPatcher.patchManifest(
|
||||
manifestBytes = manifest,
|
||||
packageName = options.packageName,
|
||||
appName = options.appName,
|
||||
debuggable = options.debuggable,
|
||||
enableWazeIntegration = enableWazeIntegration,
|
||||
)
|
||||
|
||||
container.log("Repacking apk with patched manifest")
|
||||
|
||||
+13
-1
@@ -95,7 +95,19 @@ class SmaliPatchStep(
|
||||
val entry = zip.openEntry(patchFile)
|
||||
?: throw FileNotFoundException("Missing zip entry: $patchFile")
|
||||
out.canonicalFile.parentFile?.mkdirs()
|
||||
out.writeBytes(entry.read())
|
||||
var smaliText = entry.read()
|
||||
.decodeToString()
|
||||
.replace("\r\n", "\n")
|
||||
for ((token, value) in substitutions) {
|
||||
if (smaliText.contains(token)) {
|
||||
smaliText = smaliText.replace(token, value)
|
||||
container.log("Applied substitution $token -> $value in $patchFile")
|
||||
}
|
||||
}
|
||||
UNRESOLVED_TOKEN.find(smaliText)?.let { match ->
|
||||
throw Error("Unresolved option placeholder ${match.value} in $patchFile")
|
||||
}
|
||||
out.writeText(smaliText)
|
||||
container.log("Extracted extension smali: $relative")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -18,12 +18,16 @@ object ManifestPatcher {
|
||||
private const val IS_SPLIT_REQUIRED = "isSplitRequired"
|
||||
private const val REQUIRED_SPLIT_TYPES = "requiredSplitTypes"
|
||||
private const val SPLIT_TYPES = "splitTypes"
|
||||
private const val WAZE_PACKAGE = "com.waze"
|
||||
private const val WAZE_INIT_RECEIVER = "radiant.WazeInitReceiver"
|
||||
private const val WAZE_ACTION_INIT = "com.waze.sdk.audio.ACTION_INIT"
|
||||
|
||||
fun patchManifest(
|
||||
manifestBytes: ByteArray,
|
||||
packageName: String,
|
||||
appName: String,
|
||||
debuggable: Boolean,
|
||||
enableWazeIntegration: Boolean,
|
||||
): ByteArray {
|
||||
// Extract original package name to rewrite every reference to it
|
||||
// (permissions, provider authorities) to the new packageName.
|
||||
@@ -84,6 +88,49 @@ object ManifestPatcher {
|
||||
}
|
||||
|
||||
return when (name) {
|
||||
"queries" -> object : NodeVisitor(nv) {
|
||||
private var hasWazePackage = false
|
||||
|
||||
override fun child(ns: String?, name: String): NodeVisitor {
|
||||
val visitor = super.child(ns, name)
|
||||
|
||||
return if (enableWazeIntegration && name == "package") {
|
||||
object : NodeVisitor(visitor) {
|
||||
override fun attr(
|
||||
ns: String?,
|
||||
name: String?,
|
||||
resourceId: Int,
|
||||
type: Int,
|
||||
value: Any?,
|
||||
) {
|
||||
if (name == "name" && value == WAZE_PACKAGE) {
|
||||
hasWazePackage = true
|
||||
}
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visitor
|
||||
}
|
||||
}
|
||||
|
||||
override fun end() {
|
||||
if (enableWazeIntegration && !hasWazePackage) {
|
||||
super.child(null, "package").apply {
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"name",
|
||||
android.R.attr.name,
|
||||
TYPE_STRING,
|
||||
WAZE_PACKAGE,
|
||||
)
|
||||
end()
|
||||
}
|
||||
}
|
||||
super.end()
|
||||
}
|
||||
}
|
||||
|
||||
"uses-permission" -> object : NodeVisitor(nv) {
|
||||
override fun attr(ns: String?, name: String?, resourceId: Int, type: Int, value: Any?) {
|
||||
if (name != "maxSdkVersion") {
|
||||
@@ -132,6 +179,7 @@ object ManifestPatcher {
|
||||
private var addUseEmbeddedDex = true
|
||||
private var addExtractNativeLibs = true
|
||||
private var addMetadata = true
|
||||
private var hasWazeInitReceiver = false
|
||||
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false
|
||||
@@ -161,6 +209,22 @@ object ManifestPatcher {
|
||||
|
||||
return when (name) {
|
||||
"activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to appName))
|
||||
|
||||
"receiver" -> object : NodeVisitor(visitor) {
|
||||
override fun attr(
|
||||
ns: String?,
|
||||
name: String,
|
||||
resourceId: Int,
|
||||
type: Int,
|
||||
value: Any?
|
||||
) {
|
||||
if (name == "name" && value == WAZE_INIT_RECEIVER) {
|
||||
hasWazeInitReceiver = true
|
||||
}
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
}
|
||||
}
|
||||
|
||||
"provider" -> object : NodeVisitor(visitor) {
|
||||
override fun attr(
|
||||
ns: String?,
|
||||
@@ -219,6 +283,39 @@ object ManifestPatcher {
|
||||
0
|
||||
)
|
||||
|
||||
if (enableWazeIntegration && !hasWazeInitReceiver) {
|
||||
super.child(null, "receiver").apply {
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"name",
|
||||
android.R.attr.name,
|
||||
TYPE_STRING,
|
||||
WAZE_INIT_RECEIVER,
|
||||
)
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"exported",
|
||||
android.R.attr.exported,
|
||||
TYPE_INT_BOOLEAN,
|
||||
1,
|
||||
)
|
||||
child(null, "intent-filter").apply {
|
||||
child(null, "action").apply {
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"name",
|
||||
android.R.attr.name,
|
||||
TYPE_STRING,
|
||||
WAZE_ACTION_INIT,
|
||||
)
|
||||
end()
|
||||
}
|
||||
end()
|
||||
}
|
||||
end()
|
||||
}
|
||||
}
|
||||
|
||||
super.end()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -35,12 +35,14 @@ private fun PatchOptionsScreenPreview(
|
||||
packageName = parameters.packageName,
|
||||
packageNameState = parameters.packageNameState,
|
||||
setPackageName = {},
|
||||
packageNameLocked = parameters.packageName == PatchOptions.Default.packageName,
|
||||
onUnlockPackageName = {},
|
||||
onLockPackageName = {},
|
||||
customTidalApk = parameters.customTidalApk,
|
||||
onSelectCustomTidalApk = {},
|
||||
customPatches = parameters.customPatches,
|
||||
onSelectCustomPatches = {},
|
||||
specs = specs,
|
||||
enabledPatchCount = specs.size,
|
||||
isPatchEnabled = { true },
|
||||
onTogglePatch = { _, _ -> },
|
||||
patchLockState = { PatchLock.Free },
|
||||
|
||||
+66
-15
@@ -24,6 +24,8 @@ enum class KnownPatch(
|
||||
val variants: List<PatchVariant> = emptyList(),
|
||||
val defaultVariantIndex: Int = 0,
|
||||
val advancedOptions: List<PatchOption> = emptyList(),
|
||||
val category: String = PatchSpec.CATEGORY_PATCH,
|
||||
val pathLocked: Boolean = false,
|
||||
) {
|
||||
LyricsDisableCover(
|
||||
order = 41,
|
||||
@@ -95,6 +97,18 @@ enum class KnownPatch(
|
||||
token = "RL_SCRIM_ARGB",
|
||||
encode = SmaliEncode(EncodeKind.ArgbAlpha),
|
||||
),
|
||||
PatchOption.Toggle(
|
||||
key = "cover_everywhere",
|
||||
titleRes = R.string.patch_cover_everywhere_title,
|
||||
descRes = R.string.patch_cover_everywhere_desc,
|
||||
default = false,
|
||||
inline = true,
|
||||
fileNames = listOf(
|
||||
"home-backdrop.patch",
|
||||
"collection-backdrop.patch",
|
||||
"cover-capture.patch",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
QualityBadgeColors(
|
||||
@@ -111,17 +125,6 @@ enum class KnownPatch(
|
||||
descRes = R.string.patch_player_one_handed_desc,
|
||||
default = Disabled,
|
||||
),
|
||||
CoverEverywhere(
|
||||
order = 35,
|
||||
fileNames = listOf(
|
||||
"home-backdrop.patch",
|
||||
"collection-backdrop.patch",
|
||||
"cover-capture.patch",
|
||||
),
|
||||
titleRes = R.string.patch_cover_everywhere_title,
|
||||
descRes = R.string.patch_cover_everywhere_desc,
|
||||
default = Disabled,
|
||||
),
|
||||
DebugMenuUnlock(
|
||||
order = 100,
|
||||
fileNames = listOf("debug-menu-unlock.patch"),
|
||||
@@ -129,6 +132,41 @@ enum class KnownPatch(
|
||||
descRes = R.string.patch_debug_menu_unlock_desc,
|
||||
default = Disabled,
|
||||
),
|
||||
WazeIntegration(
|
||||
order = 90,
|
||||
fileNames = listOf("waze-media-browser.patch"),
|
||||
extensionFiles = listOf(
|
||||
"radiant/WazeInitReceiver.smali",
|
||||
"radiant/WazeServiceConnection.smali",
|
||||
),
|
||||
titleRes = R.string.patch_waze_integration_title,
|
||||
descRes = R.string.patch_waze_integration_desc,
|
||||
default = Disabled,
|
||||
category = PatchSpec.CATEGORY_INTEGRATION,
|
||||
pathLocked = true,
|
||||
advancedOptions = listOf(
|
||||
PatchOption.Choice(
|
||||
key = "browse_root",
|
||||
titleRes = R.string.patch_waze_browse_root_title,
|
||||
entries = listOf(
|
||||
ChoiceEntry(R.string.patch_waze_root_auto, value = "ROOT_AUTO"),
|
||||
ChoiceEntry(R.string.patch_waze_root_home, value = "HOME_V2::home_page_v2_id"),
|
||||
ChoiceEntry(
|
||||
R.string.patch_waze_root_recents,
|
||||
value = "RECENTLY_PLAYED::home/pages/CONTINUE_LISTEN_TO/view-all",
|
||||
),
|
||||
),
|
||||
defaultIndex = 0,
|
||||
token = "RL_WAZE_ROOT_ID",
|
||||
),
|
||||
PatchOption.Color(
|
||||
key = "accent_color",
|
||||
titleRes = R.string.patch_waze_accent_color_title,
|
||||
default = -16747037, // Waze default #ff0075e3
|
||||
token = "RL_WAZE_THEME_COLOR",
|
||||
),
|
||||
),
|
||||
),
|
||||
LyricsProgressPill(
|
||||
order = 40,
|
||||
fileNames = listOf(
|
||||
@@ -148,15 +186,15 @@ enum class KnownPatch(
|
||||
default = Disabled,
|
||||
defaultVariantIndex = 2,
|
||||
variants = listOf(
|
||||
PatchVariant( // 0: Floating — stock rounded pill (no patch; the progress border is an option)
|
||||
PatchVariant( // 0: Floating — stock rounded pill
|
||||
titleRes = R.string.patch_mini_player_variant_floating_title,
|
||||
fileNames = emptyList(),
|
||||
),
|
||||
PatchVariant( // 1: Grey — square, theme background (shown as "Legacy" when Dynamic BG is on)
|
||||
PatchVariant( // 1: Grey — square
|
||||
titleRes = R.string.patch_mini_player_variant_square_grey_title,
|
||||
fileNames = listOf("mini-player-grey.patch"),
|
||||
),
|
||||
PatchVariant( // 2: Black — square, forced black background (hidden when Dynamic BG is on)
|
||||
PatchVariant( // 2: Black — square black background
|
||||
titleRes = R.string.patch_mini_player_variant_square_black_title,
|
||||
fileNames = listOf("mini-player-black.patch"),
|
||||
),
|
||||
@@ -193,10 +231,24 @@ enum class KnownPatch(
|
||||
extensionFiles = listOf(
|
||||
"radiant/MiniPlayerGestures.smali",
|
||||
"radiant/MiniPlayerGestures\$Gesture.smali",
|
||||
"radiant/MiniPlayerGestures\$FeedbackLayer.smali",
|
||||
"radiant/MiniPlayerGestures\$FeedbackResetAnimator.smali",
|
||||
"radiant/MiniPlayerGestures\$RootGesture.smali",
|
||||
"radiant/MiniPlayerGestures\$ApplyPending.smali",
|
||||
),
|
||||
),
|
||||
PatchOption.Choice(
|
||||
key = "swipe_up_drag",
|
||||
titleRes = R.string.patch_mini_player_drag_title,
|
||||
descRes = R.string.patch_mini_player_drag_desc,
|
||||
entries = listOf(
|
||||
ChoiceEntry(R.string.patch_mini_player_drag_static, value = "0x0"),
|
||||
ChoiceEntry(R.string.patch_mini_player_drag_drag, value = "0x1"),
|
||||
),
|
||||
defaultIndex = 1,
|
||||
requiresOption = "gestures",
|
||||
token = "RL_MINI_PLAYER_SWIPE_UP_DRAG",
|
||||
),
|
||||
// Swipe left/right to skip
|
||||
PatchOption.Toggle(
|
||||
key = "next_prev",
|
||||
@@ -232,7 +284,6 @@ enum class KnownPatch(
|
||||
PlayerBackdrop,
|
||||
QualityBadgeColors,
|
||||
LyricsProgressPill,
|
||||
CoverEverywhere,
|
||||
MiniPlayerRedesign,
|
||||
),
|
||||
);
|
||||
|
||||
+14
-1
@@ -32,6 +32,8 @@ sealed interface PatchOption {
|
||||
val hidesVariants: List<Int> = emptyList(),
|
||||
/** Variant title overrides (index -> @StringRes) applied while this toggle is on. */
|
||||
val relabelVariants: Map<Int, Int> = emptyMap(),
|
||||
/** Placeholder name (without the surrounding `__`) baked into the `.patch` files. */
|
||||
val token: String? = null,
|
||||
) : PatchOption
|
||||
|
||||
/** A continuous (or stepped) numeric value within [valueRange]. */
|
||||
@@ -57,12 +59,23 @@ sealed interface PatchOption {
|
||||
data class Choice(
|
||||
override val key: String,
|
||||
@StringRes override val titleRes: Int,
|
||||
@StringRes override val descRes: Int,
|
||||
@StringRes override val descRes: Int = 0,
|
||||
val entries: List<ChoiceEntry>,
|
||||
val defaultIndex: Int = 0,
|
||||
val requiresOption: String? = null,
|
||||
val token: String? = null,
|
||||
) : PatchOption
|
||||
|
||||
data class Color(
|
||||
override val key: String,
|
||||
@StringRes override val titleRes: Int,
|
||||
@StringRes override val descRes: Int = 0,
|
||||
val default: Int,
|
||||
val token: String? = null,
|
||||
) : PatchOption
|
||||
}
|
||||
|
||||
data class ChoiceEntry(
|
||||
@StringRes val labelRes: Int,
|
||||
val value: String? = null,
|
||||
)
|
||||
|
||||
+32
-4
@@ -52,6 +52,13 @@ data class PatchOptions(
|
||||
fun sliderValue(spec: PatchSpec, option: OptionSpec.Slider): Float =
|
||||
(optionFloats["${spec.id}/${option.key}"] ?: option.default).coerceIn(option.min, option.max)
|
||||
|
||||
fun choiceIndex(spec: PatchSpec, option: OptionSpec.Choice): Int =
|
||||
(optionInts["${spec.id}/${option.key}"] ?: option.defaultIndex)
|
||||
.coerceIn(0, option.entries.lastIndex.coerceAtLeast(0))
|
||||
|
||||
fun colorValue(spec: PatchSpec, option: OptionSpec.Color): Int =
|
||||
optionInts["${spec.id}/${option.key}"] ?: option.default
|
||||
|
||||
fun isToggleOn(spec: PatchSpec, option: OptionSpec.Toggle): Boolean =
|
||||
optionBools["${spec.id}/${option.key}"] ?: option.default
|
||||
|
||||
@@ -111,10 +118,31 @@ data class PatchOptions(
|
||||
for (spec in specs) {
|
||||
if (!isEnabled(spec)) continue
|
||||
for (option in spec.advancedOptions) {
|
||||
if (option !is OptionSpec.Slider) continue
|
||||
val token = option.token ?: continue
|
||||
val encode = option.encode ?: continue
|
||||
put("__${token}__", encode.encode(sliderValue(spec, option)))
|
||||
when (option) {
|
||||
is OptionSpec.Toggle -> {
|
||||
val token = option.token ?: continue
|
||||
put("__${token}__", if (isToggleActive(spec, option)) "0x1" else "0x0")
|
||||
}
|
||||
is OptionSpec.Slider -> {
|
||||
val token = option.token ?: continue
|
||||
val encode = option.encode ?: continue
|
||||
put("__${token}__", encode.encode(sliderValue(spec, option)))
|
||||
}
|
||||
is OptionSpec.Choice -> {
|
||||
val token = option.token ?: continue
|
||||
val gatedOff = option.requiresOption?.let { key ->
|
||||
spec.advancedOptions.filterIsInstance<OptionSpec.Toggle>()
|
||||
.firstOrNull { it.key == key }
|
||||
?.let { !isToggleOn(spec, it) }
|
||||
} ?: false
|
||||
val index = if (gatedOff) 0 else choiceIndex(spec, option)
|
||||
put("__${token}__", option.values.getOrNull(index) ?: continue)
|
||||
}
|
||||
is OptionSpec.Color -> {
|
||||
val token = option.token ?: continue
|
||||
put("__${token}__", colorValue(spec, option).toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+37
-5
@@ -43,6 +43,24 @@ class PatchOptionsModel(
|
||||
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)
|
||||
private set
|
||||
|
||||
@@ -83,7 +101,7 @@ class PatchOptionsModel(
|
||||
.coerceIn(0, spec.variants.lastIndex.coerceAtLeast(0))
|
||||
|
||||
fun isPatchEnabled(spec: PatchSpec): Boolean =
|
||||
patchStates[spec.id] ?: spec.defaultEnabled
|
||||
!isBlockedByPackageName(spec) && (patchStates[spec.id] ?: spec.defaultEnabled)
|
||||
|
||||
fun setPatchEnabled(spec: PatchSpec, enabled: Boolean) {
|
||||
val byId = specs.associateBy { it.id }
|
||||
@@ -153,11 +171,19 @@ class PatchOptionsModel(
|
||||
optionInts = optionInts + (keyOf(spec, option) to index)
|
||||
}
|
||||
|
||||
fun colorValue(spec: PatchSpec, option: OptionSpec.Color): Int =
|
||||
optionInts[keyOf(spec, option)] ?: option.default
|
||||
|
||||
fun setColorValue(spec: PatchSpec, option: OptionSpec.Color, value: Int) {
|
||||
optionInts = optionInts + (keyOf(spec, option) to value)
|
||||
}
|
||||
|
||||
fun isAdvancedModified(spec: PatchSpec): Boolean = spec.advancedOptions.any { option ->
|
||||
when (option) {
|
||||
is OptionSpec.Toggle -> toggleValue(spec, option) != option.default
|
||||
is OptionSpec.Slider -> sliderValue(spec, option) != option.default
|
||||
is OptionSpec.Choice -> choiceValue(spec, option) != option.defaultIndex
|
||||
is OptionSpec.Color -> colorValue(spec, option) != option.default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,11 +201,14 @@ class PatchOptionsModel(
|
||||
setSlider = ::setSliderValue,
|
||||
choice = ::choiceValue,
|
||||
setChoice = ::setChoiceValue,
|
||||
color = ::colorValue,
|
||||
setColor = ::setColorValue,
|
||||
isModified = ::isAdvancedModified,
|
||||
reset = ::resetAdvanced,
|
||||
)
|
||||
|
||||
fun lockState(spec: PatchSpec): PatchLock {
|
||||
if (isBlockedByPackageName(spec)) return PatchLock.RequiresDefaultPackage
|
||||
if (spec.variants.isNotEmpty()) return PatchLock.Free
|
||||
|
||||
val byId = specs.associateBy { it.id }
|
||||
@@ -206,9 +235,6 @@ class PatchOptionsModel(
|
||||
return PatchLock.Free
|
||||
}
|
||||
|
||||
val enabledPatchCount: Int
|
||||
get() = specs.count { isPatchEnabled(it) }
|
||||
|
||||
var customTidalApk by mutableStateOf<PatchComponent?>(null)
|
||||
private set
|
||||
var customPatches by mutableStateOf<PatchComponent?>(null)
|
||||
@@ -323,7 +349,10 @@ class PatchOptionsModel(
|
||||
debuggable = debuggable,
|
||||
customTidalApk = customTidalApk,
|
||||
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,
|
||||
optionFloats = optionFloats,
|
||||
optionBools = optionBools,
|
||||
@@ -385,4 +414,7 @@ sealed class PatchLock {
|
||||
data object Free : PatchLock()
|
||||
data class LockedOn(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.screens.componentopts.PatchComponent
|
||||
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.PackageNameUnlockDialog
|
||||
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.options.*
|
||||
@@ -55,13 +57,16 @@ class PatchOptionsScreen(
|
||||
packageNameState = model.packageNameState,
|
||||
setPackageName = model::changePackageName,
|
||||
|
||||
packageNameLocked = model.packageNameLocked,
|
||||
onUnlockPackageName = model::unlockPackageName,
|
||||
onLockPackageName = model::lockPackageName,
|
||||
|
||||
customTidalApk = model.customTidalApk,
|
||||
customPatches = model.customPatches,
|
||||
onSelectCustomTidalApk = { model.selectCustomTidalApk(navigator) },
|
||||
onSelectCustomPatches = { model.selectCustomPatches(navigator) },
|
||||
|
||||
specs = model.specs,
|
||||
enabledPatchCount = model.enabledPatchCount,
|
||||
isPatchEnabled = model::isPatchEnabled,
|
||||
onTogglePatch = model::setPatchEnabled,
|
||||
patchLockState = model::lockState,
|
||||
@@ -93,13 +98,16 @@ fun PatchOptionsScreenContent(
|
||||
packageNameState: PackageNameState,
|
||||
setPackageName: (String) -> Unit,
|
||||
|
||||
packageNameLocked: Boolean,
|
||||
onUnlockPackageName: () -> Unit,
|
||||
onLockPackageName: () -> Unit,
|
||||
|
||||
customTidalApk: PatchComponent?,
|
||||
onSelectCustomTidalApk: () -> Unit,
|
||||
customPatches: PatchComponent?,
|
||||
onSelectCustomPatches: () -> Unit,
|
||||
|
||||
specs: List<PatchSpec>,
|
||||
enabledPatchCount: Int,
|
||||
isPatchEnabled: (PatchSpec) -> Boolean,
|
||||
onTogglePatch: (PatchSpec, Boolean) -> Unit,
|
||||
patchLockState: (PatchSpec) -> PatchLock,
|
||||
@@ -110,6 +118,18 @@ fun PatchOptionsScreenContent(
|
||||
isConfigValid: Boolean,
|
||||
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(
|
||||
topBar = { PatchOptionsAppBar(isUpdate = isUpdate) },
|
||||
) { paddingValues ->
|
||||
@@ -159,6 +179,10 @@ fun PatchOptionsScreenContent(
|
||||
valueIsDefault = packageNameIsDefault,
|
||||
onValueChange = setPackageName,
|
||||
onValueReset = { setPackageName(PatchOptions.Default.packageName) },
|
||||
locked = packageNameLocked,
|
||||
onLockClick = {
|
||||
if (packageNameLocked) showPkgUnlockDialog = true else onLockPackageName()
|
||||
},
|
||||
) {
|
||||
PackageNameStateLabel(
|
||||
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(
|
||||
specs = specs,
|
||||
enabledCount = enabledPatchCount,
|
||||
totalCount = specs.size,
|
||||
iconRes = R.drawable.ic_healing,
|
||||
titleRes = R.string.patchopts_patches_title,
|
||||
descriptionRes = R.string.patchopts_patches_desc,
|
||||
specs = patches,
|
||||
enabledCount = patches.count(isPatchEnabled),
|
||||
totalCount = patches.size,
|
||||
isEnabled = isPatchEnabled,
|
||||
onToggle = onTogglePatch,
|
||||
lockState = patchLockState,
|
||||
variantIndex = variantIndex,
|
||||
onSelectVariant = onSelectVariant,
|
||||
optionState = optionState,
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
modifier = if (integrations.isEmpty()) Modifier.padding(top = 4.dp) else Modifier,
|
||||
)
|
||||
|
||||
if (isDevMode) {
|
||||
|
||||
+47
-3
@@ -29,7 +29,16 @@ data class PatchSpec(
|
||||
val variants: List<VariantSpec> = emptyList(),
|
||||
val defaultVariantIndex: Int = 0,
|
||||
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
|
||||
@Serializable
|
||||
@@ -68,6 +77,8 @@ sealed interface OptionSpec {
|
||||
val hidesVariants: List<Int> = emptyList(),
|
||||
/** Variant title overrides (index -> title) applied while this toggle is on. */
|
||||
val relabelVariants: Map<Int, String> = emptyMap(),
|
||||
/** Placeholder name (without the surrounding `__`) baked into the `.patch` files. */
|
||||
val token: String? = null,
|
||||
) : OptionSpec
|
||||
|
||||
@Immutable
|
||||
@@ -96,10 +107,25 @@ sealed interface OptionSpec {
|
||||
@SerialName("choice")
|
||||
data class Choice(
|
||||
override val key: String,
|
||||
override val title: String,
|
||||
override val title: String = "",
|
||||
override val description: String = "",
|
||||
val entries: List<String> = emptyList(),
|
||||
val defaultIndex: Int = 0,
|
||||
val values: List<String> = emptyList(),
|
||||
val requiresOption: String? = null,
|
||||
val token: String? = null,
|
||||
) : OptionSpec
|
||||
|
||||
@Immutable
|
||||
@Serializable
|
||||
@SerialName("color")
|
||||
data class Color(
|
||||
override val key: String,
|
||||
override val title: String = "",
|
||||
override val description: String = "",
|
||||
val default: Int = 0,
|
||||
/** Placeholder name (without the surrounding `__`) baked into the `.patch`/extension files. */
|
||||
val token: String? = null,
|
||||
) : OptionSpec
|
||||
}
|
||||
|
||||
@@ -146,6 +172,8 @@ fun builtinPatchSpecs(resolve: (Int) -> String): List<PatchSpec> =
|
||||
variants = patch.variants.map { VariantSpec(resolve(it.titleRes), it.fileNames, it.extensionFiles) },
|
||||
defaultVariantIndex = patch.defaultVariantIndex,
|
||||
advancedOptions = patch.advancedOptions.map { it.toSpec(resolve) },
|
||||
category = patch.category,
|
||||
pathLocked = patch.pathLocked,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -162,6 +190,7 @@ private fun PatchOption.toSpec(resolve: (Int) -> String): OptionSpec = when (thi
|
||||
requiresOption = requiresOption,
|
||||
hidesVariants = hidesVariants,
|
||||
relabelVariants = relabelVariants.mapValues { resolve(it.value) },
|
||||
token = token,
|
||||
)
|
||||
|
||||
is PatchOption.Slider -> OptionSpec.Slider(
|
||||
@@ -181,9 +210,20 @@ private fun PatchOption.toSpec(resolve: (Int) -> String): OptionSpec = when (thi
|
||||
is PatchOption.Choice -> OptionSpec.Choice(
|
||||
key = key,
|
||||
title = resolve(titleRes),
|
||||
description = resolve(descRes),
|
||||
description = if (descRes != 0) resolve(descRes) else "",
|
||||
entries = entries.map { resolve(it.labelRes) },
|
||||
defaultIndex = defaultIndex,
|
||||
values = entries.map { it.value ?: "" },
|
||||
requiresOption = requiresOption,
|
||||
token = token,
|
||||
)
|
||||
|
||||
is PatchOption.Color -> OptionSpec.Color(
|
||||
key = key,
|
||||
title = resolve(titleRes),
|
||||
description = if (descRes != 0) resolve(descRes) else "",
|
||||
default = default,
|
||||
token = token,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -249,6 +289,8 @@ class PatchOptionState(
|
||||
val setSlider: (PatchSpec, OptionSpec.Slider, Float) -> Unit,
|
||||
val choice: (PatchSpec, OptionSpec.Choice) -> Int,
|
||||
val setChoice: (PatchSpec, OptionSpec.Choice, Int) -> Unit,
|
||||
val color: (PatchSpec, OptionSpec.Color) -> Int,
|
||||
val setColor: (PatchSpec, OptionSpec.Color, Int) -> Unit,
|
||||
val isModified: (PatchSpec) -> Boolean,
|
||||
val reset: (PatchSpec) -> Unit,
|
||||
) {
|
||||
@@ -261,6 +303,8 @@ class PatchOptionState(
|
||||
setSlider = { _, _, _ -> },
|
||||
choice = { _, option -> option.defaultIndex },
|
||||
setChoice = { _, _, _ -> },
|
||||
color = { _, option -> option.default },
|
||||
setColor = { _, _, _ -> },
|
||||
isModified = { false },
|
||||
reset = {},
|
||||
)
|
||||
|
||||
+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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+316
-20
@@ -1,9 +1,14 @@
|
||||
package com.meowarex.rlmobile.ui.screens.patchopts.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
@@ -11,11 +16,16 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.fromHtml
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -87,18 +97,91 @@ fun PatchAdvancedOptionsSheet(
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
val sheetOptions = patch.advancedOptions.filter { it !is OptionSpec.Toggle || !it.inline }
|
||||
val parentKeys = patch.advancedOptions
|
||||
.filterIsInstance<OptionSpec.Toggle>()
|
||||
.filter { !it.inline }
|
||||
.map { it.key }
|
||||
.toSet()
|
||||
val sheetOptions = patch.advancedOptions.filter { option ->
|
||||
when {
|
||||
option is OptionSpec.Toggle && option.inline -> false
|
||||
option is OptionSpec.Toggle && option.requiresOption in parentKeys -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
for (option in sheetOptions) key(option.key) {
|
||||
val lock = patch.optionLock(option, selectedVariant) { state.toggle(patch, it) }
|
||||
when (option) {
|
||||
is OptionSpec.Toggle -> ToggleOptionRow(
|
||||
title = option.title,
|
||||
description = option.description,
|
||||
checked = state.toggle(patch, option),
|
||||
onCheckedChange = { state.setToggle(patch, option, it) },
|
||||
locked = lock != OptionLock.Free,
|
||||
onLockedTap = { lockDialog = lock },
|
||||
)
|
||||
is OptionSpec.Toggle -> {
|
||||
val toggleOn = state.toggle(patch, option)
|
||||
val gatedChoices = patch.advancedOptions.filterIsInstance<OptionSpec.Choice>()
|
||||
.filter { it.requiresOption == option.key }
|
||||
val gatedToggles = patch.advancedOptions.filterIsInstance<OptionSpec.Toggle>()
|
||||
.filter { it.requiresOption == option.key && !it.inline }
|
||||
val hasSubOptions = gatedChoices.isNotEmpty() || gatedToggles.isNotEmpty()
|
||||
val carded = hasSubOptions && toggleOn
|
||||
|
||||
Column(
|
||||
modifier = if (carded) {
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.background(MaterialTheme.colorScheme.primary.copy(alpha = 0.07f))
|
||||
.border(
|
||||
width = 1.5.dp,
|
||||
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.55f),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
)
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||
} else {
|
||||
Modifier.fillMaxWidth()
|
||||
},
|
||||
) {
|
||||
ToggleOptionRow(
|
||||
title = option.title,
|
||||
description = option.description,
|
||||
checked = toggleOn,
|
||||
onCheckedChange = { state.setToggle(patch, option, it) },
|
||||
locked = lock != OptionLock.Free,
|
||||
onLockedTap = { lockDialog = lock },
|
||||
modifier = if (hasSubOptions) Modifier.padding(vertical = 6.dp) else Modifier,
|
||||
)
|
||||
if (hasSubOptions) {
|
||||
AnimatedVisibility(visible = toggleOn) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 8.dp),
|
||||
) {
|
||||
gatedChoices.forEach { choice ->
|
||||
key(choice.key) {
|
||||
ChoiceOptionRow(
|
||||
title = choice.title,
|
||||
entries = choice.entries,
|
||||
selectedIndex = state.choice(patch, choice),
|
||||
onSelect = { state.setChoice(patch, choice, it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
gatedToggles.forEach { sub ->
|
||||
key(sub.key) {
|
||||
val subLock = patch.optionLock(sub, selectedVariant) { state.toggle(patch, it) }
|
||||
ToggleOptionRow(
|
||||
title = sub.title,
|
||||
description = sub.description,
|
||||
checked = state.toggle(patch, sub),
|
||||
onCheckedChange = { state.setToggle(patch, sub, it) },
|
||||
locked = subLock != OptionLock.Free,
|
||||
onLockedTap = { lockDialog = subLock },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is OptionSpec.Slider -> SliderOptionRow(
|
||||
title = option.title,
|
||||
@@ -110,12 +193,20 @@ fun PatchAdvancedOptionsSheet(
|
||||
onValueChange = { state.setSlider(patch, option, it) },
|
||||
)
|
||||
|
||||
is OptionSpec.Choice -> ChoiceOptionRow(
|
||||
is OptionSpec.Choice ->
|
||||
if (option.requiresOption == null) {
|
||||
ChoiceOptionRow(
|
||||
title = option.title,
|
||||
entries = option.entries,
|
||||
selectedIndex = state.choice(patch, option),
|
||||
onSelect = { state.setChoice(patch, option, it) },
|
||||
)
|
||||
}
|
||||
|
||||
is OptionSpec.Color -> ColorOptionRow(
|
||||
title = option.title,
|
||||
description = option.description,
|
||||
entries = option.entries,
|
||||
selectedIndex = state.choice(patch, option),
|
||||
onSelect = { state.setChoice(patch, option, it) },
|
||||
color = state.color(patch, option),
|
||||
onColorChange = { state.setColor(patch, option, it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -147,13 +238,14 @@ private fun ToggleOptionRow(
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
locked: Boolean = false,
|
||||
onLockedTap: () -> Unit = {},
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val interactionSource = remember(::MutableInteractionSource)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(
|
||||
interactionSource = interactionSource,
|
||||
@@ -279,18 +371,58 @@ private fun snapToNearestStep(
|
||||
|
||||
@Composable
|
||||
private fun ChoiceOptionRow(
|
||||
title: String,
|
||||
description: String,
|
||||
entries: List<String>,
|
||||
selectedIndex: Int,
|
||||
onSelect: (Int) -> Unit,
|
||||
title: String = "",
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
OptionText(title = title, description = description)
|
||||
if (title.isNotEmpty()) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
if (entries.size > 3) {
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
val selectedLabel = entries.getOrNull(selectedIndex).orEmpty()
|
||||
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
OutlinedButton(
|
||||
onClick = { expanded = true },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
text = selectedLabel,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
entries.forEachIndexed { index, entry ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(entry) },
|
||||
onClick = {
|
||||
onSelect(index)
|
||||
expanded = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return@Column
|
||||
}
|
||||
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
|
||||
entries.forEachIndexed { index, entry ->
|
||||
SegmentedButton(
|
||||
@@ -313,6 +445,150 @@ private fun ChoiceOptionRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColorOptionRow(
|
||||
title: String,
|
||||
color: Int,
|
||||
onColorChange: (Int) -> Unit,
|
||||
) {
|
||||
var showPicker by rememberSaveable { mutableStateOf(false) }
|
||||
val selectedColor = color.withOpaqueAlpha()
|
||||
val materialYouColor = MaterialTheme.colorScheme.primary.toArgb().withOpaqueAlpha()
|
||||
val presets = listOf(
|
||||
stringResource(R.string.patch_waze_color_waze_default),
|
||||
stringResource(R.string.patch_waze_color_tidal_cyan),
|
||||
stringResource(R.string.patch_waze_color_material_you),
|
||||
)
|
||||
val presetColors = listOf(WAZE_DEFAULT, TIDAL_CYAN, materialYouColor)
|
||||
val selectedPreset = presetColors.indexOf(selectedColor)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.clickable { showPicker = true }
|
||||
.padding(vertical = 4.dp),
|
||||
) {
|
||||
ColorSwatch(color = selectedColor)
|
||||
Text(
|
||||
text = selectedColor.toRgbHex(),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
|
||||
presets.forEachIndexed { index, label ->
|
||||
SegmentedButton(
|
||||
selected = index == selectedPreset,
|
||||
onClick = { onColorChange(presetColors[index]) },
|
||||
shape = SegmentedButtonDefaults.itemShape(index = index, count = presets.size),
|
||||
icon = {},
|
||||
label = {
|
||||
Text(
|
||||
text = label,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showPicker) {
|
||||
ColorPickerDialog(
|
||||
initialColor = selectedColor,
|
||||
onDismiss = { showPicker = false },
|
||||
onColorSelected = {
|
||||
onColorChange(it)
|
||||
showPicker = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColorSwatch(color: Int, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(32.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color(color))
|
||||
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, CircleShape),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColorPickerDialog(
|
||||
initialColor: Int,
|
||||
onDismiss: () -> Unit,
|
||||
onColorSelected: (Int) -> Unit,
|
||||
) {
|
||||
var color by rememberSaveable(initialColor) { mutableIntStateOf(initialColor.withOpaqueAlpha()) }
|
||||
var hex by rememberSaveable(initialColor) { mutableStateOf(color.toRgbHex()) }
|
||||
val parsedHex = parseRgbHex(hex)
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(R.string.patch_color_picker_title)) },
|
||||
text = {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
ColorSwatch(color = parsedHex ?: color, modifier = Modifier.size(40.dp))
|
||||
OutlinedTextField(
|
||||
value = hex,
|
||||
onValueChange = { value ->
|
||||
hex = value
|
||||
parseRgbHex(value)?.let { color = it }
|
||||
},
|
||||
label = { Text(stringResource(R.string.patch_color_picker_hex)) },
|
||||
singleLine = true,
|
||||
isError = parsedHex == null,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.Characters,
|
||||
keyboardType = KeyboardType.Ascii,
|
||||
),
|
||||
supportingText = if (parsedHex == null) {
|
||||
{ Text(stringResource(R.string.patch_color_picker_hex_error)) }
|
||||
} else null,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
enabled = parsedHex != null,
|
||||
onClick = { parsedHex?.let(onColorSelected) },
|
||||
) {
|
||||
Text(stringResource(R.string.action_done))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OptionText(
|
||||
title: String,
|
||||
@@ -345,6 +621,26 @@ private fun formatSliderValue(option: OptionSpec.Slider, value: Float): String {
|
||||
}
|
||||
}
|
||||
|
||||
private const val OPAQUE_ALPHA = -0x1000000
|
||||
private const val WAZE_DEFAULT = -16747037 // #ff0075e3
|
||||
private const val TIDAL_CYAN = -14549268 // #ff21feec
|
||||
|
||||
private fun Int.withOpaqueAlpha(): Int = (this and 0x00FFFFFF) or OPAQUE_ALPHA
|
||||
|
||||
private fun Int.toRgbHex(): String = "#" +
|
||||
(this and 0x00FFFFFF).toString(16).uppercase().padStart(6, '0')
|
||||
|
||||
private fun parseRgbHex(value: String): Int? {
|
||||
val clean = value.trim()
|
||||
.removePrefix("#")
|
||||
.removePrefix("0x")
|
||||
.removePrefix("0X")
|
||||
if (clean.length != 6 && clean.length != 8) return null
|
||||
val parsed = clean.toLongOrNull(16) ?: return null
|
||||
val rgb = if (clean.length == 8) parsed and 0x00FFFFFFL else parsed
|
||||
return (0xFF000000L or rgb).toInt()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun OptionLockDialog(lock: OptionLock, onDismiss: () -> Unit) {
|
||||
|
||||
+93
-66
@@ -1,9 +1,12 @@
|
||||
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.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -26,6 +29,7 @@ import com.meowarex.rlmobile.R
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.OptionSpec
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchLock
|
||||
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.effectiveVariants
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.resolveVariantIndex
|
||||
@@ -34,6 +38,9 @@ private data class LockInfo(val patch: PatchSpec, val lock: PatchLock)
|
||||
|
||||
@Composable
|
||||
fun PatchSelectionAccordion(
|
||||
@DrawableRes iconRes: Int,
|
||||
@StringRes titleRes: Int,
|
||||
@StringRes descriptionRes: Int,
|
||||
specs: List<PatchSpec>,
|
||||
enabledCount: Int,
|
||||
totalCount: Int,
|
||||
@@ -68,12 +75,17 @@ fun PatchSelectionAccordion(
|
||||
.clickable(role = Role.Button) { expanded = !expanded }
|
||||
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(iconRes),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.patchopts_patches_title),
|
||||
text = stringResource(titleRes),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Text(
|
||||
@@ -105,7 +117,7 @@ fun PatchSelectionAccordion(
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.patchopts_patches_desc),
|
||||
text = stringResource(descriptionRes),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.alpha(.7f)
|
||||
@@ -115,75 +127,85 @@ fun PatchSelectionAccordion(
|
||||
for (patch in specs) key(patch.id) {
|
||||
val checked = isEnabled(patch)
|
||||
val lock = lockState(patch)
|
||||
PatchSwitchRow(
|
||||
title = patch.title,
|
||||
description = patch.description,
|
||||
checked = checked,
|
||||
lock = lock,
|
||||
onCheckedChange = { onToggle(patch, it) },
|
||||
onLockedTap = { lockInfo = LockInfo(patch, lock) },
|
||||
)
|
||||
|
||||
if (patch.variants.isNotEmpty()) {
|
||||
AnimatedVisibility(visible = checked) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 4.dp, end = 4.dp, top = 4.dp, bottom = 4.dp),
|
||||
) {
|
||||
val effective = patch.effectiveVariants { optionState.toggle(patch, it) }
|
||||
val resolved = patch.resolveVariantIndex(variantIndex(patch)) {
|
||||
optionState.toggle(patch, it)
|
||||
}
|
||||
PatchVariantSelector(
|
||||
variants = effective,
|
||||
selectedIndex = effective
|
||||
.indexOfFirst { it.originalIndex == resolved }
|
||||
.coerceAtLeast(0),
|
||||
onSelect = { pos ->
|
||||
effective.getOrNull(pos)?.let { onSelectVariant(patch, it.originalIndex) }
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val inlineToggles = patch.advancedOptions
|
||||
.filterIsInstance<OptionSpec.Toggle>()
|
||||
.filter { it.inline }
|
||||
if (inlineToggles.isNotEmpty()) {
|
||||
AnimatedVisibility(visible = checked) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
for (option in inlineToggles) key(option.key) {
|
||||
InlineToggleRow(
|
||||
title = option.title,
|
||||
description = option.description,
|
||||
checked = optionState.toggle(patch, option),
|
||||
onCheckedChange = { optionState.setToggle(patch, option, it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val hasSheetOptions = patch.advancedOptions.any { it !is OptionSpec.Toggle || !it.inline }
|
||||
if (hasSheetOptions) {
|
||||
AnimatedVisibility(visible = checked) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
AdvancedOptionsButton(
|
||||
modified = optionState.isModified(patch),
|
||||
onClick = { advancedFor = patch },
|
||||
val hasSettings = patch.variants.isNotEmpty() || inlineToggles.isNotEmpty() || hasSheetOptions
|
||||
|
||||
// When a patch is enabled and has settings show a carded view of the settings
|
||||
val carded = checked && hasSettings
|
||||
Column(
|
||||
modifier = if (carded) {
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.background(MaterialTheme.colorScheme.primary.copy(alpha = 0.07f))
|
||||
.border(
|
||||
width = 1.5.dp,
|
||||
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.55f),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
)
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||
} else {
|
||||
Modifier.fillMaxWidth()
|
||||
},
|
||||
) {
|
||||
PatchSwitchRow(
|
||||
title = patch.title,
|
||||
description = patch.description,
|
||||
checked = checked,
|
||||
lock = lock,
|
||||
onCheckedChange = { onToggle(patch, it) },
|
||||
onLockedTap = { lockInfo = LockInfo(patch, lock) },
|
||||
)
|
||||
|
||||
if (hasSettings) {
|
||||
AnimatedVisibility(visible = checked) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 8.dp),
|
||||
) {
|
||||
if (patch.variants.isNotEmpty()) {
|
||||
val effective = patch.effectiveVariants { optionState.toggle(patch, it) }
|
||||
val resolved = patch.resolveVariantIndex(variantIndex(patch)) {
|
||||
optionState.toggle(patch, it)
|
||||
}
|
||||
PatchVariantSelector(
|
||||
variants = effective,
|
||||
selectedIndex = effective
|
||||
.indexOfFirst { it.originalIndex == resolved }
|
||||
.coerceAtLeast(0),
|
||||
onSelect = { pos ->
|
||||
effective.getOrNull(pos)?.let { onSelectVariant(patch, it.originalIndex) }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for (option in inlineToggles) key(option.key) {
|
||||
InlineToggleRow(
|
||||
title = option.title,
|
||||
description = option.description,
|
||||
checked = optionState.toggle(patch, option),
|
||||
onCheckedChange = { optionState.setToggle(patch, option, it) },
|
||||
)
|
||||
}
|
||||
|
||||
if (hasSheetOptions) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
AdvancedOptionsButton(
|
||||
modified = optionState.isModified(patch),
|
||||
onClick = { advancedFor = patch },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,6 +383,11 @@ private fun PatchLockDialog(
|
||||
R.string.patch_lock_blocked_msg,
|
||||
lock.by.title,
|
||||
)
|
||||
PatchLock.RequiresDefaultPackage -> Triple(
|
||||
R.string.patch_lock_pkgname_title,
|
||||
R.string.patch_lock_pkgname_msg,
|
||||
PatchOptions.Default.packageName,
|
||||
)
|
||||
PatchLock.Free -> return
|
||||
}
|
||||
|
||||
@@ -380,7 +407,7 @@ private fun PatchLockDialog(
|
||||
)
|
||||
Text(
|
||||
text = AnnotatedString.fromHtml(stringResource(msgRes, blockerTitle)),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
TextButton(
|
||||
|
||||
+35
-4
@@ -3,8 +3,12 @@ package com.meowarex.rlmobile.ui.screens.patchopts.components.options
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.meowarex.rlmobile.R
|
||||
import com.meowarex.rlmobile.ui.components.Label
|
||||
import com.meowarex.rlmobile.ui.components.ResetToDefaultButton
|
||||
|
||||
@@ -18,6 +22,8 @@ fun TextPatchOption(
|
||||
onValueChange: (String) -> Unit,
|
||||
onValueReset: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
locked: Boolean? = null,
|
||||
onLockClick: () -> Unit = {},
|
||||
extra: (@Composable ColumnScope.() -> Unit)? = null,
|
||||
) {
|
||||
Label(
|
||||
@@ -30,16 +36,41 @@ fun TextPatchOption(
|
||||
onValueChange = onValueChange,
|
||||
isError = valueIsError,
|
||||
singleLine = true,
|
||||
enabled = locked != true,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||
focusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||
errorContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||
disabledContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
|
||||
),
|
||||
trailingIcon = {
|
||||
ResetToDefaultButton(
|
||||
enabled = !valueIsDefault,
|
||||
onClick = onValueReset,
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (locked != true) {
|
||||
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
|
||||
.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_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_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_sheet_label">Advanced Options</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_desc">Removes the mini track cover from the lyrics screen.</string>
|
||||
@@ -286,6 +293,19 @@
|
||||
<string
|
||||
name="patch_debug_menu_unlock_desc"
|
||||
>Reveals TIDAL\'s hidden Debug Menu in Settings. (Unlocks Feature Flags & the legacy Debug Options)</string>
|
||||
<string name="patch_waze_integration_title">Waze Integration</string>
|
||||
<string name="patch_waze_integration_desc">Control TIDAL playback from the Waze app</string>
|
||||
<string name="patch_waze_browse_root_title">Media Menu</string>
|
||||
<string name="patch_waze_accent_color_title">Accent Color</string>
|
||||
<string name="patch_waze_color_waze_default">Waze Default</string>
|
||||
<string name="patch_waze_color_tidal_cyan">TIDAL Cyan</string>
|
||||
<string name="patch_waze_color_material_you">Material You</string>
|
||||
<string name="patch_waze_root_auto">Auto Menu</string>
|
||||
<string name="patch_waze_root_home">Home</string>
|
||||
<string name="patch_waze_root_recents">Recents</string>
|
||||
<string name="patch_color_picker_title">Custom color</string>
|
||||
<string name="patch_color_picker_hex">Hex color</string>
|
||||
<string name="patch_color_picker_hex_error">Use #RRGGBB or #AARRGGBB.</string>
|
||||
<string name="patch_enable_legacy_ui_title">Enable Legacy UI</string>
|
||||
<string
|
||||
name="patch_enable_legacy_ui_desc"
|
||||
@@ -295,6 +315,10 @@
|
||||
<string name="patch_mini_player_redesign_desc">Integrates the Seekbar into the control panel at the bottom of the screen.</string>
|
||||
<string name="patch_mini_player_gestures_title">Mini-Player Gestures</string>
|
||||
<string name="patch_mini_player_gestures_desc">Swipe up on the mini-player to open the full player.</string>
|
||||
<string name="patch_mini_player_drag_title">Swipe Up Style</string>
|
||||
<string name="patch_mini_player_drag_desc">Whether the player follows your finger when swiping up to open it.</string>
|
||||
<string name="patch_mini_player_drag_static">Static</string>
|
||||
<string name="patch_mini_player_drag_drag">Drag</string>
|
||||
<string name="patch_mini_player_left_right_gestures_title">Next/Previous Gestures</string>
|
||||
<string name="patch_mini_player_left_right_gestures_desc">Swipe left or right on the mini-player to skip tracks.</string>
|
||||
<string name="patch_mini_player_dynamic_bg_title">Mini-Player Dynamic Background</string>
|
||||
@@ -316,6 +340,8 @@
|
||||
<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_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_needs_variant">Requires the <b>%s</b> style.</string>
|
||||
<string name="patch_opt_lock_needs_option">Requires the <b>%s</b> option.</string>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"tidalVersionCode": 9090,
|
||||
"tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk",
|
||||
"patchesVersion": "0.9.12"
|
||||
"patchesVersion": "0.9.15"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
.class public final Lradiant/MiniPlayerGestures$FeedbackLayer;
|
||||
.super Ljava/lang/Object;
|
||||
.implements Lyl0/l;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/EnclosingClass;
|
||||
value = Lradiant/MiniPlayerGestures;
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/InnerClass;
|
||||
accessFlags = 0x19
|
||||
name = "FeedbackLayer"
|
||||
.end annotation
|
||||
|
||||
|
||||
# static fields
|
||||
.field public static final INSTANCE:Lradiant/MiniPlayerGestures$FeedbackLayer;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method static constructor <clinit>()V
|
||||
.locals 1
|
||||
|
||||
new-instance v0, Lradiant/MiniPlayerGestures$FeedbackLayer;
|
||||
|
||||
invoke-direct {v0}, Lradiant/MiniPlayerGestures$FeedbackLayer;-><init>()V
|
||||
|
||||
sput-object v0, Lradiant/MiniPlayerGestures$FeedbackLayer;->INSTANCE:Lradiant/MiniPlayerGestures$FeedbackLayer;
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public final invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/u;
|
||||
.locals 1
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState;
|
||||
|
||||
invoke-interface {v0}, Landroidx/compose/runtime/MutableFloatState;->getFloatValue()F
|
||||
|
||||
move-result v0
|
||||
|
||||
invoke-interface {p1, v0}, Landroidx/compose/ui/graphics/GraphicsLayerScope;->setTranslationY(F)V
|
||||
|
||||
sget-object p1, Lkotlin/u;->a:Lkotlin/u;
|
||||
|
||||
return-object p1
|
||||
.end method
|
||||
|
||||
.method public bridge synthetic invoke(Ljava/lang/Object;)Ljava/lang/Object;
|
||||
.locals 0
|
||||
|
||||
check-cast p1, Landroidx/compose/ui/graphics/GraphicsLayerScope;
|
||||
|
||||
invoke-virtual {p0, p1}, Lradiant/MiniPlayerGestures$FeedbackLayer;->invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/u;
|
||||
|
||||
move-result-object p1
|
||||
|
||||
return-object p1
|
||||
.end method
|
||||
@@ -0,0 +1,60 @@
|
||||
.class public final Lradiant/MiniPlayerGestures$FeedbackResetAnimator;
|
||||
.super Ljava/lang/Object;
|
||||
.implements Landroid/animation/ValueAnimator$AnimatorUpdateListener;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/EnclosingClass;
|
||||
value = Lradiant/MiniPlayerGestures;
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/InnerClass;
|
||||
accessFlags = 0x19
|
||||
name = "FeedbackResetAnimator"
|
||||
.end annotation
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public final onAnimationUpdate(Landroid/animation/ValueAnimator;)V
|
||||
.locals 3
|
||||
|
||||
move-object v0, p1
|
||||
|
||||
invoke-virtual {p1}, Landroid/animation/ValueAnimator;->getAnimatedValue()Ljava/lang/Object;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
check-cast v1, Ljava/lang/Float;
|
||||
|
||||
invoke-virtual {v1}, Ljava/lang/Float;->floatValue()F
|
||||
|
||||
move-result v1
|
||||
|
||||
invoke-static {v1}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
invoke-virtual {v0}, Landroid/animation/ValueAnimator;->getAnimatedFraction()F
|
||||
|
||||
move-result v1
|
||||
|
||||
const/high16 v2, 0x3f800000 # 1.0f
|
||||
|
||||
cmpg-float v1, v1, v2
|
||||
|
||||
if-gez v1, :done
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->clearSwipeFeedbackAnimator(Landroid/animation/ValueAnimator;)V
|
||||
|
||||
:done
|
||||
return-void
|
||||
.end method
|
||||
@@ -38,9 +38,12 @@
|
||||
# True once horizontal movement wins (prevents later vertical start)
|
||||
.field public j:Z
|
||||
|
||||
# Drag option enabled
|
||||
.field public final k:Z
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>(Lyl0/l;Landroidx/compose/material3/SheetState;)V
|
||||
.method public constructor <init>(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
@@ -49,6 +52,8 @@
|
||||
|
||||
iput-object p2, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState;
|
||||
|
||||
iput-boolean p3, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -150,6 +155,10 @@
|
||||
|
||||
iput-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z
|
||||
|
||||
iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z
|
||||
|
||||
if-eqz v0, :done
|
||||
|
||||
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState;
|
||||
|
||||
iget v0, p0, Lradiant/MiniPlayerGestures$Gesture;->b:F
|
||||
@@ -158,6 +167,7 @@
|
||||
|
||||
invoke-direct {p0}, Lradiant/MiniPlayerGestures$Gesture;->openPlayer()V
|
||||
|
||||
:done
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -189,6 +199,8 @@
|
||||
|
||||
# ACTION_DOWN
|
||||
:down
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V
|
||||
|
||||
invoke-static {p1}, Lradiant/MiniPlayerGestures;->beginMotion(Landroid/view/MotionEvent;)V
|
||||
|
||||
invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F
|
||||
@@ -221,6 +233,12 @@
|
||||
|
||||
iput-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->j:Z
|
||||
|
||||
iget v0, p0, Lradiant/MiniPlayerGestures$Gesture;->b:F
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->beginSwipeGesture(F)V
|
||||
|
||||
:skip_feedback_down
|
||||
|
||||
goto :done
|
||||
|
||||
# ACTION_MOVE
|
||||
@@ -253,8 +271,17 @@
|
||||
|
||||
if-eqz v3, :maybe_start
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->suppressHorizontalGestures()V
|
||||
|
||||
iget-boolean v3, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z
|
||||
|
||||
if-eqz v3, :feedback_active
|
||||
|
||||
invoke-direct {p0, v2, v5, v6}, Lradiant/MiniPlayerGestures$Gesture;->dragSheet(FJ)V
|
||||
|
||||
:feedback_active
|
||||
invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V
|
||||
|
||||
goto :store_last
|
||||
|
||||
:maybe_start
|
||||
@@ -281,28 +308,60 @@
|
||||
|
||||
move-result v8
|
||||
|
||||
const/high16 v9, 0x41800000 # 16.0f
|
||||
const/high16 v9, 0x40c00000 # 6.0f axis deadzone
|
||||
|
||||
invoke-static {v9}, Lradiant/MiniPlayerGestures$Gesture;->dp(F)F
|
||||
|
||||
move-result v9
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->isHorizontalGestureLocked()Z
|
||||
|
||||
move-result v10
|
||||
|
||||
if-eqz v10, :horizontal_check
|
||||
|
||||
const/4 v10, 0x0
|
||||
|
||||
invoke-static {v10}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
goto :store_last
|
||||
|
||||
:horizontal_check
|
||||
|
||||
cmpg-float v10, v7, v9
|
||||
|
||||
if-gez v10, :vertical_check
|
||||
if-gez v10, :horizontal_dominance
|
||||
|
||||
const/high16 v10, 0x3fc00000 # 1.5f
|
||||
goto :vertical_check
|
||||
|
||||
:horizontal_dominance
|
||||
|
||||
const v10, 0x3f8ccccd # 1.1f
|
||||
|
||||
mul-float/2addr v10, v8
|
||||
|
||||
cmpl-float v10, v7, v10
|
||||
cmpg-float v10, v7, v10
|
||||
|
||||
if-lez v10, :vertical_check
|
||||
if-gez v10, :horizontal_wins
|
||||
|
||||
goto :vertical_check
|
||||
|
||||
:horizontal_wins
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->lockHorizontalGesture()Z
|
||||
|
||||
move-result v10
|
||||
|
||||
if-eqz v10, :store_last
|
||||
|
||||
const/4 v10, 0x1
|
||||
|
||||
iput-boolean v10, p0, Lradiant/MiniPlayerGestures$Gesture;->j:Z
|
||||
|
||||
const/4 v10, 0x0
|
||||
|
||||
invoke-static {v10}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
goto :store_last
|
||||
|
||||
# At least 16dp up to open the player
|
||||
@@ -313,10 +372,12 @@
|
||||
|
||||
if-lez v10, :vertical_dominance
|
||||
|
||||
invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V
|
||||
|
||||
goto :store_last
|
||||
|
||||
:vertical_dominance
|
||||
const/high16 v10, 0x3fc00000 # 1.5f -> has to dominate horizontal mov. by 1.5x
|
||||
const v10, 0x3f8ccccd # 1.1f -> early vertical axis lock
|
||||
|
||||
mul-float/2addr v7, v10
|
||||
|
||||
@@ -327,10 +388,29 @@
|
||||
goto :store_last
|
||||
|
||||
:begin
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->lockVerticalGesture()Z
|
||||
|
||||
move-result v10
|
||||
|
||||
if-eqz v10, :store_last
|
||||
|
||||
invoke-direct {p0, v2, v5, v6}, Lradiant/MiniPlayerGestures$Gesture;->startSheet(FJ)V
|
||||
|
||||
iget-boolean v10, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z
|
||||
|
||||
if-eqz v10, :store_last
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->suppressHorizontalGestures()V
|
||||
|
||||
iget-boolean v10, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z
|
||||
|
||||
if-eqz v10, :feedback_begin
|
||||
|
||||
invoke-direct {p0, v2, v5, v6}, Lradiant/MiniPlayerGestures$Gesture;->dragSheet(FJ)V
|
||||
|
||||
:feedback_begin
|
||||
invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V
|
||||
|
||||
|
||||
:store_last
|
||||
iput v0, p0, Lradiant/MiniPlayerGestures$Gesture;->c:F
|
||||
@@ -345,7 +425,11 @@
|
||||
|
||||
iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z
|
||||
|
||||
if-eqz v0, :finish
|
||||
if-eqz v0, :up_no_drag
|
||||
|
||||
iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z
|
||||
|
||||
if-eqz v0, :open_simple
|
||||
|
||||
invoke-static {p1}, Lradiant/MiniPlayerGestures;->trackMotion(Landroid/view/MotionEvent;)V
|
||||
|
||||
@@ -367,6 +451,28 @@
|
||||
|
||||
invoke-direct {p0, v0}, Lradiant/MiniPlayerGestures$Gesture;->finishSheet(F)V
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
goto :finish
|
||||
|
||||
:up_no_drag
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
goto :finish
|
||||
|
||||
:open_simple
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->suppressHorizontalGestures()V
|
||||
|
||||
invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F
|
||||
|
||||
move-result v0
|
||||
|
||||
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l;
|
||||
|
||||
invoke-static {v1, v0}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lyl0/l;F)Z
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
|
||||
:finish
|
||||
invoke-direct {p0}, Lradiant/MiniPlayerGestures$Gesture;->reset()V
|
||||
@@ -377,7 +483,9 @@
|
||||
:cancel
|
||||
iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z
|
||||
|
||||
if-eqz v0, :cancel_reset
|
||||
if-eqz v0, :cancel_no_active
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
iget-object v0, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState;
|
||||
|
||||
@@ -385,6 +493,11 @@
|
||||
|
||||
invoke-static {v0, v1}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V
|
||||
|
||||
goto :cancel_reset
|
||||
|
||||
:cancel_no_active
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
:cancel_reset
|
||||
invoke-direct {p0}, Lradiant/MiniPlayerGestures$Gesture;->reset()V
|
||||
|
||||
|
||||
@@ -40,16 +40,16 @@
|
||||
|
||||
iget-object v0, p0, Lradiant/MiniPlayerGestures$RootGesture;->b:Landroidx/compose/material3/SheetState;
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->isDragging(Landroidx/compose/material3/SheetState;)Z
|
||||
|
||||
move-result v1
|
||||
|
||||
if-eqz v1, :done
|
||||
|
||||
invoke-virtual {p1}, Landroid/view/MotionEvent;->getActionMasked()I
|
||||
|
||||
move-result v1
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->isDragging(Landroidx/compose/material3/SheetState;)Z
|
||||
|
||||
move-result v2
|
||||
|
||||
if-eqz v2, :maybe_reset_only
|
||||
|
||||
const/4 v2, 0x1
|
||||
|
||||
if-eq v1, v2, :up
|
||||
@@ -64,6 +64,51 @@
|
||||
|
||||
goto :done
|
||||
|
||||
:maybe_reset_only
|
||||
const/4 v2, 0x1
|
||||
|
||||
if-eq v1, v2, :simple_up
|
||||
|
||||
const/4 v2, 0x3
|
||||
|
||||
if-eq v1, v2, :reset_only
|
||||
|
||||
const/4 v2, 0x2
|
||||
|
||||
if-eq v1, v2, :simple_move
|
||||
|
||||
goto :done
|
||||
|
||||
:reset_only
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
goto :done
|
||||
|
||||
:simple_move
|
||||
invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F
|
||||
|
||||
move-result v1
|
||||
|
||||
invoke-static {v1}, Lradiant/MiniPlayerGestures;->updateSimpleSwipe(F)Z
|
||||
|
||||
goto :done
|
||||
|
||||
:simple_up
|
||||
invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F
|
||||
|
||||
move-result v1
|
||||
|
||||
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lyl0/l;
|
||||
|
||||
invoke-static {v2, v1}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lyl0/l;F)Z
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
goto :done
|
||||
|
||||
|
||||
# ACTION_MOVE
|
||||
:move
|
||||
invoke-static {p1}, Lradiant/MiniPlayerGestures;->trackMotion(Landroid/view/MotionEvent;)V
|
||||
@@ -102,6 +147,8 @@
|
||||
|
||||
invoke-static {v0, v2, v1}, Lradiant/MiniPlayerGestures;->finishDrag(Landroidx/compose/material3/SheetState;Lyl0/l;F)V
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
goto :done
|
||||
|
||||
# ACTION_CANCEL
|
||||
@@ -110,6 +157,8 @@
|
||||
|
||||
invoke-static {v0, v2}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
|
||||
|
||||
:done
|
||||
sget-object p1, Lkotlin/u;->a:Lkotlin/u;
|
||||
|
||||
|
||||
@@ -50,8 +50,43 @@
|
||||
# Mini player media state
|
||||
.field private static r:Z
|
||||
|
||||
# AppScaffold context
|
||||
.field private static s:Lyl0/l;
|
||||
|
||||
.field private static t:Landroidx/compose/material3/SheetState;
|
||||
|
||||
.field private static u:Z
|
||||
|
||||
# Feedback offset
|
||||
.field public static v:Landroidx/compose/runtime/MutableFloatState;
|
||||
|
||||
.field private static w:Landroid/animation/ValueAnimator;
|
||||
|
||||
# Gesture axis lock: 0 = none, 1 = vertical, 2 = horizontal
|
||||
.field private static x:I
|
||||
|
||||
# Swipe gesture start Y
|
||||
.field private static y:F
|
||||
|
||||
# Relative to Y drag offset
|
||||
.field private static z:F
|
||||
|
||||
|
||||
# direct methods
|
||||
.method static constructor <clinit>()V
|
||||
.locals 1
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
invoke-static {v0}, Landroidx/compose/runtime/PrimitiveSnapshotStateKt;->mutableFloatStateOf(F)Landroidx/compose/runtime/MutableFloatState;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
sput-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState;
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
@@ -60,6 +95,119 @@
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static animateSwipeFeedbackReset()V
|
||||
.locals 7
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
if-eqz v0, :read_offset
|
||||
|
||||
invoke-virtual {v0}, Landroid/animation/ValueAnimator;->cancel()V
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
:read_offset
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState;
|
||||
|
||||
invoke-interface {v0}, Landroidx/compose/runtime/MutableFloatState;->getFloatValue()F
|
||||
|
||||
move-result v0
|
||||
|
||||
invoke-static {v0}, Ljava/lang/Math;->abs(F)F
|
||||
|
||||
move-result v1
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
const/high16 v2, 0x3f000000 # 0.5f
|
||||
|
||||
cmpg-float v1, v1, v2
|
||||
|
||||
if-lez v1, :snap_zero
|
||||
|
||||
const/4 v1, 0x2
|
||||
|
||||
new-array v1, v1, [F
|
||||
|
||||
const/4 v2, 0x0
|
||||
|
||||
aput v0, v1, v2
|
||||
|
||||
const/4 v0, 0x1
|
||||
|
||||
aput v3, v1, v0
|
||||
|
||||
invoke-static {v1}, Landroid/animation/ValueAnimator;->ofFloat([F)Landroid/animation/ValueAnimator;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
const-wide/16 v4, 0xb4 # 180ms
|
||||
|
||||
invoke-virtual {v1, v4, v5}, Landroid/animation/ValueAnimator;->setDuration(J)Landroid/animation/ValueAnimator;
|
||||
|
||||
new-instance v0, Landroid/view/animation/DecelerateInterpolator;
|
||||
|
||||
const/high16 v4, 0x3fc00000 # 1.5f
|
||||
|
||||
invoke-direct {v0, v4}, Landroid/view/animation/DecelerateInterpolator;-><init>(F)V
|
||||
|
||||
invoke-virtual {v1, v0}, Landroid/animation/ValueAnimator;->setInterpolator(Landroid/animation/TimeInterpolator;)V
|
||||
|
||||
new-instance v0, Lradiant/MiniPlayerGestures$FeedbackResetAnimator;
|
||||
|
||||
invoke-direct {v0}, Lradiant/MiniPlayerGestures$FeedbackResetAnimator;-><init>()V
|
||||
|
||||
invoke-virtual {v1, v0}, Landroid/animation/ValueAnimator;->addUpdateListener(Landroid/animation/ValueAnimator$AnimatorUpdateListener;)V
|
||||
|
||||
sput-object v1, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
invoke-virtual {v1}, Landroid/animation/ValueAnimator;->start()V
|
||||
|
||||
return-void
|
||||
|
||||
:snap_zero
|
||||
invoke-static {v3}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static beginSwipeFeedback()V
|
||||
.locals 1
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
if-eqz v0, :zero
|
||||
|
||||
invoke-virtual {v0}, Landroid/animation/ValueAnimator;->cancel()V
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
:zero
|
||||
const/4 v0, 0x0
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static beginSwipeGesture(F)V
|
||||
.locals 1
|
||||
|
||||
sput p0, Lradiant/MiniPlayerGestures;->y:F
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->z:F
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->beginSwipeFeedback()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static applyPendingDrag(Landroidx/compose/material3/SheetState;)V
|
||||
.locals 5
|
||||
|
||||
@@ -473,6 +621,114 @@
|
||||
|
||||
sget-boolean v0, Lradiant/MiniPlayerGestures;->b:Z
|
||||
|
||||
if-nez v0, :yes
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->isHorizontalGestureSuppressed()Z
|
||||
|
||||
move-result v0
|
||||
|
||||
return v0
|
||||
|
||||
:yes
|
||||
const/4 v0, 0x1
|
||||
|
||||
return v0
|
||||
.end method
|
||||
|
||||
.method public static isHorizontalGestureSuppressed()Z
|
||||
.locals 2
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
if-ne v0, v1, :no
|
||||
|
||||
const/4 v0, 0x1
|
||||
|
||||
return v0
|
||||
|
||||
:no
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
.end method
|
||||
|
||||
.method public static isHorizontalGestureLocked()Z
|
||||
.locals 2
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x2
|
||||
|
||||
if-ne v0, v1, :no
|
||||
|
||||
const/4 v0, 0x1
|
||||
|
||||
return v0
|
||||
|
||||
:no
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
.end method
|
||||
|
||||
.method public static lockHorizontalGesture()Z
|
||||
.locals 2
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
if-ne v0, v1, :lock
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
|
||||
:lock
|
||||
const/4 v0, 0x2
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v0, 0x1
|
||||
|
||||
return v0
|
||||
|
||||
.end method
|
||||
|
||||
.method public static resetGestureLock()V
|
||||
.locals 1
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->y:F
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->z:F
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static lockVerticalGesture()Z
|
||||
.locals 2
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x2
|
||||
|
||||
if-ne v0, v1, :lock
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
|
||||
:lock
|
||||
const/4 v0, 0x1
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
return v0
|
||||
.end method
|
||||
|
||||
@@ -492,6 +748,63 @@
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static configure(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
|
||||
.locals 0
|
||||
|
||||
sput-object p0, Lradiant/MiniPlayerGestures;->s:Lyl0/l;
|
||||
|
||||
sput-object p1, Lradiant/MiniPlayerGestures;->t:Landroidx/compose/material3/SheetState;
|
||||
|
||||
sput-boolean p2, Lradiant/MiniPlayerGestures;->u:Z
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static clearSwipeFeedbackAnimator(Landroid/animation/ValueAnimator;)V
|
||||
.locals 1
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
if-ne v0, p0, :done
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
:done
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private static dp(F)F
|
||||
.locals 1
|
||||
|
||||
invoke-static {}, Landroid/content/res/Resources;->getSystem()Landroid/content/res/Resources;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-virtual {v0}, Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
iget v0, v0, Landroid/util/DisplayMetrics;->density:F
|
||||
|
||||
mul-float/2addr p0, v0
|
||||
|
||||
return p0
|
||||
.end method
|
||||
|
||||
.method public static feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
|
||||
.locals 1
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures$FeedbackLayer;->INSTANCE:Lradiant/MiniPlayerGestures$FeedbackLayer;
|
||||
|
||||
invoke-static {p0, v0}, Landroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
return-object p0
|
||||
.end method
|
||||
|
||||
.method private static clampReleaseVelocity(F)F
|
||||
.locals 4
|
||||
|
||||
@@ -535,12 +848,12 @@
|
||||
return p0
|
||||
.end method
|
||||
|
||||
.method public static modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier;
|
||||
.method public static modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier;
|
||||
.locals 1
|
||||
|
||||
new-instance v0, Lradiant/MiniPlayerGestures$Gesture;
|
||||
|
||||
invoke-direct {v0, p1, p2}, Lradiant/MiniPlayerGestures$Gesture;-><init>(Lyl0/l;Landroidx/compose/material3/SheetState;)V
|
||||
invoke-direct {v0, p1, p2, p3}, Lradiant/MiniPlayerGestures$Gesture;-><init>(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
|
||||
|
||||
invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
|
||||
|
||||
@@ -549,6 +862,249 @@
|
||||
return-object p0
|
||||
.end method
|
||||
|
||||
.method public static trackAreaModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
|
||||
.locals 3
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->s:Lyl0/l;
|
||||
|
||||
if-eqz v0, :done
|
||||
|
||||
sget-object v1, Lradiant/MiniPlayerGestures;->t:Landroidx/compose/material3/SheetState;
|
||||
|
||||
if-eqz v1, :done
|
||||
|
||||
sget-boolean v2, Lradiant/MiniPlayerGestures;->u:Z
|
||||
|
||||
invoke-static {p0, v0, v1, v2}, Lradiant/MiniPlayerGestures;->modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
:done
|
||||
return-object p0
|
||||
.end method
|
||||
|
||||
.method public static setSwipeFeedback(F)V
|
||||
.locals 5
|
||||
|
||||
const/4 v4, 0x0
|
||||
|
||||
cmpl-float v0, p0, v4
|
||||
|
||||
if-gtz v0, :snap_zero
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
if-eqz v0, :rubber_band
|
||||
|
||||
invoke-virtual {v0}, Landroid/animation/ValueAnimator;->cancel()V
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator;
|
||||
|
||||
:rubber_band
|
||||
invoke-static {p0}, Ljava/lang/Math;->abs(F)F
|
||||
|
||||
move-result v0
|
||||
|
||||
const/high16 v1, 0x41800000 # 16.0f dp travel
|
||||
|
||||
invoke-static {v1}, Lradiant/MiniPlayerGestures;->dp(F)F
|
||||
|
||||
move-result v1
|
||||
|
||||
cmpg-float v2, v0, v1
|
||||
|
||||
if-lez v2, :publish
|
||||
|
||||
sub-float/2addr v0, v1
|
||||
|
||||
const v2, 0x3e19999a # 0.15f resistance after 16dp
|
||||
|
||||
mul-float/2addr v0, v2
|
||||
|
||||
const/high16 v2, 0x3d800000 # 0.0625f max up travel
|
||||
|
||||
mul-float/2addr v2, v1
|
||||
|
||||
invoke-static {v0, v2}, Ljava/lang/Math;->min(FF)F
|
||||
|
||||
move-result v0
|
||||
|
||||
add-float/2addr v0, v1
|
||||
|
||||
neg-float p0, v0
|
||||
|
||||
:publish
|
||||
invoke-static {p0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
return-void
|
||||
|
||||
:snap_zero
|
||||
invoke-static {v4}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static setSwipeFeedbackFromDrag(F)V
|
||||
.locals 3
|
||||
|
||||
sput p0, Lradiant/MiniPlayerGestures;->z:F
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
cmpl-float v1, p0, v0
|
||||
|
||||
if-ltz v1, :maybe_up
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
return-void
|
||||
|
||||
:maybe_up
|
||||
const/high16 v0, 0x40c00000 # 6.0f feedback deadzone
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->dp(F)F
|
||||
|
||||
move-result v0
|
||||
|
||||
neg-float v1, v0
|
||||
|
||||
cmpg-float v2, p0, v1
|
||||
|
||||
if-gtz v2, :snap_zero
|
||||
|
||||
add-float/2addr p0, v0
|
||||
|
||||
invoke-static {p0}, Lradiant/MiniPlayerGestures;->setSwipeFeedback(F)V
|
||||
|
||||
return-void
|
||||
|
||||
:snap_zero
|
||||
const/4 v0, 0x0
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static completeSimpleSwipe(Lyl0/l;F)Z
|
||||
.locals 4
|
||||
|
||||
sget-boolean v0, Lradiant/MiniPlayerGestures;->u:Z
|
||||
|
||||
if-nez v0, :no
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
if-ne v0, v1, :no
|
||||
|
||||
sget-boolean v0, Lradiant/MiniPlayerGestures;->r:Z
|
||||
|
||||
if-eqz v0, :consume_no
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->y:F
|
||||
|
||||
sub-float/2addr p1, v0
|
||||
|
||||
sput p1, Lradiant/MiniPlayerGestures;->z:F
|
||||
|
||||
const/high16 v0, 0x42400000 # 48.0f release threshold
|
||||
|
||||
invoke-static {v0}, Lradiant/MiniPlayerGestures;->dp(F)F
|
||||
|
||||
move-result v0
|
||||
|
||||
neg-float v0, v0
|
||||
|
||||
cmpg-float v2, p1, v0
|
||||
|
||||
if-lez v2, :open
|
||||
|
||||
:consume_no
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
|
||||
:open
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V
|
||||
|
||||
sget-object v0, Lcom/tidal/android/feature/appscaffold/ui/b$b;->a:Lcom/tidal/android/feature/appscaffold/ui/b$b;
|
||||
|
||||
invoke-interface {p0, v0}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
|
||||
|
||||
const/4 v0, 0x1
|
||||
|
||||
return v0
|
||||
|
||||
:no
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
.end method
|
||||
|
||||
.method public static updateSimpleSwipe(F)Z
|
||||
.locals 3
|
||||
|
||||
sget-boolean v0, Lradiant/MiniPlayerGestures;->u:Z
|
||||
|
||||
if-nez v0, :no
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
if-ne v0, v1, :no
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->y:F
|
||||
|
||||
sub-float/2addr p0, v0
|
||||
|
||||
invoke-static {p0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V
|
||||
|
||||
const/4 v0, 0x1
|
||||
|
||||
return v0
|
||||
|
||||
:no
|
||||
const/4 v0, 0x0
|
||||
|
||||
return v0
|
||||
.end method
|
||||
|
||||
.method public static setSwipeFeedbackDirect(F)V
|
||||
.locals 1
|
||||
|
||||
sget-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState;
|
||||
|
||||
invoke-interface {v0, p0}, Landroidx/compose/runtime/MutableFloatState;->setFloatValue(F)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static suppressHorizontalGestures()V
|
||||
.locals 2
|
||||
|
||||
sget v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
const/4 v1, 0x2
|
||||
|
||||
if-ne v0, v1, :lock
|
||||
|
||||
return-void
|
||||
|
||||
:lock
|
||||
const/4 v0, 0x1
|
||||
|
||||
sput v0, Lradiant/MiniPlayerGestures;->x:I
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private static minFlingVelocity()F
|
||||
.locals 2
|
||||
|
||||
@@ -1007,6 +1563,8 @@
|
||||
|
||||
:apply
|
||||
|
||||
invoke-static {p1}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V
|
||||
|
||||
invoke-static {p0}, Lradiant/MiniPlayerGestures;->applyPendingDrag(Landroidx/compose/material3/SheetState;)V
|
||||
|
||||
const/4 v0, 0x3
|
||||
|
||||
@@ -126,6 +126,8 @@
|
||||
.method public static beginDrag(FF)V
|
||||
.locals 2
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V
|
||||
|
||||
sput p0, Lradiant/MiniPlayerTrackGestures;->e:F
|
||||
|
||||
sput p1, Lradiant/MiniPlayerTrackGestures;->f:F
|
||||
@@ -188,6 +190,24 @@
|
||||
.method public static finishDrag(FF)I
|
||||
.locals 5
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->isAnyDragging()Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-eqz v0, :check_active
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->g:Z
|
||||
|
||||
sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->h:Z
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerTrackGestures;->animateReset()V
|
||||
|
||||
return v0
|
||||
|
||||
:check_active
|
||||
|
||||
sget-boolean v0, Lradiant/MiniPlayerTrackGestures;->g:Z
|
||||
|
||||
if-nez v0, :active
|
||||
@@ -336,17 +356,38 @@
|
||||
goto :done
|
||||
|
||||
:accept
|
||||
invoke-static {}, Lradiant/MiniPlayerGestures;->lockHorizontalGesture()Z
|
||||
|
||||
move-result v2
|
||||
|
||||
if-eqz v2, :cancel_locked
|
||||
|
||||
const/4 v2, 0x1
|
||||
|
||||
sput-boolean v2, Lradiant/MiniPlayerTrackGestures;->h:Z
|
||||
|
||||
:publish
|
||||
const/4 v2, 0x0
|
||||
|
||||
invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerTrackGestures;->suppressTapOpen()V
|
||||
|
||||
invoke-static {p0}, Lradiant/MiniPlayerTrackGestures;->setDragOffset(F)V
|
||||
|
||||
:done
|
||||
return-void
|
||||
|
||||
:cancel_locked
|
||||
const/4 v0, 0x0
|
||||
|
||||
sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->g:Z
|
||||
|
||||
sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->h:Z
|
||||
|
||||
invoke-static {}, Lradiant/MiniPlayerTrackGestures;->animateReset()V
|
||||
|
||||
goto :done
|
||||
.end method
|
||||
|
||||
.method private static dp(F)F
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
.class public final Lradiant/WazeInitReceiver;
|
||||
.super Landroid/content/BroadcastReceiver;
|
||||
.source "WazeInitReceiver.smali"
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
|
||||
.locals 5
|
||||
|
||||
if-eqz p1, :return
|
||||
|
||||
if-eqz p2, :return
|
||||
|
||||
const-string v0, "com.waze.sdk.audio.ACTION_INIT"
|
||||
|
||||
invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-eqz v0, :return
|
||||
|
||||
const-string v0, "token"
|
||||
|
||||
invoke-virtual {p2, v0}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
if-eqz v0, :return
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/String;->length()I
|
||||
|
||||
move-result v1
|
||||
|
||||
if-lez v1, :return
|
||||
|
||||
invoke-virtual {p1}, Landroid/content/Context;->getApplicationContext()Landroid/content/Context;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
if-eqz v1, :context_ready
|
||||
|
||||
move-object p1, v1
|
||||
|
||||
:context_ready
|
||||
new-instance v1, Landroid/content/Intent;
|
||||
|
||||
invoke-direct {v1}, Landroid/content/Intent;-><init>()V
|
||||
|
||||
const-string v2, "com.waze"
|
||||
|
||||
const-string v3, "com.waze.sdk.SdkService"
|
||||
|
||||
invoke-virtual {v1, v2, v3}, Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
|
||||
|
||||
new-instance v2, Lradiant/WazeServiceConnection;
|
||||
|
||||
invoke-direct {v2, p1, v0}, Lradiant/WazeServiceConnection;-><init>(Landroid/content/Context;Ljava/lang/String;)V
|
||||
|
||||
:try_start_0
|
||||
const/4 v3, 0x1
|
||||
|
||||
invoke-virtual {p1, v1, v2, v3}, Landroid/content/Context;->bindService(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
|
||||
|
||||
goto :return
|
||||
|
||||
:catch_0
|
||||
move-exception v4
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
@@ -0,0 +1,228 @@
|
||||
.class public final Lradiant/WazeServiceConnection;
|
||||
.super Ljava/lang/Object;
|
||||
.source "WazeServiceConnection.smali"
|
||||
|
||||
# interfaces
|
||||
.implements Landroid/content/ServiceConnection;
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private final context:Landroid/content/Context;
|
||||
|
||||
.field private final token:Ljava/lang/String;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>(Landroid/content/Context;Ljava/lang/String;)V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
iput-object p1, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
|
||||
|
||||
iput-object p2, p0, Lradiant/WazeServiceConnection;->token:Ljava/lang/String;
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private addOpenMeIntent(Landroid/os/Bundle;)V
|
||||
.locals 4
|
||||
|
||||
iget-object v0, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
|
||||
|
||||
invoke-virtual {v0}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
invoke-virtual {v0}, Landroid/content/Context;->getPackageName()Ljava/lang/String;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/content/pm/PackageManager;->getLaunchIntentForPackage(Ljava/lang/String;)Landroid/content/Intent;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
if-eqz v1, :return
|
||||
|
||||
const/high16 v2, 0x10000000
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;
|
||||
|
||||
const v2, 0xc000000
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
invoke-static {v0, v3, v1, v2}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
const-string v2, "openMeIntent"
|
||||
|
||||
invoke-virtual {p1, v2, v1}, Landroid/os/Bundle;->putParcelable(Ljava/lang/String;Landroid/os/Parcelable;)V
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private createClientMessenger()Landroid/os/Messenger;
|
||||
.locals 3
|
||||
|
||||
new-instance v0, Landroid/os/Handler;
|
||||
|
||||
invoke-static {}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
invoke-direct {v0, v1}, Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
|
||||
|
||||
new-instance v2, Landroid/os/Messenger;
|
||||
|
||||
invoke-direct {v2, v0}, Landroid/os/Messenger;-><init>(Landroid/os/Handler;)V
|
||||
|
||||
return-object v2
|
||||
.end method
|
||||
|
||||
.method private createConfigBundle()Landroid/os/Bundle;
|
||||
.locals 3
|
||||
|
||||
new-instance v0, Landroid/os/Bundle;
|
||||
|
||||
invoke-direct {v0}, Landroid/os/Bundle;-><init>()V
|
||||
|
||||
const-string v1, "versionCode"
|
||||
|
||||
const/16 v2, 0xa
|
||||
|
||||
invoke-virtual {v0, v1, v2}, Landroid/os/Bundle;->putInt(Ljava/lang/String;I)V
|
||||
|
||||
const-string v1, "themeColor"
|
||||
|
||||
const v2, __RL_WAZE_THEME_COLOR__ # Waze SDK themeColor
|
||||
|
||||
invoke-virtual {v0, v1, v2}, Landroid/os/Bundle;->putInt(Ljava/lang/String;I)V
|
||||
|
||||
invoke-direct {p0, v0}, Lradiant/WazeServiceConnection;->addOpenMeIntent(Landroid/os/Bundle;)V
|
||||
|
||||
return-object v0
|
||||
.end method
|
||||
|
||||
.method private register(Landroid/os/IBinder;)V
|
||||
.locals 5
|
||||
|
||||
if-eqz p1, :return
|
||||
|
||||
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
const-string v2, "com.waze.sdk.ISdkService"
|
||||
|
||||
invoke-virtual {v0, v2}, Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V
|
||||
|
||||
iget-object v2, p0, Lradiant/WazeServiceConnection;->token:Ljava/lang/String;
|
||||
|
||||
invoke-virtual {v0, v2}, Landroid/os/Parcel;->writeString(Ljava/lang/String;)V
|
||||
|
||||
invoke-direct {p0}, Lradiant/WazeServiceConnection;->createConfigBundle()Landroid/os/Bundle;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-static {v0, v2}, Lradiant/WazeServiceConnection;->writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
|
||||
|
||||
invoke-direct {p0}, Lradiant/WazeServiceConnection;->createClientMessenger()Landroid/os/Messenger;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-static {v0, v2}, Lradiant/WazeServiceConnection;->writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
|
||||
|
||||
const/4 v2, 0x1
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
invoke-interface {p1, v2, v0, v1, v3}, Landroid/os/IBinder;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
|
||||
|
||||
move-result v4
|
||||
|
||||
if-eqz v4, :cleanup
|
||||
|
||||
invoke-virtual {v1}, Landroid/os/Parcel;->readException()V
|
||||
|
||||
:cleanup
|
||||
invoke-virtual {v1}, Landroid/os/Parcel;->recycle()V
|
||||
|
||||
invoke-virtual {v0}, Landroid/os/Parcel;->recycle()V
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private safeUnbind()V
|
||||
.locals 1
|
||||
|
||||
:try_start_0
|
||||
iget-object v0, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
|
||||
|
||||
invoke-virtual {v0, p0}, Landroid/content/Context;->unbindService(Landroid/content/ServiceConnection;)V
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
|
||||
|
||||
goto :return
|
||||
|
||||
:catch_0
|
||||
move-exception v0
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private static writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
|
||||
.locals 2
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
if-eqz p1, :null_value
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
invoke-virtual {p0, v1}, Landroid/os/Parcel;->writeInt(I)V
|
||||
|
||||
invoke-interface {p1, p0, v0}, Landroid/os/Parcelable;->writeToParcel(Landroid/os/Parcel;I)V
|
||||
|
||||
return-void
|
||||
|
||||
:null_value
|
||||
invoke-virtual {p0, v0}, Landroid/os/Parcel;->writeInt(I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V
|
||||
.locals 1
|
||||
|
||||
:try_start_0
|
||||
invoke-direct {p0, p2}, Lradiant/WazeServiceConnection;->register(Landroid/os/IBinder;)V
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
|
||||
|
||||
goto :unbind
|
||||
|
||||
:catch_0
|
||||
move-exception v0
|
||||
|
||||
:unbind
|
||||
invoke-direct {p0}, Lradiant/WazeServiceConnection;->safeUnbind()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public onServiceDisconnected(Landroid/content/ComponentName;)V
|
||||
.locals 0
|
||||
|
||||
return-void
|
||||
.end method
|
||||
+58
-13
@@ -18,7 +18,6 @@
|
||||
"PlayerBackdrop",
|
||||
"QualityBadgeColors",
|
||||
"LyricsProgressPill",
|
||||
"CoverEverywhere",
|
||||
"MiniPlayerRedesign"
|
||||
]
|
||||
},
|
||||
@@ -35,14 +34,14 @@
|
||||
"order": 30,
|
||||
"fileNames": ["player-backdrop.patch"],
|
||||
"title": "Player Backdrop",
|
||||
"description": "Restores the legacy translucent backdrop blur behind the player.",
|
||||
"description": "Restores the legacy translucent backdrop blur behind the player",
|
||||
"default": true,
|
||||
"advancedOptions": [
|
||||
{
|
||||
"type": "slider",
|
||||
"key": "blur_strength",
|
||||
"title": "Blur Strength",
|
||||
"description": "How strongly the album art behind the player is blurred. 0% is sharp, 50% matches the original look.",
|
||||
"description": "How strongly the album art behind the player is blurred",
|
||||
"default": 50,
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
@@ -55,7 +54,7 @@
|
||||
"type": "slider",
|
||||
"key": "dimming",
|
||||
"title": "Backdrop Dimming",
|
||||
"description": "Darkens the backdrop so the foreground controls stay legible.",
|
||||
"description": "Darkens the backdrop so the foreground controls stay legible",
|
||||
"default": 50,
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
@@ -63,17 +62,18 @@
|
||||
"displayAsPercent": true,
|
||||
"token": "RL_SCRIM_ARGB",
|
||||
"encode": { "kind": "argbAlpha" }
|
||||
},
|
||||
{
|
||||
"type": "toggle",
|
||||
"key": "cover_everywhere",
|
||||
"title": "Cover Everywhere - WIP",
|
||||
"description": "Applies the blurred backdrop to every Compose based page (Home & Collection)",
|
||||
"default": false,
|
||||
"inline": true,
|
||||
"fileNames": ["home-backdrop.patch", "collection-backdrop.patch", "cover-capture.patch"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CoverEverywhere",
|
||||
"order": 35,
|
||||
"fileNames": ["home-backdrop.patch", "collection-backdrop.patch", "cover-capture.patch"],
|
||||
"title": "Cover Everywhere - WIP",
|
||||
"description": "Applies the blurred backdrop to every Compose based page (Home & Collection)",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"id": "QualityBadgeColors",
|
||||
"order": 36,
|
||||
@@ -163,16 +163,28 @@
|
||||
"type": "toggle",
|
||||
"key": "gestures",
|
||||
"title": "Mini-Player Gestures",
|
||||
"description": "Swipe up on the mini-player to open the full player.",
|
||||
"description": "Adds swipe up gesture to the mini-player to reopen the player",
|
||||
"default": true,
|
||||
"fileNames": ["mini-player-gestures.patch"],
|
||||
"extensionFiles": [
|
||||
"radiant/MiniPlayerGestures.smali",
|
||||
"radiant/MiniPlayerGestures$Gesture.smali",
|
||||
"radiant/MiniPlayerGestures$FeedbackLayer.smali",
|
||||
"radiant/MiniPlayerGestures$FeedbackResetAnimator.smali",
|
||||
"radiant/MiniPlayerGestures$RootGesture.smali",
|
||||
"radiant/MiniPlayerGestures$ApplyPending.smali"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "choice",
|
||||
"key": "swipe_up_drag",
|
||||
"title": "Swipe Up Style",
|
||||
"entries": ["Static", "Drag"],
|
||||
"values": ["0x0", "0x1"],
|
||||
"defaultIndex": 1,
|
||||
"requiresOption": "gestures",
|
||||
"token": "RL_MINI_PLAYER_SWIPE_UP_DRAG"
|
||||
},
|
||||
{
|
||||
"type": "toggle",
|
||||
"key": "next_prev",
|
||||
@@ -200,6 +212,39 @@
|
||||
"description": "Inverts the auto-hide behavior on the lyrics screen, playback controls stay visible by default and only hide when you tap them off.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"id": "WazeIntegration",
|
||||
"order": 90,
|
||||
"category": "integration",
|
||||
"pathLocked": true,
|
||||
"fileNames": ["waze-media-browser.patch"],
|
||||
"extensionFiles": ["radiant/WazeInitReceiver.smali", "radiant/WazeServiceConnection.smali"],
|
||||
"title": "Waze Integration",
|
||||
"description": "Control TIDAL playback from the Waze app",
|
||||
"default": true,
|
||||
"advancedOptions": [
|
||||
{
|
||||
"type": "choice",
|
||||
"key": "browse_root",
|
||||
"title": "Media Menu",
|
||||
"entries": ["Auto Menu", "Home", "Recents"],
|
||||
"values": [
|
||||
"ROOT_AUTO",
|
||||
"HOME_V2::home_page_v2_id",
|
||||
"RECENTLY_PLAYED::home/pages/CONTINUE_LISTEN_TO/view-all"
|
||||
],
|
||||
"defaultIndex": 0,
|
||||
"token": "RL_WAZE_ROOT_ID"
|
||||
},
|
||||
{
|
||||
"type": "color",
|
||||
"key": "accent_color",
|
||||
"title": "Accent Color",
|
||||
"default": -16747037,
|
||||
"token": "RL_WAZE_THEME_COLOR"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "DebugMenuUnlock",
|
||||
"order": 100,
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
--- a/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
|
||||
+++ b/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
|
||||
@@ -1746,6 +1746,10 @@
|
||||
invoke-static {v9, v10, v15, v6, v8}, Landroidx/compose/foundation/layout/PaddingKt;->padding-qDBjuR0(Landroidx/compose/ui/Modifier;FFFF)Landroidx/compose/ui/Modifier;
|
||||
|
||||
@@ -1768,3 +1768,7 @@
|
||||
move-result-object v6
|
||||
-
|
||||
+
|
||||
+ invoke-static {v6, v1}, Lradiant/MiniPlayerTrackGestures;->trackModifier(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier; # attach horizontal swipe listener
|
||||
+
|
||||
+ move-result-object v6
|
||||
|
||||
+
|
||||
.line 38
|
||||
sget-object v21, Landroidx/compose/ui/Alignment;->Companion:Landroidx/compose/ui/Alignment$Companion;
|
||||
@@ -1884,5 +1888,5 @@
|
||||
.line 56
|
||||
iget-object v6, v0, Lcom/tidal/android/feature/appscaffold/ui/s;->b:Lcom/tidal/android/feature/appscaffold/ui/p;
|
||||
|
||||
@@ -1,41 +1,10 @@
|
||||
--- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali
|
||||
+++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali
|
||||
@@ -2832,27 +2832,5 @@
|
||||
- .line 150
|
||||
- sget-object v8, Lkotlin/u;->a:Lkotlin/u;
|
||||
-
|
||||
- .line 151
|
||||
- invoke-interface {v15}, Landroidx/compose/runtime/Composer;->rememberedValue()Ljava/lang/Object;
|
||||
-
|
||||
- move-result-object v10
|
||||
-
|
||||
- .line 152
|
||||
- invoke-virtual/range {v22 .. v22}, Landroidx/compose/runtime/Composer$Companion;->getEmpty()Ljava/lang/Object;
|
||||
-
|
||||
- move-result-object v11
|
||||
-
|
||||
- if-ne v10, v11, :cond_48
|
||||
-
|
||||
- .line 153
|
||||
- sget-object v10, Lcom/tidal/android/feature/appscaffold/ui/composable/AppScaffoldKt$AppScaffold$3$2$1$1;->a:Lcom/tidal/android/feature/appscaffold/ui/composable/AppScaffoldKt$AppScaffold$3$2$1$1;
|
||||
-
|
||||
- invoke-interface {v15, v10}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V
|
||||
-
|
||||
- .line 154
|
||||
- :cond_48
|
||||
- check-cast v10, Landroidx/compose/ui/input/pointer/PointerInputEventHandler;
|
||||
-
|
||||
- invoke-static {v0, v8, v10}, Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->pointerInput(Landroidx/compose/ui/Modifier;Ljava/lang/Object;Landroidx/compose/ui/input/pointer/PointerInputEventHandler;)Landroidx/compose/ui/Modifier;
|
||||
+ move-object/from16 v8, v25 # SheetState from AppScaffold
|
||||
+
|
||||
+ invoke-static {v0, v6, v8}, Lradiant/MiniPlayerGestures;->modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier; # attach swipe up listener
|
||||
|
||||
move-result-object v0
|
||||
@@ -2427,6 +2406,12 @@
|
||||
@@ -2427,6 +2427,12 @@
|
||||
move-object/from16 v16, v9
|
||||
|
||||
.line 99
|
||||
+ move-object/from16 v9, v25 # same SheetState used by the modal sheet
|
||||
+ move-object/from16 v9, v25 # SheetState
|
||||
+
|
||||
+ invoke-static {v5, v6, v9}, Lradiant/MiniPlayerGestures;->rootModifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier; # continue drag after player recomposition
|
||||
+
|
||||
@@ -44,7 +13,15 @@
|
||||
invoke-static {v15, v5}, Landroidx/compose/ui/ComposedModifierKt;->materializeModifier(Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
|
||||
|
||||
move-result-object v9
|
||||
|
||||
@@ -2832,2 +2838,8 @@
|
||||
+ move-object/from16 v8, v25 # SheetState from AppScaffold
|
||||
+
|
||||
+ const/4 v10, __RL_MINI_PLAYER_SWIPE_UP_DRAG__ # Enable Drag option
|
||||
+
|
||||
+ invoke-static {v6, v8, v10}, Lradiant/MiniPlayerGestures;->configure(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
|
||||
+
|
||||
.line 150
|
||||
sget-object v8, Lkotlin/u;->a:Lkotlin/u;
|
||||
--- a/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
|
||||
+++ b/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
|
||||
@@ -1243,5 +1243,21 @@
|
||||
@@ -67,9 +44,30 @@
|
||||
+
|
||||
+ :rl_set_media
|
||||
+ invoke-static {v5}, Lradiant/MiniPlayerGestures;->setHasMiniPlayerMedia(Z)V
|
||||
|
||||
-
|
||||
+
|
||||
invoke-virtual {v1}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
|
||||
|
||||
@@ -1750,2 +1766,6 @@
|
||||
+ invoke-static {v6}, Lradiant/MiniPlayerGestures;->trackAreaModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # attach swipe up listener
|
||||
+
|
||||
+ move-result-object v6
|
||||
+
|
||||
.line 38
|
||||
sget-object v21, Landroidx/compose/ui/Alignment;->Companion:Landroidx/compose/ui/Alignment$Companion;
|
||||
@@ -1923,2 +1943,6 @@
|
||||
+ invoke-static {v4}, Lradiant/MiniPlayerGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move cover (swipe up feedback)
|
||||
+
|
||||
+ move-result-object v4
|
||||
+
|
||||
.line 63
|
||||
invoke-virtual/range {v22 .. v22}, Lcom/squareup/ui/market/core/theme/MarketStylesheet$c;->p0()Lc20/a;
|
||||
@@ -2034,2 +2058,6 @@
|
||||
+ invoke-static {v4}, Lradiant/MiniPlayerGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move title/artist (swipe up feedback)
|
||||
+
|
||||
+ move-result-object v4
|
||||
+
|
||||
.line 72
|
||||
invoke-virtual/range {p2 .. p2}, Landroidx/compose/foundation/layout/Arrangement;->getTop()Landroidx/compose/foundation/layout/Arrangement$Vertical;
|
||||
--- a/androidx/compose/material3/ModalBottomSheetKt$ModalBottomSheet$4$1.smali
|
||||
+++ b/androidx/compose/material3/ModalBottomSheetKt$ModalBottomSheet$4$1.smali
|
||||
@@ -210,8 +210,10 @@
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
--- a/pb/c.smali
|
||||
+++ b/pb/c.smali
|
||||
@@ -801,6 +801,26 @@
|
||||
-
|
||||
+
|
||||
.line 236
|
||||
:goto_8
|
||||
+ const-string/jumbo v5, "com.waze"
|
||||
+
|
||||
+ invoke-static {v3, v5}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # package match
|
||||
+
|
||||
+ move-result v5
|
||||
+
|
||||
+ if-eqz v5, :rl_waze_done
|
||||
+
|
||||
+ const-string/jumbo v5, "03:63:7f:6c:5d:8f:60:4e:6f:db:79:a6:ff:bf:a5:78:de:4e:31:8f:8d:a2:2f:c6:10:66:65:24:7f:88:07:d7" # Waze cert
|
||||
+
|
||||
+ invoke-static {v2, v5}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # cert match
|
||||
+
|
||||
+ move-result v5
|
||||
+
|
||||
+ if-eqz v5, :rl_waze_done
|
||||
+
|
||||
+ goto :goto_9 # trust Waze
|
||||
+
|
||||
+ :rl_waze_done
|
||||
+
|
||||
invoke-static {}, Landroid/os/Process;->myUid()I
|
||||
-
|
||||
+
|
||||
.line 237
|
||||
@@ -957,6 +977,26 @@
|
||||
:goto_b
|
||||
if-eqz v2, :cond_14
|
||||
-
|
||||
+
|
||||
+ const-string/jumbo v1, "com.waze"
|
||||
+
|
||||
+ invoke-static {v3, v1}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # package match
|
||||
+
|
||||
+ move-result v1
|
||||
+
|
||||
+ if-eqz v1, :rl_waze_recent_root_done_2
|
||||
+
|
||||
+ new-instance v1, Landroidx/media/MediaBrowserServiceCompat$BrowserRoot;
|
||||
+
|
||||
+ const-string/jumbo v4, "__RL_WAZE_ROOT_ID__"
|
||||
+
|
||||
+ const/4 v5, 0x0
|
||||
+
|
||||
+ invoke-direct {v1, v4, v5}, Landroidx/media/MediaBrowserServiceCompat$BrowserRoot;-><init>(Ljava/lang/String;Landroid/os/Bundle;)V
|
||||
+
|
||||
+ return-object v1
|
||||
+
|
||||
+ :rl_waze_recent_root_done_2
|
||||
+
|
||||
.line 306
|
||||
.line 307
|
||||
iget-object v1, v0, Lpb/c;->c:Ljava/util/Map;
|
||||
Reference in New Issue
Block a user