mirror of
https://github.com/meowarex/rl-mobile.git
synced 2026-06-18 05:23:12 +10:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d9de3207f5 | |||
| 59fe232ae4 | |||
| e105a3eb35 | |||
| e7b69a8deb | |||
| 324a6eb6c8 | |||
| c5962ad1a8 | |||
| 77ab041b97 |
@@ -48,6 +48,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mv ./dist/app-release.apk ./dist/rl-manager.apk
|
mv ./dist/app-release.apk ./dist/rl-manager.apk
|
||||||
cp patches/data.json ./dist/data.json
|
cp patches/data.json ./dist/data.json
|
||||||
|
# Point each release's data.json at its own assets so historical releases stay self-contained.
|
||||||
|
sed -i "s|releases/download/latest/|releases/download/v${{ needs.Version.outputs.version }}/|g" ./dist/data.json
|
||||||
cd patches && zip -r ../dist/patches.zip . -x "data.json" && cd ..
|
cd patches && zip -r ../dist/patches.zip . -x "data.json" && cd ..
|
||||||
|
|
||||||
tidal_src=$(find tidal-apk -maxdepth 1 \( -name "*.apk" -o -name "*.apkm" \) | head -1)
|
tidal_src=$(find tidal-apk -maxdepth 1 \( -name "*.apk" -o -name "*.apkm" \) | head -1)
|
||||||
@@ -58,7 +60,7 @@ jobs:
|
|||||||
if [[ "$tidal_src" == *.apkm ]]; then
|
if [[ "$tidal_src" == *.apkm ]]; then
|
||||||
echo "Merging splits from $tidal_src via APKEditor"
|
echo "Merging splits from $tidal_src via APKEditor"
|
||||||
curl --fail --location --retry 3 --retry-delay 2 -sSo /tmp/APKEditor.jar \
|
curl --fail --location --retry 3 --retry-delay 2 -sSo /tmp/APKEditor.jar \
|
||||||
https://github.com/REAndroid/APKEditor/releases/download/V1.4.3/APKEditor-1.4.3.jar
|
https://github.com/REAndroid/APKEditor/releases/download/V1.4.9/APKEditor-1.4.9.jar
|
||||||
java -jar /tmp/APKEditor.jar m -i "$tidal_src" -o ./dist/tidal-stock.apk
|
java -jar /tmp/APKEditor.jar m -i "$tidal_src" -o ./dist/tidal-stock.apk
|
||||||
echo "Merged tidal-stock.apk:"
|
echo "Merged tidal-stock.apk:"
|
||||||
ls -la ./dist/tidal-stock.apk
|
ls -la ./dist/tidal-stock.apk
|
||||||
@@ -67,10 +69,10 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: marvinpinto/action-automatic-releases@latest
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
tag_name: v${{ needs.Version.outputs.version }}
|
||||||
automatic_release_tag: latest
|
name: v${{ needs.Version.outputs.version }}
|
||||||
prerelease: false
|
prerelease: false
|
||||||
title: v${{ needs.Version.outputs.version }}
|
make_latest: "true"
|
||||||
files: ./dist/**
|
files: ./dist/**
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val targetDir = when (componentType) {
|
val targetDir = when (componentType) {
|
||||||
"injector" -> paths.customInjectorsDir
|
"tidal" -> paths.customTidalApksDir
|
||||||
"patches" -> paths.customPatchesDir
|
"patches" -> paths.customPatchesDir
|
||||||
else -> {
|
else -> {
|
||||||
Log.w(BuildConfig.TAG, "Extra $EXTRA_COMPONENT_TYPE is not a valid value!")
|
Log.w(BuildConfig.TAG, "Extra $EXTRA_COMPONENT_TYPE is not a valid value!")
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class PathManager(
|
|||||||
|
|
||||||
val customComponentsDir = patchingDir.resolve("custom")
|
val customComponentsDir = patchingDir.resolve("custom")
|
||||||
|
|
||||||
val customInjectorsDir = customComponentsDir.resolve("injector")
|
val customTidalApksDir = customComponentsDir.resolve("tidal")
|
||||||
|
|
||||||
val customPatchesDir = customComponentsDir.resolve("patches")
|
val customPatchesDir = customComponentsDir.resolve("patches")
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ class PathManager(
|
|||||||
.resolve("patches")
|
.resolve("patches")
|
||||||
.resolve("$version.zip")
|
.resolve("$version.zip")
|
||||||
|
|
||||||
fun customInjectors() = customInjectorsDir.listFiles()?.asList() ?: emptyList()
|
fun customTidalApks() = customTidalApksDir.listFiles()?.asList() ?: emptyList()
|
||||||
|
|
||||||
fun customSmaliPatches() = customPatchesDir.listFiles()?.asList() ?: emptyList()
|
fun customSmaliPatches() = customPatchesDir.listFiles()?.asList() ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager
|
|||||||
var devMode by booleanPreference("dev_mode", false)
|
var devMode by booleanPreference("dev_mode", false)
|
||||||
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PackageInstaller)
|
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PackageInstaller)
|
||||||
var keepPatchedApks by booleanPreference("keep_patched_apks", false)
|
var keepPatchedApks by booleanPreference("keep_patched_apks", false)
|
||||||
var showNetworkWarning by booleanPreference("show_network_warning", true)
|
|
||||||
var showPlayProtectWarning by booleanPreference("show_play_protect_warning", true)
|
var showPlayProtectWarning by booleanPreference("show_play_protect_warning", true)
|
||||||
var autoUpdateCheck by booleanPreference("auto_update_check", true)
|
var autoUpdateCheck by booleanPreference("auto_update_check", true)
|
||||||
|
|
||||||
|
var lastSeenManagerVersion by stringPreference("last_seen_manager_version", "")
|
||||||
|
var lastSeenPatchesVersion by stringPreference("last_seen_patches_version", "")
|
||||||
|
var lastSeenTidalVersionCode by intPreference("last_seen_tidal_version_code", -1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class TidalPatchRunner(
|
|||||||
RestoreDownloadsStep(),
|
RestoreDownloadsStep(),
|
||||||
|
|
||||||
// Download
|
// Download
|
||||||
DownloadTidalStep(),
|
DownloadTidalStep(options.customTidalApk),
|
||||||
DownloadPatchesStep(options.customPatches),
|
DownloadPatchesStep(options.customPatches),
|
||||||
CopyDependenciesStep(),
|
CopyDependenciesStep(),
|
||||||
|
|
||||||
|
|||||||
+25
-2
@@ -5,12 +5,17 @@ import com.meowarex.rlmobile.R
|
|||||||
import com.meowarex.rlmobile.manager.PathManager
|
import com.meowarex.rlmobile.manager.PathManager
|
||||||
import com.meowarex.rlmobile.patcher.StepRunner
|
import com.meowarex.rlmobile.patcher.StepRunner
|
||||||
import com.meowarex.rlmobile.patcher.steps.base.DownloadStep
|
import com.meowarex.rlmobile.patcher.steps.base.DownloadStep
|
||||||
|
import com.meowarex.rlmobile.patcher.steps.base.StepState
|
||||||
import com.meowarex.rlmobile.patcher.steps.prepare.FetchInfoStep
|
import com.meowarex.rlmobile.patcher.steps.prepare.FetchInfoStep
|
||||||
|
import com.meowarex.rlmobile.ui.screens.componentopts.PatchComponent
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class DownloadTidalStep : DownloadStep<Int>(), KoinComponent {
|
class DownloadTidalStep(
|
||||||
|
private val custom: PatchComponent?,
|
||||||
|
) : DownloadStep<Int>(), KoinComponent {
|
||||||
private val paths: PathManager by inject()
|
private val paths: PathManager by inject()
|
||||||
|
|
||||||
override val localizedName = R.string.patch_step_dl_tidal_apk
|
override val localizedName = R.string.patch_step_dl_tidal_apk
|
||||||
@@ -22,5 +27,23 @@ class DownloadTidalStep : DownloadStep<Int>(), KoinComponent {
|
|||||||
container.getStep<FetchInfoStep>().data.tidalApkUrl
|
container.getStep<FetchInfoStep>().data.tidalApkUrl
|
||||||
|
|
||||||
override fun getStoredFile(container: StepRunner) =
|
override fun getStoredFile(container: StepRunner) =
|
||||||
paths.cachedTidalApk(getVersion(container))
|
custom?.getFile(paths) ?: paths.cachedTidalApk(getVersion(container))
|
||||||
|
|
||||||
|
override suspend fun execute(container: StepRunner) {
|
||||||
|
if (custom != null) {
|
||||||
|
container.log("Using custom TIDAL APK with version ${custom.version} imported ${custom.timestamp}")
|
||||||
|
|
||||||
|
if (!custom.getFile(paths).exists()) {
|
||||||
|
throw FileNotFoundException(
|
||||||
|
"Selected custom TIDAL APK does not exist on disk! If this is an update, " +
|
||||||
|
"updates cannot occur when the originally selected custom component has been deleted."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
state = StepState.Skipped
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
super.execute(container)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.meowarex.rlmobile.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Tag(text: String) {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
shape = RoundedCornerShape(6.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 3.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
-96
@@ -1,96 +0,0 @@
|
|||||||
package com.meowarex.rlmobile.ui.components.dialogs
|
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.material3.*
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
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.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.window.DialogProperties
|
|
||||||
import com.meowarex.rlmobile.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun NetworkWarningDialog(
|
|
||||||
onConfirm: (neverShow: Boolean) -> Unit,
|
|
||||||
onDismiss: (neverShow: Boolean) -> Unit,
|
|
||||||
) {
|
|
||||||
val interactionSource = remember(::MutableInteractionSource)
|
|
||||||
var neverShow by rememberSaveable { mutableStateOf(false) }
|
|
||||||
val rememberedNeverShow by rememberUpdatedState(neverShow)
|
|
||||||
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { onDismiss(rememberedNeverShow) },
|
|
||||||
properties = DialogProperties(
|
|
||||||
dismissOnClickOutside = false,
|
|
||||||
),
|
|
||||||
confirmButton = {
|
|
||||||
FilledTonalButton(
|
|
||||||
onClick = { onConfirm(rememberedNeverShow) },
|
|
||||||
colors = ButtonDefaults.filledTonalButtonColors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.error,
|
|
||||||
contentColor = MaterialTheme.colorScheme.onError,
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.action_continue))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(
|
|
||||||
onClick = { onDismiss(rememberedNeverShow) },
|
|
||||||
colors = ButtonDefaults.textButtonColors(
|
|
||||||
contentColor = MaterialTheme.colorScheme.onErrorContainer
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.navigation_back))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title = { Text(stringResource(R.string.network_warning_title)) },
|
|
||||||
text = {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.network_warning_body),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable(
|
|
||||||
interactionSource = interactionSource,
|
|
||||||
indication = null,
|
|
||||||
onClick = { neverShow = !rememberedNeverShow },
|
|
||||||
)
|
|
||||||
.padding(end = 16.dp)
|
|
||||||
) {
|
|
||||||
Checkbox(
|
|
||||||
checked = neverShow,
|
|
||||||
onCheckedChange = { neverShow = it },
|
|
||||||
interactionSource = interactionSource,
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(stringResource(R.string.network_warning_disable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon = {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_warning),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(32.dp),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
containerColor = MaterialTheme.colorScheme.errorContainer,
|
|
||||||
iconContentColor = MaterialTheme.colorScheme.onErrorContainer,
|
|
||||||
titleContentColor = MaterialTheme.colorScheme.onErrorContainer,
|
|
||||||
textContentColor = MaterialTheme.colorScheme.onErrorContainer,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
package com.meowarex.rlmobile.ui.previews.dialogs
|
|
||||||
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import com.meowarex.rlmobile.ui.components.dialogs.NetworkWarningDialog
|
|
||||||
import com.meowarex.rlmobile.ui.theme.ManagerTheme
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
|
||||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
|
||||||
private fun NetworkWarningDialogPreview() {
|
|
||||||
ManagerTheme {
|
|
||||||
NetworkWarningDialog(
|
|
||||||
onConfirm = {},
|
|
||||||
onDismiss = {},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+12
-6
@@ -30,6 +30,12 @@ private fun ComponentOptionsScreenPreview(
|
|||||||
selected = parameters.selected,
|
selected = parameters.selected,
|
||||||
onSelectComponent = {},
|
onSelectComponent = {},
|
||||||
onDeleteComponent = {},
|
onDeleteComponent = {},
|
||||||
|
onImportFromUri = {},
|
||||||
|
releasesExpanded = false,
|
||||||
|
releasesState = com.meowarex.rlmobile.ui.screens.componentopts.ComponentOptionsModel.ReleasesState.Idle,
|
||||||
|
onToggleReleases = {},
|
||||||
|
onImportRelease = {},
|
||||||
|
importingReleaseTag = null,
|
||||||
onBackPressed = {},
|
onBackPressed = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -44,27 +50,27 @@ private data class ComponentOptionsParameters(
|
|||||||
private class ComponentOptionsParametersProvider : PreviewParameterProvider<ComponentOptionsParameters> {
|
private class ComponentOptionsParametersProvider : PreviewParameterProvider<ComponentOptionsParameters> {
|
||||||
private val components = persistentListOf(
|
private val components = persistentListOf(
|
||||||
PatchComponent(
|
PatchComponent(
|
||||||
type = PatchComponent.Type.Injector,
|
type = PatchComponent.Type.TidalApk,
|
||||||
version = SemVer(1, 2, 3),
|
version = SemVer(1, 2, 3),
|
||||||
timestamp = Clock.System.now(),
|
timestamp = Clock.System.now(),
|
||||||
),
|
),
|
||||||
PatchComponent(
|
PatchComponent(
|
||||||
type = PatchComponent.Type.Injector,
|
type = PatchComponent.Type.TidalApk,
|
||||||
version = SemVer(2, 3, 1),
|
version = SemVer(2, 3, 1),
|
||||||
timestamp = Clock.System.now() - 10.minutes,
|
timestamp = Clock.System.now() - 10.minutes,
|
||||||
),
|
),
|
||||||
PatchComponent(
|
PatchComponent(
|
||||||
type = PatchComponent.Type.Injector,
|
type = PatchComponent.Type.TidalApk,
|
||||||
version = SemVer(2, 3, 1),
|
version = SemVer(2, 3, 1),
|
||||||
timestamp = Clock.System.now() - 1.days,
|
timestamp = Clock.System.now() - 1.days,
|
||||||
),
|
),
|
||||||
PatchComponent(
|
PatchComponent(
|
||||||
type = PatchComponent.Type.Injector,
|
type = PatchComponent.Type.TidalApk,
|
||||||
version = SemVer(0, 0, 1),
|
version = SemVer(0, 0, 1),
|
||||||
timestamp = Clock.System.now() - 10.hours,
|
timestamp = Clock.System.now() - 10.hours,
|
||||||
),
|
),
|
||||||
PatchComponent(
|
PatchComponent(
|
||||||
type = PatchComponent.Type.Injector,
|
type = PatchComponent.Type.TidalApk,
|
||||||
version = SemVer(3, 0, 2),
|
version = SemVer(3, 0, 2),
|
||||||
timestamp = Clock.System.now() - 7.days,
|
timestamp = Clock.System.now() - 7.days,
|
||||||
),
|
),
|
||||||
@@ -72,7 +78,7 @@ private class ComponentOptionsParametersProvider : PreviewParameterProvider<Comp
|
|||||||
|
|
||||||
override val values = sequenceOf(
|
override val values = sequenceOf(
|
||||||
ComponentOptionsParameters(
|
ComponentOptionsParameters(
|
||||||
componentType = PatchComponent.Type.Injector,
|
componentType = PatchComponent.Type.TidalApk,
|
||||||
components = components,
|
components = components,
|
||||||
selected = null,
|
selected = null,
|
||||||
),
|
),
|
||||||
|
|||||||
+7
-7
@@ -30,8 +30,8 @@ private fun PatchOptionsScreenPreview(
|
|||||||
packageName = parameters.packageName,
|
packageName = parameters.packageName,
|
||||||
packageNameState = parameters.packageNameState,
|
packageNameState = parameters.packageNameState,
|
||||||
setPackageName = {},
|
setPackageName = {},
|
||||||
customInjector = parameters.customInjector,
|
customTidalApk = parameters.customTidalApk,
|
||||||
onSelectCustomInjector = {},
|
onSelectCustomTidalApk = {},
|
||||||
customPatches = parameters.customPatches,
|
customPatches = parameters.customPatches,
|
||||||
onSelectCustomPatches = {},
|
onSelectCustomPatches = {},
|
||||||
enabledPatchCount = KnownPatch.All.size,
|
enabledPatchCount = KnownPatch.All.size,
|
||||||
@@ -51,7 +51,7 @@ private data class PatchOptionsParameters(
|
|||||||
val appNameIsError: Boolean,
|
val appNameIsError: Boolean,
|
||||||
val packageName: String,
|
val packageName: String,
|
||||||
val packageNameState: PackageNameState,
|
val packageNameState: PackageNameState,
|
||||||
val customInjector: PatchComponent?,
|
val customTidalApk: PatchComponent?,
|
||||||
val customPatches: PatchComponent?,
|
val customPatches: PatchComponent?,
|
||||||
val isConfigValid: Boolean,
|
val isConfigValid: Boolean,
|
||||||
)
|
)
|
||||||
@@ -66,7 +66,7 @@ private class PatchOptionsParametersProvider : PreviewParameterProvider<PatchOpt
|
|||||||
appNameIsError = false,
|
appNameIsError = false,
|
||||||
packageName = PatchOptions.Default.packageName,
|
packageName = PatchOptions.Default.packageName,
|
||||||
packageNameState = PackageNameState.Ok,
|
packageNameState = PackageNameState.Ok,
|
||||||
customInjector = null,
|
customTidalApk = null,
|
||||||
customPatches = null,
|
customPatches = null,
|
||||||
isConfigValid = true,
|
isConfigValid = true,
|
||||||
),
|
),
|
||||||
@@ -78,7 +78,7 @@ private class PatchOptionsParametersProvider : PreviewParameterProvider<PatchOpt
|
|||||||
appNameIsError = true,
|
appNameIsError = true,
|
||||||
packageName = "a b",
|
packageName = "a b",
|
||||||
packageNameState = PackageNameState.Invalid,
|
packageNameState = PackageNameState.Invalid,
|
||||||
customInjector = null,
|
customTidalApk = null,
|
||||||
customPatches = null,
|
customPatches = null,
|
||||||
isConfigValid = false,
|
isConfigValid = false,
|
||||||
),
|
),
|
||||||
@@ -90,8 +90,8 @@ private class PatchOptionsParametersProvider : PreviewParameterProvider<PatchOpt
|
|||||||
appNameIsError = false,
|
appNameIsError = false,
|
||||||
packageName = PatchOptions.Default.packageName,
|
packageName = PatchOptions.Default.packageName,
|
||||||
packageNameState = PackageNameState.Taken,
|
packageNameState = PackageNameState.Taken,
|
||||||
customInjector = PatchComponent(
|
customTidalApk = PatchComponent(
|
||||||
type = PatchComponent.Type.Injector,
|
type = PatchComponent.Type.TidalApk,
|
||||||
version = SemVer(1, 2, 3),
|
version = SemVer(1, 2, 3),
|
||||||
timestamp = Clock.System.now(),
|
timestamp = Clock.System.now(),
|
||||||
),
|
),
|
||||||
|
|||||||
+169
-1
@@ -1,26 +1,44 @@
|
|||||||
package com.meowarex.rlmobile.ui.screens.componentopts
|
package com.meowarex.rlmobile.ui.screens.componentopts
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.OpenableColumns
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
|
import com.meowarex.rlmobile.BuildConfig
|
||||||
import com.meowarex.rlmobile.R
|
import com.meowarex.rlmobile.R
|
||||||
import com.meowarex.rlmobile.manager.PathManager
|
import com.meowarex.rlmobile.manager.PathManager
|
||||||
|
import com.meowarex.rlmobile.manager.download.KtorDownloadManager
|
||||||
|
import com.meowarex.rlmobile.network.models.GithubRelease
|
||||||
|
import com.meowarex.rlmobile.network.services.RadiantLyricsGithubService
|
||||||
import com.meowarex.rlmobile.network.utils.SemVer
|
import com.meowarex.rlmobile.network.utils.SemVer
|
||||||
|
import com.meowarex.rlmobile.network.utils.fold
|
||||||
import com.meowarex.rlmobile.ui.util.ScreenModelWithResult
|
import com.meowarex.rlmobile.ui.util.ScreenModelWithResult
|
||||||
import com.meowarex.rlmobile.ui.util.ScreenResultKey
|
import com.meowarex.rlmobile.ui.util.ScreenResultKey
|
||||||
import com.meowarex.rlmobile.util.*
|
import com.meowarex.rlmobile.util.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
class ComponentOptionsModel(
|
class ComponentOptionsModel(
|
||||||
screenResultKey: ScreenResultKey,
|
screenResultKey: ScreenResultKey,
|
||||||
private val paths: PathManager,
|
private val paths: PathManager,
|
||||||
private val context: Application,
|
private val context: Application,
|
||||||
|
private val github: RadiantLyricsGithubService,
|
||||||
|
private val downloader: KtorDownloadManager,
|
||||||
) : ScreenModelWithResult<PatchComponent?>(screenResultKey) {
|
) : ScreenModelWithResult<PatchComponent?>(screenResultKey) {
|
||||||
val components = mutableStateListOf<PatchComponent>()
|
val components = mutableStateListOf<PatchComponent>()
|
||||||
var selected by mutableStateOf<PatchComponent?>(null)
|
var selected by mutableStateOf<PatchComponent?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var releasesExpanded by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
var releasesState by mutableStateOf<ReleasesState>(ReleasesState.Idle)
|
||||||
|
private set
|
||||||
|
var importingReleaseTag by mutableStateOf<String?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
fun selectComponent(component: PatchComponent?) {
|
fun selectComponent(component: PatchComponent?) {
|
||||||
selected = component
|
selected = component
|
||||||
}
|
}
|
||||||
@@ -39,7 +57,7 @@ class ComponentOptionsModel(
|
|||||||
*/
|
*/
|
||||||
suspend fun refreshComponents(type: PatchComponent.Type) {
|
suspend fun refreshComponents(type: PatchComponent.Type) {
|
||||||
val files = when (type) {
|
val files = when (type) {
|
||||||
PatchComponent.Type.Injector -> paths.customInjectors()
|
PatchComponent.Type.TidalApk -> paths.customTidalApks()
|
||||||
PatchComponent.Type.Patches -> paths.customSmaliPatches()
|
PatchComponent.Type.Patches -> paths.customSmaliPatches()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +82,157 @@ class ComponentOptionsModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun importFromUri(uri: Uri, type: PatchComponent.Type) = screenModelScope.launchIO {
|
||||||
|
try {
|
||||||
|
val targetDir = when (type) {
|
||||||
|
PatchComponent.Type.TidalApk -> paths.customTidalApksDir
|
||||||
|
PatchComponent.Type.Patches -> paths.customPatchesDir
|
||||||
|
}
|
||||||
|
val ext = when (type) {
|
||||||
|
PatchComponent.Type.TidalApk -> "apk"
|
||||||
|
PatchComponent.Type.Patches -> "zip"
|
||||||
|
}
|
||||||
|
targetDir.mkdirs()
|
||||||
|
|
||||||
|
val tempFile = targetDir.resolve("import-${System.currentTimeMillis()}.tmp")
|
||||||
|
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||||
|
tempFile.outputStream().use { output -> input.copyTo(output) }
|
||||||
|
} ?: throw IllegalStateException("Could not open input stream for $uri")
|
||||||
|
|
||||||
|
val sourceDisplayName = queryDisplayName(uri)
|
||||||
|
val version = when (type) {
|
||||||
|
PatchComponent.Type.TidalApk -> readApkVersion(tempFile)
|
||||||
|
?: extractVersionFromName(sourceDisplayName)
|
||||||
|
?: FALLBACK_VERSION
|
||||||
|
PatchComponent.Type.Patches -> extractVersionFromName(sourceDisplayName)
|
||||||
|
?: FALLBACK_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
val finalName = "${System.currentTimeMillis()}_$version.$ext"
|
||||||
|
val finalFile = targetDir.resolve(finalName)
|
||||||
|
if (!tempFile.renameTo(finalFile)) {
|
||||||
|
tempFile.copyTo(finalFile, overwrite = true)
|
||||||
|
tempFile.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshComponents(type)
|
||||||
|
mainThread { context.showToast(R.string.intent_import_component_success, finalName) }
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
Log.e(BuildConfig.TAG, "Failed to import custom component from $uri", t)
|
||||||
|
mainThread { context.showToast(R.string.intent_import_component_failure) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun queryDisplayName(uri: Uri): String? = try {
|
||||||
|
context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)
|
||||||
|
?.use { cursor ->
|
||||||
|
if (cursor.moveToFirst()) cursor.getString(0) else null
|
||||||
|
}
|
||||||
|
} catch (_: Throwable) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readApkVersion(apkFile: File): String? = try {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
context.packageManager.getPackageArchiveInfo(apkFile.absolutePath, 0)
|
||||||
|
?.versionName
|
||||||
|
?.let { SemVer.parseOrNull(it) }
|
||||||
|
?.toString()
|
||||||
|
} catch (_: Throwable) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractVersionFromName(name: String?): String? {
|
||||||
|
if (name == null) return null
|
||||||
|
return """(\d+\.\d+\.\d+)""".toRegex().find(name)?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleReleasesExpanded(type: PatchComponent.Type) {
|
||||||
|
releasesExpanded = !releasesExpanded
|
||||||
|
if (releasesExpanded && releasesState is ReleasesState.Idle) {
|
||||||
|
loadReleases(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadReleases(type: PatchComponent.Type) = screenModelScope.launchIO {
|
||||||
|
releasesState = ReleasesState.Loading
|
||||||
|
github.getManagerReleases().fold(
|
||||||
|
success = { all ->
|
||||||
|
val assetName = assetNameFor(type)
|
||||||
|
val filtered = all.filter { release ->
|
||||||
|
release.assets.any { it.name == assetName }
|
||||||
|
}
|
||||||
|
releasesState = ReleasesState.Loaded(filtered)
|
||||||
|
},
|
||||||
|
fail = {
|
||||||
|
Log.w(BuildConfig.TAG, "Failed to load GitHub releases", it)
|
||||||
|
releasesState = ReleasesState.Failed
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun importFromRelease(release: GithubRelease, type: PatchComponent.Type) = screenModelScope.launchIO {
|
||||||
|
val assetName = assetNameFor(type)
|
||||||
|
val asset = release.assets.find { it.name == assetName } ?: run {
|
||||||
|
mainThread { context.showToast(R.string.intent_import_component_failure) }
|
||||||
|
return@launchIO
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetDir = when (type) {
|
||||||
|
PatchComponent.Type.TidalApk -> paths.customTidalApksDir
|
||||||
|
PatchComponent.Type.Patches -> paths.customPatchesDir
|
||||||
|
}
|
||||||
|
targetDir.mkdirs()
|
||||||
|
|
||||||
|
importingReleaseTag = release.tagName
|
||||||
|
try {
|
||||||
|
val tempFile = targetDir.resolve("release-${System.currentTimeMillis()}.tmp")
|
||||||
|
val result = downloader.download(asset.browserDownloadUrl, tempFile)
|
||||||
|
if (result !is com.meowarex.rlmobile.manager.download.IDownloadManager.Result.Success) {
|
||||||
|
tempFile.delete()
|
||||||
|
mainThread { context.showToast(R.string.intent_import_component_failure) }
|
||||||
|
return@launchIO
|
||||||
|
}
|
||||||
|
|
||||||
|
val ext = when (type) {
|
||||||
|
PatchComponent.Type.TidalApk -> "apk"
|
||||||
|
PatchComponent.Type.Patches -> "zip"
|
||||||
|
}
|
||||||
|
val version = SemVer.parseOrNull(release.tagName.removePrefix("v"))?.toString()
|
||||||
|
?: FALLBACK_VERSION
|
||||||
|
val finalName = "${System.currentTimeMillis()}_$version.$ext"
|
||||||
|
val finalFile = targetDir.resolve(finalName)
|
||||||
|
if (!tempFile.renameTo(finalFile)) {
|
||||||
|
tempFile.copyTo(finalFile, overwrite = true)
|
||||||
|
tempFile.delete()
|
||||||
|
}
|
||||||
|
refreshComponents(type)
|
||||||
|
mainThread { context.showToast(R.string.intent_import_component_success, finalName) }
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
Log.e(BuildConfig.TAG, "Failed to import release ${release.tagName}", t)
|
||||||
|
mainThread { context.showToast(R.string.intent_import_component_failure) }
|
||||||
|
} finally {
|
||||||
|
importingReleaseTag = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assetNameFor(type: PatchComponent.Type) = when (type) {
|
||||||
|
PatchComponent.Type.TidalApk -> "tidal-stock.apk"
|
||||||
|
PatchComponent.Type.Patches -> "patches.zip"
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDispose() {
|
override fun onDispose() {
|
||||||
screenModelScope.launch { setResult(selected) }
|
screenModelScope.launch { setResult(selected) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed interface ReleasesState {
|
||||||
|
data object Idle : ReleasesState
|
||||||
|
data object Loading : ReleasesState
|
||||||
|
data class Loaded(val releases: List<GithubRelease>) : ReleasesState
|
||||||
|
data object Failed : ReleasesState
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val FALLBACK_VERSION = "0.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+232
@@ -1,13 +1,20 @@
|
|||||||
package com.meowarex.rlmobile.ui.screens.componentopts
|
package com.meowarex.rlmobile.ui.screens.componentopts
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cafe.adriel.voyager.koin.koinScreenModel
|
import cafe.adriel.voyager.koin.koinScreenModel
|
||||||
@@ -61,6 +68,12 @@ class ComponentOptionsScreen(
|
|||||||
selected = model.selected,
|
selected = model.selected,
|
||||||
onSelectComponent = model::selectComponent,
|
onSelectComponent = model::selectComponent,
|
||||||
onDeleteComponent = model::deleteComponent,
|
onDeleteComponent = model::deleteComponent,
|
||||||
|
onImportFromUri = { uri -> model.importFromUri(uri, componentType) },
|
||||||
|
releasesExpanded = model.releasesExpanded,
|
||||||
|
releasesState = model.releasesState,
|
||||||
|
onToggleReleases = { model.toggleReleasesExpanded(componentType) },
|
||||||
|
onImportRelease = { release -> model.importFromRelease(release, componentType) },
|
||||||
|
importingReleaseTag = model.importingReleaseTag,
|
||||||
onBackPressed = { navigator.back(null) },
|
onBackPressed = { navigator.back(null) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -73,8 +86,22 @@ fun ComponentOptionsScreenContent(
|
|||||||
selected: PatchComponent?,
|
selected: PatchComponent?,
|
||||||
onSelectComponent: (PatchComponent?) -> Unit,
|
onSelectComponent: (PatchComponent?) -> Unit,
|
||||||
onDeleteComponent: (PatchComponent) -> Unit,
|
onDeleteComponent: (PatchComponent) -> Unit,
|
||||||
|
onImportFromUri: (Uri) -> Unit,
|
||||||
|
releasesExpanded: Boolean,
|
||||||
|
releasesState: ComponentOptionsModel.ReleasesState,
|
||||||
|
onToggleReleases: () -> Unit,
|
||||||
|
onImportRelease: (com.meowarex.rlmobile.network.models.GithubRelease) -> Unit,
|
||||||
|
importingReleaseTag: String?,
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val mime = when (componentType) {
|
||||||
|
PatchComponent.Type.TidalApk -> "application/vnd.android.package-archive"
|
||||||
|
PatchComponent.Type.Patches -> "application/zip"
|
||||||
|
}
|
||||||
|
val filePicker = rememberLauncherForActivityResult(
|
||||||
|
ActivityResultContracts.OpenDocument(),
|
||||||
|
) { uri -> uri?.let(onImportFromUri) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { ComponentOptionsAppBar(componentType = componentType) },
|
topBar = { ComponentOptionsAppBar(componentType = componentType) },
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@@ -98,6 +125,16 @@ fun ComponentOptionsScreenContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item(key = "RELEASES_ACCORDION") {
|
||||||
|
ReleasesAccordion(
|
||||||
|
expanded = releasesExpanded,
|
||||||
|
state = releasesState,
|
||||||
|
importingTag = importingReleaseTag,
|
||||||
|
onToggle = onToggleReleases,
|
||||||
|
onImport = onImportRelease,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
items(
|
items(
|
||||||
items = components,
|
items = components,
|
||||||
contentType = { "COMPONENT" },
|
contentType = { "COMPONENT" },
|
||||||
@@ -112,6 +149,10 @@ fun ComponentOptionsScreenContent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item(key = "BROWSE") {
|
||||||
|
BrowseImportCard(onClick = { filePicker.launch(arrayOf(mime)) })
|
||||||
|
}
|
||||||
|
|
||||||
item("EXIT_BTN") {
|
item("EXIT_BTN") {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.End,
|
horizontalArrangement = Arrangement.End,
|
||||||
@@ -129,3 +170,194 @@ fun ComponentOptionsScreenContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ReleasesAccordion(
|
||||||
|
expanded: Boolean,
|
||||||
|
state: ComponentOptionsModel.ReleasesState,
|
||||||
|
importingTag: String?,
|
||||||
|
onToggle: () -> Unit,
|
||||||
|
onImport: (com.meowarex.rlmobile.network.models.GithubRelease) -> Unit,
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onToggle)
|
||||||
|
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_account_github_white_24dp),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.componentopts_releases_title),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.componentopts_releases_desc),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = LocalContentColor.current.copy(alpha = 0.65f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(
|
||||||
|
if (expanded) R.drawable.ic_arrow_up_small else R.drawable.ic_arrow_down_small
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = LocalContentColor.current.copy(alpha = 0.7f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expanded) {
|
||||||
|
HorizontalDivider(
|
||||||
|
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f),
|
||||||
|
)
|
||||||
|
ReleasesContent(
|
||||||
|
state = state,
|
||||||
|
importingTag = importingTag,
|
||||||
|
onImport = onImport,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ReleasesContent(
|
||||||
|
state: ComponentOptionsModel.ReleasesState,
|
||||||
|
importingTag: String?,
|
||||||
|
onImport: (com.meowarex.rlmobile.network.models.GithubRelease) -> Unit,
|
||||||
|
) {
|
||||||
|
when (state) {
|
||||||
|
is ComponentOptionsModel.ReleasesState.Idle,
|
||||||
|
ComponentOptionsModel.ReleasesState.Loading -> Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(20.dp),
|
||||||
|
) { CircularProgressIndicator(modifier = Modifier.size(24.dp)) }
|
||||||
|
|
||||||
|
ComponentOptionsModel.ReleasesState.Failed -> Text(
|
||||||
|
text = stringResource(R.string.network_load_fail),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(20.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
is ComponentOptionsModel.ReleasesState.Loaded -> {
|
||||||
|
if (state.releases.isEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.componentopts_releases_empty),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = LocalContentColor.current.copy(alpha = 0.65f),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(20.dp),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Column {
|
||||||
|
state.releases.forEachIndexed { index, release ->
|
||||||
|
ReleaseRow(
|
||||||
|
release = release,
|
||||||
|
importing = importingTag == release.tagName,
|
||||||
|
anyImporting = importingTag != null,
|
||||||
|
onImport = { onImport(release) },
|
||||||
|
)
|
||||||
|
if (index != state.releases.lastIndex) {
|
||||||
|
HorizontalDivider(
|
||||||
|
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.2f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ReleaseRow(
|
||||||
|
release: com.meowarex.rlmobile.network.models.GithubRelease,
|
||||||
|
importing: Boolean,
|
||||||
|
anyImporting: Boolean,
|
||||||
|
onImport: () -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = release.tagName,
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = release.name ?: release.tagName,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = LocalContentColor.current.copy(alpha = 0.55f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FilledTonalButton(
|
||||||
|
onClick = onImport,
|
||||||
|
enabled = !anyImporting,
|
||||||
|
) {
|
||||||
|
if (importing) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
strokeWidth = 2.dp,
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Text(stringResource(R.string.action_install))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BrowseImportCard(onClick: () -> Unit) {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onClick),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_add),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.componentopts_browse_title),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.componentopts_browse_desc),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = LocalContentColor.current.copy(alpha = 0.65f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+4
-4
@@ -34,8 +34,8 @@ data class PatchComponent(
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class Type : Parcelable {
|
enum class Type : Parcelable {
|
||||||
@SerialName("injector")
|
@SerialName("tidal")
|
||||||
Injector,
|
TidalApk,
|
||||||
|
|
||||||
@SerialName("patches")
|
@SerialName("patches")
|
||||||
Patches,
|
Patches,
|
||||||
@@ -47,11 +47,11 @@ data class PatchComponent(
|
|||||||
*/
|
*/
|
||||||
fun getFile(paths: PathManager): File {
|
fun getFile(paths: PathManager): File {
|
||||||
val dir = when (type) {
|
val dir = when (type) {
|
||||||
Type.Injector -> paths.customInjectorsDir
|
Type.TidalApk -> paths.customTidalApksDir
|
||||||
Type.Patches -> paths.customPatchesDir
|
Type.Patches -> paths.customPatchesDir
|
||||||
}
|
}
|
||||||
val ext = when (type) {
|
val ext = when (type) {
|
||||||
Type.Injector -> "dex"
|
Type.TidalApk -> "apk"
|
||||||
Type.Patches -> "zip"
|
Type.Patches -> "zip"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
|||||||
import com.github.diamondminer88.zip.ZipReader
|
import com.github.diamondminer88.zip.ZipReader
|
||||||
import com.meowarex.rlmobile.BuildConfig
|
import com.meowarex.rlmobile.BuildConfig
|
||||||
import com.meowarex.rlmobile.R
|
import com.meowarex.rlmobile.R
|
||||||
|
import com.meowarex.rlmobile.manager.PreferencesManager
|
||||||
import com.meowarex.rlmobile.network.models.GithubCommit
|
import com.meowarex.rlmobile.network.models.GithubCommit
|
||||||
import com.meowarex.rlmobile.network.models.RLBuildInfo
|
import com.meowarex.rlmobile.network.models.RLBuildInfo
|
||||||
import com.meowarex.rlmobile.network.services.RadiantLyricsGithubService
|
import com.meowarex.rlmobile.network.services.RadiantLyricsGithubService
|
||||||
@@ -28,6 +29,7 @@ import com.meowarex.rlmobile.patcher.InstallMetadata
|
|||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionsScreen
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionsScreen
|
||||||
import com.meowarex.rlmobile.ui.util.TidalVersion
|
import com.meowarex.rlmobile.ui.util.TidalVersion
|
||||||
|
import com.meowarex.rlmobile.ui.widgets.managerupdate.VersionDelta
|
||||||
import com.meowarex.rlmobile.util.*
|
import com.meowarex.rlmobile.util.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
@@ -39,11 +41,15 @@ class HomeModel(
|
|||||||
private val application: Application,
|
private val application: Application,
|
||||||
private val github: RadiantLyricsGithubService,
|
private val github: RadiantLyricsGithubService,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
|
private val prefs: PreferencesManager,
|
||||||
) : ScreenModel {
|
) : ScreenModel {
|
||||||
|
|
||||||
var state by mutableStateOf<HomeState>(HomeState.Loading)
|
var state by mutableStateOf<HomeState>(HomeState.Loading)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var managerUpdateDeltas by mutableStateOf<List<VersionDelta>?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
val commits = Pager(PagingConfig(pageSize = 30)) {
|
val commits = Pager(PagingConfig(pageSize = 30)) {
|
||||||
CommitsPagingSource(github)
|
CommitsPagingSource(github)
|
||||||
}.flow.cachedIn(screenModelScope)
|
}.flow.cachedIn(screenModelScope)
|
||||||
@@ -51,10 +57,103 @@ class HomeModel(
|
|||||||
private val refreshingLock = Mutex()
|
private val refreshingLock = Mutex()
|
||||||
private var remoteDataJson: RLBuildInfo? = null
|
private var remoteDataJson: RLBuildInfo? = null
|
||||||
|
|
||||||
|
private val initialPrefManagerVersion: String = prefs.lastSeenManagerVersion
|
||||||
|
private val initialPrefPatchesVersion: String = prefs.lastSeenPatchesVersion
|
||||||
|
private val initialPrefTidalVersionCode: Int = prefs.lastSeenTidalVersionCode
|
||||||
|
|
||||||
|
private var managerUpdateChecked = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dismissManagerUpdate() {
|
||||||
|
managerUpdateDeltas = null
|
||||||
|
commitVersionPrefs()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun commitVersionPrefs() {
|
||||||
|
prefs.lastSeenManagerVersion = BuildConfig.VERSION_NAME
|
||||||
|
remoteDataJson?.let {
|
||||||
|
prefs.lastSeenPatchesVersion = it.patchesVersion.toString()
|
||||||
|
prefs.lastSeenTidalVersionCode = it.tidalVersionCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeCheckManagerUpdate(installedPkg: PackageInfo?) {
|
||||||
|
if (managerUpdateChecked) return
|
||||||
|
managerUpdateChecked = true
|
||||||
|
|
||||||
|
val installMetadata = installedPkg?.packageName?.let(::loadInstallMetadata)
|
||||||
|
val current = BuildConfig.VERSION_NAME
|
||||||
|
|
||||||
|
val previousManager = initialPrefManagerVersion.ifEmpty {
|
||||||
|
installMetadata?.managerVersion?.toString().orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
when {
|
||||||
|
previousManager.isEmpty() -> commitVersionPrefs()
|
||||||
|
previousManager == current -> commitVersionPrefs()
|
||||||
|
else -> managerUpdateDeltas =
|
||||||
|
buildDeltas(previousManager, current, installMetadata, installedPkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDeltas(
|
||||||
|
previousManager: String,
|
||||||
|
currentManager: String,
|
||||||
|
installMetadata: InstallMetadata?,
|
||||||
|
installedPkg: PackageInfo?,
|
||||||
|
): List<VersionDelta> = buildList {
|
||||||
|
add(
|
||||||
|
VersionDelta(
|
||||||
|
label = application.getString(R.string.manager_update_row_manager),
|
||||||
|
iconRes = R.drawable.ic_sparkle,
|
||||||
|
from = previousManager,
|
||||||
|
to = currentManager,
|
||||||
|
tag = application.getString(R.string.manager_update_tag_complete),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val remote = remoteDataJson
|
||||||
|
val currentPatches = remote?.patchesVersion?.toString()
|
||||||
|
val previousPatches = initialPrefPatchesVersion.ifEmpty {
|
||||||
|
installMetadata?.patchesVersion?.toString().orEmpty()
|
||||||
|
}
|
||||||
|
val patchesFrom = previousPatches.takeIf { it.isNotEmpty() }
|
||||||
|
val patchesTo = currentPatches ?: previousPatches.ifEmpty { "?" }
|
||||||
|
add(
|
||||||
|
VersionDelta(
|
||||||
|
label = application.getString(R.string.manager_update_row_patches),
|
||||||
|
iconRes = R.drawable.ic_extension,
|
||||||
|
from = patchesFrom,
|
||||||
|
to = patchesTo,
|
||||||
|
tag = if (patchesFrom != null && patchesFrom != patchesTo)
|
||||||
|
application.getString(R.string.manager_update_tag_available) else null,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val currentTidal = remote?.tidalVersionCode
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val installedTidalVersionCode = installedPkg?.versionCode ?: -1
|
||||||
|
val previousTidal = if (initialPrefTidalVersionCode > 0) initialPrefTidalVersionCode
|
||||||
|
else installedTidalVersionCode
|
||||||
|
val tidalFrom = previousTidal.takeIf { it > 0 }?.toString()
|
||||||
|
val tidalTo = currentTidal?.toString()
|
||||||
|
?: previousTidal.takeIf { it > 0 }?.toString()
|
||||||
|
?: "?"
|
||||||
|
add(
|
||||||
|
VersionDelta(
|
||||||
|
label = application.getString(R.string.manager_update_row_tidal),
|
||||||
|
iconRes = R.drawable.ic_music_note,
|
||||||
|
from = tidalFrom,
|
||||||
|
to = tidalTo,
|
||||||
|
tag = if (tidalFrom != null && tidalFrom != tidalTo)
|
||||||
|
application.getString(R.string.manager_update_tag_available) else null,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun refresh(delay: Boolean = false) = screenModelScope.launchIO {
|
fun refresh(delay: Boolean = false) = screenModelScope.launchIO {
|
||||||
if (refreshingLock.isLocked) return@launchIO
|
if (refreshingLock.isLocked) return@launchIO
|
||||||
if (delay) {
|
if (delay) {
|
||||||
@@ -75,6 +174,7 @@ class HomeModel(
|
|||||||
install = install,
|
install = install,
|
||||||
latestTidalVersionCode = latest,
|
latestTidalVersionCode = latest,
|
||||||
)
|
)
|
||||||
|
maybeCheckManagerUpdate(pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +189,7 @@ class HomeModel(
|
|||||||
openAppInfo(current.packageName)
|
openAppInfo(current.packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createReinstallScreen(): PatchOptionsScreen? {
|
fun createRepatchScreen(): PatchOptionsScreen? {
|
||||||
val current = (state as? HomeState.Loaded)?.install ?: return null
|
val current = (state as? HomeState.Loaded)?.install ?: return null
|
||||||
return createPrefilledPatchOptsScreen(current.packageName)
|
return createPrefilledPatchOptsScreen(current.packageName)
|
||||||
}
|
}
|
||||||
@@ -112,20 +212,21 @@ class HomeModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createPrefilledPatchOptsScreen(packageName: String): PatchOptionsScreen {
|
fun createPrefilledPatchOptsScreen(packageName: String): PatchOptionsScreen {
|
||||||
val metadata = try {
|
val patchOptions = loadInstallMetadata(packageName)?.options
|
||||||
val applicationInfo = application.packageManager.getApplicationInfo(packageName, 0)
|
?: PatchOptions.Default.copy(packageName = packageName)
|
||||||
val metadataFile = ZipReader(applicationInfo.publicSourceDir)
|
|
||||||
.use { it.openEntry("rlmobile.json")?.read() }
|
|
||||||
metadataFile?.let { json.decodeFromStream<InstallMetadata>(it.inputStream()) }
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
Log.w(BuildConfig.TAG, "Failed to parse install metadata for $packageName", t)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val patchOptions = metadata?.options ?: PatchOptions.Default.copy(packageName = packageName)
|
|
||||||
return PatchOptionsScreen(prefilledOptions = patchOptions)
|
return PatchOptionsScreen(prefilledOptions = patchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadInstallMetadata(packageName: String): InstallMetadata? = try {
|
||||||
|
val applicationInfo = application.packageManager.getApplicationInfo(packageName, 0)
|
||||||
|
val metadataBytes = ZipReader(applicationInfo.publicSourceDir)
|
||||||
|
.use { it.openEntry("rlmobile.json")?.read() }
|
||||||
|
metadataBytes?.let { json.decodeFromStream<InstallMetadata>(it.inputStream()) }
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
Log.w(BuildConfig.TAG, "Failed to parse install metadata for $packageName", t)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
private fun fetchInstalled(): PackageInfo? = application.packageManager
|
private fun fetchInstalled(): PackageInfo? = application.packageManager
|
||||||
.getInstalledPackages(PackageManager.GET_META_DATA)
|
.getInstalledPackages(PackageManager.GET_META_DATA)
|
||||||
.firstOrNull { it.applicationInfo?.metaData?.containsKey("isRadiantLyrics") == true }
|
.firstOrNull { it.applicationInfo?.metaData?.containsKey("isRadiantLyrics") == true }
|
||||||
@@ -138,7 +239,8 @@ class HomeModel(
|
|||||||
return InstallData(
|
return InstallData(
|
||||||
name = pm.getApplicationLabel(info).toString(),
|
name = pm.getApplicationLabel(info).toString(),
|
||||||
packageName = packageName,
|
packageName = packageName,
|
||||||
isUpToDate = isInstallationUpToDate(this),
|
tidalUpToDate = isTidalUpToDate(this),
|
||||||
|
patchesUpToDate = isPatchesUpToDate(this),
|
||||||
icon = pm.getApplicationIcon(info).toBitmap().asImageBitmap().let(::BitmapPainter),
|
icon = pm.getApplicationIcon(info).toBitmap().asImageBitmap().let(::BitmapPainter),
|
||||||
version = TidalVersion.Existing(
|
version = TidalVersion.Existing(
|
||||||
type = TidalVersion.parseVersionType(versionCode),
|
type = TidalVersion.parseVersionType(versionCode),
|
||||||
@@ -170,11 +272,14 @@ class HomeModel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isInstallationUpToDate(pkg: PackageInfo): Boolean? {
|
private fun isTidalUpToDate(pkg: PackageInfo): Boolean? {
|
||||||
val remote = remoteDataJson ?: return null
|
val remote = remoteDataJson ?: return null
|
||||||
@Suppress("DEPRECATION") val versionCode = pkg.versionCode
|
@Suppress("DEPRECATION") val versionCode = pkg.versionCode
|
||||||
if (remote.tidalVersionCode != versionCode) return false
|
return remote.tidalVersionCode == versionCode
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isPatchesUpToDate(pkg: PackageInfo): Boolean? {
|
||||||
|
val remote = remoteDataJson ?: return null
|
||||||
val apkPath = pkg.applicationInfo?.publicSourceDir ?: return false
|
val apkPath = pkg.applicationInfo?.publicSourceDir ?: return false
|
||||||
val installMetadata = try {
|
val installMetadata = try {
|
||||||
val mf = ZipReader(apkPath).use { it.openEntry("rlmobile.json")?.read() } ?: return false
|
val mf = ZipReader(apkPath).use { it.openEntry("rlmobile.json")?.read() } ?: return false
|
||||||
@@ -182,8 +287,6 @@ class HomeModel(
|
|||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (installMetadata.options.customPatches != null) return true
|
|
||||||
return remote.patchesVersion == installMetadata.patchesVersion
|
return remote.patchesVersion == installMetadata.patchesVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,13 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import com.meowarex.rlmobile.R
|
import com.meowarex.rlmobile.R
|
||||||
import com.meowarex.rlmobile.ui.components.SegmentedButton
|
import com.meowarex.rlmobile.ui.components.SegmentedButton
|
||||||
|
import com.meowarex.rlmobile.ui.components.Tag
|
||||||
import com.meowarex.rlmobile.ui.screens.about.AboutScreen
|
import com.meowarex.rlmobile.ui.screens.about.AboutScreen
|
||||||
import com.meowarex.rlmobile.ui.screens.home.components.CommitList
|
import com.meowarex.rlmobile.ui.screens.home.components.CommitList
|
||||||
import com.meowarex.rlmobile.ui.screens.logs.LogsListScreen
|
import com.meowarex.rlmobile.ui.screens.logs.LogsListScreen
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionsScreen
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionsScreen
|
||||||
import com.meowarex.rlmobile.ui.screens.settings.SettingsScreen
|
import com.meowarex.rlmobile.ui.screens.settings.SettingsScreen
|
||||||
|
import com.meowarex.rlmobile.ui.widgets.managerupdate.ManagerUpdateDialog
|
||||||
import com.meowarex.rlmobile.util.*
|
import com.meowarex.rlmobile.util.*
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
@@ -106,9 +108,9 @@ class HomeScreen : Screen, Parcelable {
|
|||||||
state = state,
|
state = state,
|
||||||
commits = model.commits,
|
commits = model.commits,
|
||||||
onInstall = { navigator.pushOnce(PatchOptionsScreen()) },
|
onInstall = { navigator.pushOnce(PatchOptionsScreen()) },
|
||||||
onReinstall = {
|
onRepatch = {
|
||||||
scope.launchIO {
|
scope.launchIO {
|
||||||
val screen = model.createReinstallScreen() ?: return@launchIO
|
val screen = model.createRepatchScreen() ?: return@launchIO
|
||||||
mainThread { navigator.push(screen) }
|
mainThread { navigator.push(screen) }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -116,6 +118,13 @@ class HomeScreen : Screen, Parcelable {
|
|||||||
onInfo = model::openCurrentAppInfo,
|
onInfo = model::openCurrentAppInfo,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.managerUpdateDeltas?.let { deltas ->
|
||||||
|
ManagerUpdateDialog(
|
||||||
|
deltas = deltas,
|
||||||
|
onDismiss = model::dismissManagerUpdate,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,12 +135,13 @@ private fun ColumnScope.HomeContent(
|
|||||||
state: HomeState.Loaded,
|
state: HomeState.Loaded,
|
||||||
commits: kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<com.meowarex.rlmobile.network.models.GithubCommit>>,
|
commits: kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<com.meowarex.rlmobile.network.models.GithubCommit>>,
|
||||||
onInstall: () -> Unit,
|
onInstall: () -> Unit,
|
||||||
onReinstall: () -> Unit,
|
onRepatch: () -> Unit,
|
||||||
onLaunch: () -> Unit,
|
onLaunch: () -> Unit,
|
||||||
onInfo: () -> Unit,
|
onInfo: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val install = state.install
|
val install = state.install
|
||||||
val currentVersionName = install?.version?.let { "v${it.toString()}" }
|
val currentVersionName = (install?.version as? com.meowarex.rlmobile.ui.util.TidalVersion.Existing)
|
||||||
|
?.let { "v${it.name} (build ${it.code})" }
|
||||||
val latestVersionName = state.latestTidalVersionCode?.let { "build $it" }
|
val latestVersionName = state.latestTidalVersionCode?.let { "build $it" }
|
||||||
|
|
||||||
val fallbackPainter = if (install?.icon == null) {
|
val fallbackPainter = if (install?.icon == null) {
|
||||||
@@ -181,8 +191,17 @@ private fun ColumnScope.HomeContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val patchesBehind = install != null && install.patchesUpToDate == false
|
||||||
|
val tidalBehind = install != null && install.tidalUpToDate == false
|
||||||
|
AnimatedVisibility(visible = patchesBehind || tidalBehind) {
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
|
if (patchesBehind) Tag(text = "New Patches!")
|
||||||
|
if (tidalBehind) Tag(text = "TIDAL Update!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = if (install == null) onInstall else onReinstall,
|
onClick = if (install == null) onInstall else onRepatch,
|
||||||
enabled = state.latestTidalVersionCode != null,
|
enabled = state.latestTidalVersionCode != null,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
@@ -190,7 +209,7 @@ private fun ColumnScope.HomeContent(
|
|||||||
state.latestTidalVersionCode == null -> "Loading…"
|
state.latestTidalVersionCode == null -> "Loading…"
|
||||||
install == null -> "Install"
|
install == null -> "Install"
|
||||||
install.isUpToDate == false -> "Update"
|
install.isUpToDate == false -> "Update"
|
||||||
else -> "Reinstall"
|
else -> "Repatch"
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = label,
|
text = label,
|
||||||
|
|||||||
@@ -10,5 +10,12 @@ data class InstallData(
|
|||||||
val packageName: String,
|
val packageName: String,
|
||||||
val version: TidalVersion,
|
val version: TidalVersion,
|
||||||
val icon: BitmapPainter,
|
val icon: BitmapPainter,
|
||||||
val isUpToDate: Boolean?,
|
val tidalUpToDate: Boolean?,
|
||||||
)
|
val patchesUpToDate: Boolean?,
|
||||||
|
) {
|
||||||
|
val isUpToDate: Boolean?
|
||||||
|
get() = when {
|
||||||
|
tidalUpToDate == null || patchesUpToDate == null -> null
|
||||||
|
else -> tidalUpToDate && patchesUpToDate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
-14
@@ -28,7 +28,6 @@ import com.meowarex.rlmobile.patcher.steps.StepGroup
|
|||||||
import com.meowarex.rlmobile.ui.components.MainActionButton
|
import com.meowarex.rlmobile.ui.components.MainActionButton
|
||||||
import com.meowarex.rlmobile.ui.components.Wakelock
|
import com.meowarex.rlmobile.ui.components.Wakelock
|
||||||
import com.meowarex.rlmobile.ui.components.dialogs.InstallerAbortDialog
|
import com.meowarex.rlmobile.ui.components.dialogs.InstallerAbortDialog
|
||||||
import com.meowarex.rlmobile.ui.components.dialogs.NetworkWarningDialog
|
|
||||||
import com.meowarex.rlmobile.ui.screens.log.LogScreen
|
import com.meowarex.rlmobile.ui.screens.log.LogScreen
|
||||||
import com.meowarex.rlmobile.ui.screens.patching.components.*
|
import com.meowarex.rlmobile.ui.screens.patching.components.*
|
||||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
||||||
@@ -111,19 +110,6 @@ class PatchingScreen(
|
|||||||
listState.animateScrollToItem(0)
|
listState.animateScrollToItem(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.showNetworkWarningDialog) {
|
|
||||||
NetworkWarningDialog(
|
|
||||||
onConfirm = { neverShow ->
|
|
||||||
model.hideNetworkWarning(neverShow)
|
|
||||||
model.install()
|
|
||||||
},
|
|
||||||
onDismiss = { neverShow ->
|
|
||||||
model.hideNetworkWarning(neverShow)
|
|
||||||
navigator.pop()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showAbortWarning) {
|
if (showAbortWarning) {
|
||||||
InstallerAbortDialog(
|
InstallerAbortDialog(
|
||||||
onDismiss = { showAbortWarning = false },
|
onDismiss = { showAbortWarning = false },
|
||||||
|
|||||||
+1
-17
@@ -41,9 +41,6 @@ class PatchingScreenModel(
|
|||||||
|
|
||||||
val devMode get() = prefs.devMode
|
val devMode get() = prefs.devMode
|
||||||
|
|
||||||
var showNetworkWarningDialog by mutableStateOf(!alreadyShownNetworkWarning && application.isNetworkDangerous())
|
|
||||||
private set
|
|
||||||
|
|
||||||
var steps by mutableStateOf<ImmutableMap<StepGroup, ImmutableList<Step>>?>(null)
|
var steps by mutableStateOf<ImmutableMap<StepGroup, ImmutableList<Step>>?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -52,11 +49,7 @@ class PatchingScreenModel(
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (!prefs.showNetworkWarning)
|
install()
|
||||||
showNetworkWarningDialog = false
|
|
||||||
|
|
||||||
if (!showNetworkWarningDialog)
|
|
||||||
install()
|
|
||||||
|
|
||||||
// Rotate fun facts every so often
|
// Rotate fun facts every so often
|
||||||
screenModelScope.launch {
|
screenModelScope.launch {
|
||||||
@@ -67,12 +60,6 @@ class PatchingScreenModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hideNetworkWarning(neverShow: Boolean) {
|
|
||||||
showNetworkWarningDialog = false
|
|
||||||
alreadyShownNetworkWarning = true
|
|
||||||
prefs.showNetworkWarning = !neverShow
|
|
||||||
}
|
|
||||||
|
|
||||||
fun launchApp() {
|
fun launchApp() {
|
||||||
if (state.value !is PatchingScreenState.Success)
|
if (state.value !is PatchingScreenState.Success)
|
||||||
return
|
return
|
||||||
@@ -194,9 +181,6 @@ class PatchingScreenModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Global state to avoid showing the warning more than once per launch
|
|
||||||
private var alreadyShownNetworkWarning = false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Random fun facts to show on the installation screen.
|
* Random fun facts to show on the installation screen.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
-6
@@ -25,10 +25,7 @@ data class PatchOptions(
|
|||||||
*/
|
*/
|
||||||
val debuggable: Boolean,
|
val debuggable: Boolean,
|
||||||
|
|
||||||
/**
|
val customTidalApk: PatchComponent? = null,
|
||||||
* A custom build of injector that was used rather than the latest.
|
|
||||||
*/
|
|
||||||
val customInjector: PatchComponent? = null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom smali patches bundle that was used rather than the latest.
|
* A custom smali patches bundle that was used rather than the latest.
|
||||||
@@ -42,9 +39,9 @@ data class PatchOptions(
|
|||||||
appName = "TIDAL",
|
appName = "TIDAL",
|
||||||
packageName = "com.aspiro.tidal",
|
packageName = "com.aspiro.tidal",
|
||||||
debuggable = false,
|
debuggable = false,
|
||||||
customInjector = null,
|
customTidalApk = null,
|
||||||
customPatches = null,
|
customPatches = null,
|
||||||
disabledPatches = emptySet(),
|
disabledPatches = (KnownPatch.DebugMenuUnlock.fileNames + KnownPatch.EnableLegacyUi.fileNames).toSet(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -81,16 +81,16 @@ class PatchOptionsModel(
|
|||||||
val enabledPatchCount: Int
|
val enabledPatchCount: Int
|
||||||
get() = KnownPatch.All.count { isPatchEnabled(it) }
|
get() = KnownPatch.All.count { isPatchEnabled(it) }
|
||||||
|
|
||||||
var customInjector by mutableStateOf<PatchComponent?>(null)
|
var customTidalApk by mutableStateOf<PatchComponent?>(null)
|
||||||
private set
|
private set
|
||||||
var customPatches by mutableStateOf<PatchComponent?>(null)
|
var customPatches by mutableStateOf<PatchComponent?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun selectCustomInjector(navigator: Navigator) = screenModelScope.launch {
|
fun selectCustomTidalApk(navigator: Navigator) = screenModelScope.launch {
|
||||||
customInjector = navigator.pushForResult(
|
customTidalApk = navigator.pushForResult(
|
||||||
ComponentOptionsScreen(
|
ComponentOptionsScreen(
|
||||||
default = customInjector,
|
default = customTidalApk,
|
||||||
componentType = PatchComponent.Type.Injector,
|
componentType = PatchComponent.Type.TidalApk,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ class PatchOptionsModel(
|
|||||||
appName = appName,
|
appName = appName,
|
||||||
packageName = packageName,
|
packageName = packageName,
|
||||||
debuggable = debuggable,
|
debuggable = debuggable,
|
||||||
customInjector = customInjector,
|
customTidalApk = customTidalApk,
|
||||||
customPatches = customPatches,
|
customPatches = customPatches,
|
||||||
disabledPatches = disabledPatches,
|
disabledPatches = disabledPatches,
|
||||||
)
|
)
|
||||||
|
|||||||
+10
-10
@@ -55,9 +55,9 @@ class PatchOptionsScreen(
|
|||||||
packageNameState = model.packageNameState,
|
packageNameState = model.packageNameState,
|
||||||
setPackageName = model::changePackageName,
|
setPackageName = model::changePackageName,
|
||||||
|
|
||||||
customInjector = model.customInjector,
|
customTidalApk = model.customTidalApk,
|
||||||
customPatches = model.customPatches,
|
customPatches = model.customPatches,
|
||||||
onSelectCustomInjector = { model.selectCustomInjector(navigator) },
|
onSelectCustomTidalApk = { model.selectCustomTidalApk(navigator) },
|
||||||
onSelectCustomPatches = { model.selectCustomPatches(navigator) },
|
onSelectCustomPatches = { model.selectCustomPatches(navigator) },
|
||||||
|
|
||||||
enabledPatchCount = model.enabledPatchCount,
|
enabledPatchCount = model.enabledPatchCount,
|
||||||
@@ -88,8 +88,8 @@ fun PatchOptionsScreenContent(
|
|||||||
packageNameState: PackageNameState,
|
packageNameState: PackageNameState,
|
||||||
setPackageName: (String) -> Unit,
|
setPackageName: (String) -> Unit,
|
||||||
|
|
||||||
customInjector: PatchComponent?,
|
customTidalApk: PatchComponent?,
|
||||||
onSelectCustomInjector: () -> Unit,
|
onSelectCustomTidalApk: () -> Unit,
|
||||||
customPatches: PatchComponent?,
|
customPatches: PatchComponent?,
|
||||||
onSelectCustomPatches: () -> Unit,
|
onSelectCustomPatches: () -> Unit,
|
||||||
|
|
||||||
@@ -180,14 +180,14 @@ fun PatchOptionsScreenContent(
|
|||||||
)
|
)
|
||||||
|
|
||||||
IconPatchOption(
|
IconPatchOption(
|
||||||
icon = painterResource(R.drawable.ic_extension),
|
icon = painterResource(R.drawable.ic_music_note),
|
||||||
name = stringResource(R.string.patchopts_custom_injector_title),
|
name = stringResource(R.string.patchopts_custom_tidal_apk_title),
|
||||||
description = stringResource(R.string.patchopts_custom_injector_desc),
|
description = stringResource(R.string.patchopts_custom_tidal_apk_desc),
|
||||||
modifier = Modifier.clickable(onClick = onSelectCustomInjector),
|
modifier = Modifier.clickable(onClick = onSelectCustomTidalApk),
|
||||||
) {
|
) {
|
||||||
FilledTonalButton(onClick = onSelectCustomInjector) {
|
FilledTonalButton(onClick = onSelectCustomTidalApk) {
|
||||||
Text(
|
Text(
|
||||||
text = customInjector?.version?.toString()
|
text = customTidalApk?.version?.toString()
|
||||||
?: stringResource(R.string.componentopts_selected_none)
|
?: stringResource(R.string.componentopts_selected_none)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
package com.meowarex.rlmobile.ui.widgets.managerupdate
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
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.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import com.meowarex.rlmobile.R
|
||||||
|
import com.meowarex.rlmobile.ui.components.Tag
|
||||||
|
|
||||||
|
data class VersionDelta(
|
||||||
|
val label: String,
|
||||||
|
@DrawableRes val iconRes: Int,
|
||||||
|
val from: String?,
|
||||||
|
val to: String,
|
||||||
|
val tag: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ManagerUpdateDialog(
|
||||||
|
deltas: List<VersionDelta>,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
confirmButton = {
|
||||||
|
FilledTonalButton(
|
||||||
|
onClick = onDismiss,
|
||||||
|
colors = ButtonDefaults.filledTonalButtonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.action_continue))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.manager_update_title),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.manager_update_subtitle),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
deltas.forEach { delta ->
|
||||||
|
DeltaCard(delta = delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_update),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(36.dp),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
properties = DialogProperties(
|
||||||
|
dismissOnBackPress = true,
|
||||||
|
dismissOnClickOutside = false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DeltaCard(delta: VersionDelta) {
|
||||||
|
val changed = delta.from != null && delta.from != delta.to
|
||||||
|
val subtitle = when {
|
||||||
|
delta.from == null || delta.from == delta.to -> delta.to
|
||||||
|
else -> "${delta.from} → ${delta.to}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
|
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp),
|
||||||
|
) {
|
||||||
|
DeltaIcon(delta)
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = delta.label,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = subtitle,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = if (changed) MaterialTheme.colorScheme.primary
|
||||||
|
else LocalContentColor.current.copy(alpha = 0.65f),
|
||||||
|
fontWeight = if (changed) FontWeight.SemiBold else FontWeight.Normal,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
delta.tag?.let { Tag(text = it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DeltaIcon(delta: VersionDelta) {
|
||||||
|
Surface(
|
||||||
|
shape = CircleShape,
|
||||||
|
color = MaterialTheme.colorScheme.secondaryContainer,
|
||||||
|
modifier = Modifier.size(40.dp),
|
||||||
|
) {
|
||||||
|
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(delta.iconRes),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||||
|
modifier = Modifier.size(22.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,9 @@ import android.app.Activity
|
|||||||
import android.content.*
|
import android.content.*
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.telephony.TelephonyManager
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
@@ -152,37 +150,6 @@ suspend fun Context.isPlayProtectEnabled(): Boolean? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the device is connected on a metered WIFI connection or through any type of mobile data,
|
|
||||||
* to avoid unknowingly downloading a lot of stuff through a potentially metered network.
|
|
||||||
*/
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
fun Context.isNetworkDangerous(): Boolean {
|
|
||||||
val connectivity = this.getSystemService<ConnectivityManager>()
|
|
||||||
?: error("Unable to get system connectivity service")
|
|
||||||
|
|
||||||
if (connectivity.isActiveNetworkMetered) return true
|
|
||||||
|
|
||||||
when (val info = connectivity.activeNetworkInfo) {
|
|
||||||
null -> return false
|
|
||||||
else -> {
|
|
||||||
if (info.isRoaming) return true
|
|
||||||
if (info.type == ConnectivityManager.TYPE_WIFI) return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val telephony = this.getSystemService<TelephonyManager>()
|
|
||||||
?: error("Unable to get system telephony service")
|
|
||||||
|
|
||||||
val dangerousMobileDataStates = arrayOf(
|
|
||||||
/* TelephonyManager.DATA_DISCONNECTING */ 4,
|
|
||||||
TelephonyManager.DATA_CONNECTED,
|
|
||||||
TelephonyManager.DATA_CONNECTING,
|
|
||||||
)
|
|
||||||
|
|
||||||
return dangerousMobileDataStates.contains(telephony.dataState)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the user associated with this context.
|
* Gets the user associated with this context.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -21,4 +21,4 @@
|
|||||||
android:pathData="M5.209,1.737C5.313,1.473 5.687,1.473 5.791,1.737L6.157,2.667C6.189,2.747 6.253,2.811 6.333,2.843L7.263,3.209C7.527,3.313 7.527,3.687 7.263,3.791L6.333,4.157C6.253,4.189 6.189,4.253 6.157,4.333L5.791,5.263C5.687,5.527 5.313,5.527 5.209,5.263L4.843,4.333C4.811,4.253 4.747,4.189 4.667,4.157L3.737,3.791C3.473,3.687 3.473,3.313 3.737,3.209L4.667,2.843C4.747,2.811 4.811,2.747 4.843,2.667L5.209,1.737Z" />
|
android:pathData="M5.209,1.737C5.313,1.473 5.687,1.473 5.791,1.737L6.157,2.667C6.189,2.747 6.253,2.811 6.333,2.843L7.263,3.209C7.527,3.313 7.527,3.687 7.263,3.791L6.333,4.157C6.253,4.189 6.189,4.253 6.157,4.333L5.791,5.263C5.687,5.527 5.313,5.527 5.209,5.263L4.843,4.333C4.811,4.253 4.747,4.189 4.667,4.157L3.737,3.791C3.473,3.687 3.473,3.313 3.737,3.209L4.667,2.843C4.747,2.811 4.811,2.747 4.843,2.667L5.209,1.737Z" />
|
||||||
</group>
|
</group>
|
||||||
</vector>
|
</vector>
|
||||||
aight
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M19,3L9,5v9.85c-0.59,-0.34 -1.27,-0.55 -2,-0.55c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4V7.36l8,-1.6v6.49c-0.59,-0.34 -1.27,-0.55 -2,-0.55c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4V3z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M19,9l1.25,-2.75L23,5l-2.75,-1.25L19,1l-1.25,2.75L15,5l2.75,1.25L19,9zm-7.5,0.5L9,4 6.5,9.5 1,12l5.5,2.5L9,20l2.5,-5.5L17,12l-5.5,-2.5zM19,15l-1.25,2.75L15,19l2.75,1.25L19,23l1.25,-2.75L23,19l-2.75,-1.25z" />
|
||||||
|
</vector>
|
||||||
@@ -43,10 +43,18 @@
|
|||||||
<string name="action_open_info">Open Info</string>
|
<string name="action_open_info">Open Info</string>
|
||||||
<string name="action_reset_default">Reset to default</string>
|
<string name="action_reset_default">Reset to default</string>
|
||||||
|
|
||||||
<string name="intent_reinstall_fail">Failed to automatically reinstall! Please try doing it manually.</string>
|
<string name="intent_reinstall_fail">Failed to automatically repatch! Please try doing it manually.</string>
|
||||||
<string name="intent_import_component_success">Successfully imported %s</string>
|
<string name="intent_import_component_success">Successfully imported %s</string>
|
||||||
<string name="intent_import_component_failure">Failed to import custom component!</string>
|
<string name="intent_import_component_failure">Failed to import custom component!</string>
|
||||||
|
|
||||||
|
<string name="manager_update_title">Update Complete</string>
|
||||||
|
<string name="manager_update_subtitle">Manager was successfully updated!</string>
|
||||||
|
<string name="manager_update_row_manager">Manager</string>
|
||||||
|
<string name="manager_update_row_patches">Patches</string>
|
||||||
|
<string name="manager_update_row_tidal">TIDAL</string>
|
||||||
|
<string name="manager_update_tag_complete">Complete</string>
|
||||||
|
<string name="manager_update_tag_available">Available</string>
|
||||||
|
|
||||||
<string name="permissions_title">Grant Permissions</string>
|
<string name="permissions_title">Grant Permissions</string>
|
||||||
<string name="permissions_subtitle">Radiant Lyrics Manager requires permissions:</string>
|
<string name="permissions_subtitle">Radiant Lyrics Manager requires permissions:</string>
|
||||||
<string name="permissions_legend">%s indicates required permissions!</string>
|
<string name="permissions_legend">%s indicates required permissions!</string>
|
||||||
@@ -63,7 +71,7 @@
|
|||||||
<string name="permissions_notifs_title">Notifications</string>
|
<string name="permissions_notifs_title">Notifications</string>
|
||||||
<string name="permissions_battery_title">Background Battery</string>
|
<string name="permissions_battery_title">Background Battery</string>
|
||||||
<string name="permissions_battery_desc">Ensures the installation process does not get automatically cancelled if the app is minimized.</string>
|
<string name="permissions_battery_desc">Ensures the installation process does not get automatically cancelled if the app is minimized.</string>
|
||||||
<string name="permissions_notifs_desc">Used only to show the download progress if Radiant Lyrics Manager is minimized during installation.</string>
|
<string name="permissions_notifs_desc">Used to notify you when updates are available!</string>
|
||||||
|
|
||||||
<string name="permissions_root_denied">Failed to obtain root permissions</string>
|
<string name="permissions_root_denied">Failed to obtain root permissions</string>
|
||||||
<string name="permissions_shizuku_denied">Failed to obtain Shizuku permissions</string>
|
<string name="permissions_shizuku_denied">Failed to obtain Shizuku permissions</string>
|
||||||
@@ -235,10 +243,10 @@
|
|||||||
>The app name is what\'s displayed in your home launcher. This should be changed on secondary installations for ease of use.</string>
|
>The app name is what\'s displayed in your home launcher. This should be changed on secondary installations for ease of use.</string>
|
||||||
<string name="patchopts_debuggable_title">Debuggable</string>
|
<string name="patchopts_debuggable_title">Debuggable</string>
|
||||||
<string name="patchopts_debuggable_desc">Enable the debuggable manifest flag. Only use this if you know what you are doing!</string>
|
<string name="patchopts_debuggable_desc">Enable the debuggable manifest flag. Only use this if you know what you are doing!</string>
|
||||||
<string name="patchopts_custom_injector_title">Custom Injector</string>
|
<string name="patchopts_custom_tidal_apk_title">Custom TIDAL APK</string>
|
||||||
<string name="patchopts_custom_injector_desc">A custom injector build that was imported by Manager.</string>
|
<string name="patchopts_custom_tidal_apk_desc">Provide your own Stock TIDAL APK to patch instead of the version from Github.</string>
|
||||||
<string name="patchopts_custom_patches_title">Custom Patches</string>
|
<string name="patchopts_custom_patches_title">Custom Patches</string>
|
||||||
<string name="patchopts_custom_patches_desc">A custom smali patch bundle that was imported by Manager.</string>
|
<string name="patchopts_custom_patches_desc">Provide your own Patches Zip to use instead of the ones from Github.</string>
|
||||||
<string name="patchopts_divider_basic">Basic</string>
|
<string name="patchopts_divider_basic">Basic</string>
|
||||||
<string name="patchopts_divider_advanced">Advanced</string>
|
<string name="patchopts_divider_advanced">Advanced</string>
|
||||||
<string name="patchopts_patches_title">Patches</string>
|
<string name="patchopts_patches_title">Patches</string>
|
||||||
@@ -270,6 +278,11 @@
|
|||||||
<string name="componentopts_screen_desc">Select a custom build that was imported by Manager.</string>
|
<string name="componentopts_screen_desc">Select a custom build that was imported by Manager.</string>
|
||||||
<string name="componentopts_selected_none">Latest</string>
|
<string name="componentopts_selected_none">Latest</string>
|
||||||
<string name="componentopts_deleted">Successfully deleted component!</string>
|
<string name="componentopts_deleted">Successfully deleted component!</string>
|
||||||
|
<string name="componentopts_browse_title">Browse files…</string>
|
||||||
|
<string name="componentopts_browse_desc">Import a file from your device</string>
|
||||||
|
<string name="componentopts_releases_title">GitHub Releases</string>
|
||||||
|
<string name="componentopts_releases_desc">Pick a historical release from the repo</string>
|
||||||
|
<string name="componentopts_releases_empty">No releases with this component found</string>
|
||||||
|
|
||||||
<string name="log_title">Log</string>
|
<string name="log_title">Log</string>
|
||||||
<string name="log_section_install_info">Installation Info</string>
|
<string name="log_section_install_info">Installation Info</string>
|
||||||
@@ -302,7 +315,7 @@
|
|||||||
<string name="play_protect_warning_open_gpp">Open Play Protect</string>
|
<string name="play_protect_warning_open_gpp">Open Play Protect</string>
|
||||||
<string name="play_protect_warning_disable">Don\'t show this again</string>
|
<string name="play_protect_warning_disable">Don\'t show this again</string>
|
||||||
|
|
||||||
<string name="fun_fact_prefix">Fun Fact: %s</string>
|
<string name="fun_fact_prefix">%s</string>
|
||||||
<string name="fun_fact_1">Did you know that TIDAL no longer like blur!</string>
|
<string name="fun_fact_1">Did you know that TIDAL no longer like blur!</string>
|
||||||
<string name="fun_fact_2">Radiant Lyrics is also available for DESKTOP!!!</string>
|
<string name="fun_fact_2">Radiant Lyrics is also available for DESKTOP!!!</string>
|
||||||
<string name="fun_fact_3">i am in your walls!</string>
|
<string name="fun_fact_3">i am in your walls!</string>
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"tidalVersionCode": 9089,
|
"tidalVersionCode": 9090,
|
||||||
"tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk",
|
"tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk",
|
||||||
"patchesVersion": "0.5.0"
|
"patchesVersion": "0.7.6"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,36 @@
|
|||||||
--- a/com/tidal/android/core/debug/DebugFeatureInteractorDefault.smali
|
--- a/com/tidal/android/core/debug/DebugFeatureInteractorDefault.smali
|
||||||
+++ b/com/tidal/android/core/debug/DebugFeatureInteractorDefault.smali
|
+++ b/com/tidal/android/core/debug/DebugFeatureInteractorDefault.smali
|
||||||
@@ -53,6 +53,11 @@
|
@@ -54,6 +54,9 @@
|
||||||
.method public final a()Z
|
.method public final a()Z
|
||||||
.locals 2
|
.locals 2
|
||||||
|
|
||||||
+ # rl-debug-unlock: force a() to always return true, bypassing the
|
+ const/4 v0, 0x1 # force true
|
||||||
+ # "debug-menu" feature flag check that normally hides the Settings entry.
|
+ return v0 # bypass debug flag
|
||||||
+ const/4 v0, 0x1
|
|
||||||
+ return v0
|
|
||||||
+
|
+
|
||||||
.line 1
|
.line 1
|
||||||
iget-object v0, p0, Lcom/tidal/android/core/debug/DebugFeatureInteractorDefault;->a:Lcom/tidal/android/featureflags/l;
|
iget-object v0, p0, Lcom/tidal/android/core/debug/DebugFeatureInteractorDefault;->a:Lcom/tidal/android/featureflags/l;
|
||||||
|
|
||||||
@@ -97,6 +102,14 @@
|
@@ -98,6 +101,14 @@
|
||||||
}
|
}
|
||||||
.end annotation
|
.end annotation
|
||||||
|
|
||||||
+ # rl-debug-unlock: short-circuit b() to always emit MutableStateFlow(TRUE).
|
+ sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean; # always-true value
|
||||||
+ # Mirrors the original ":cond_1 :goto_0" path the app uses for internal/test builds.
|
|
||||||
+ sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
|
|
||||||
+
|
+
|
||||||
+ invoke-static {v0}, Lkotlinx/coroutines/flow/StateFlowKt;->MutableStateFlow(Ljava/lang/Object;)Lkotlinx/coroutines/flow/MutableStateFlow;
|
+ invoke-static {v0}, Lkotlinx/coroutines/flow/StateFlowKt;->MutableStateFlow(Ljava/lang/Object;)Lkotlinx/coroutines/flow/MutableStateFlow; # wrap in flow
|
||||||
+
|
+
|
||||||
+ move-result-object v0
|
+ move-result-object v0 # the flow
|
||||||
+
|
+
|
||||||
+ return-object v0
|
+ return-object v0 # short-circuit b()
|
||||||
+
|
+
|
||||||
.line 1
|
.line 1
|
||||||
sget-object v0, Lh50/a;->a:Ljava/lang/String;
|
sget-object v0, Lj50/a;->a:Ljava/lang/String;
|
||||||
|
|
||||||
@@ -261,6 +274,11 @@
|
@@ -261,5 +272,8 @@
|
||||||
.method public final c()Z
|
.method public final c()Z
|
||||||
.locals 3
|
.locals 3
|
||||||
|
|
||||||
+ # rl-debug-unlock: force c() to always return true, bypassing the
|
+ const/4 v0, 0x1 # force true
|
||||||
+ # applicationId-substring / in-app-bug-reports / export-logs flag checks.
|
+ return v0 # bypass debug flag
|
||||||
+ const/4 v0, 0x1
|
|
||||||
+ return v0
|
|
||||||
+
|
+
|
||||||
.line 1
|
.line 1
|
||||||
sget-object v0, Lh50/a;->a:Ljava/lang/String;
|
sget-object v0, Lj50/a;->a:Ljava/lang/String;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
--- a/ig/d.smali
|
--- a/kg/e.smali
|
||||||
+++ b/ig/d.smali
|
+++ b/kg/e.smali
|
||||||
@@ -26,8 +26,8 @@
|
@@ -26,8 +26,8 @@
|
||||||
new-instance v0, Lig/d;
|
new-instance v0, Lkg/e;
|
||||||
|
|
||||||
.line 2
|
.line 2
|
||||||
.line 3
|
.line 3
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.class public final Lradiant/NoOp;
|
.class public final Lradiant/NoOp;
|
||||||
.super Ljava/lang/Object;
|
.super Ljava/lang/Object;
|
||||||
.implements Ltl0/a;
|
.implements Lyl0/a;
|
||||||
|
|
||||||
|
|
||||||
# static fields
|
# static fields
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# direct methods
|
# direct methods
|
||||||
.method public static final a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Ltl0/a;)V
|
.method public static final a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
|
||||||
.locals 21
|
.locals 21
|
||||||
.annotation build Landroidx/compose/runtime/Composable;
|
.annotation build Landroidx/compose/runtime/Composable;
|
||||||
.end annotation
|
.end annotation
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
const/4 v4, 0x6
|
const/4 v4, 0x6
|
||||||
|
|
||||||
invoke-static {v2, v11, v4}, Lcom/squareup/ui/market/core/theme/w;->t(Lcom/squareup/ui/market/core/theme/k$a;Landroidx/compose/runtime/Composer;I)Lcom/squareup/ui/market/core/theme/MarketStylesheet;
|
invoke-static {v2, v11, v4}, Lcom/squareup/ui/market/core/theme/x;->t(Lcom/squareup/ui/market/core/theme/k$a;Landroidx/compose/runtime/Composer;I)Lcom/squareup/ui/market/core/theme/MarketStylesheet;
|
||||||
|
|
||||||
move-result-object v15
|
move-result-object v15
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
|
|
||||||
const/16 v18, 0x0
|
const/16 v18, 0x0
|
||||||
|
|
||||||
invoke-static/range {v15 .. v20}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->P(Lcom/squareup/ui/market/core/theme/MarketStylesheet;Lcom/squareup/ui/market/core/components/properties/IconButton$Size;Lcom/squareup/ui/market/core/components/properties/IconButton$Rank;Lcom/squareup/ui/market/core/components/properties/IconButton$Variant;ILjava/lang/Object;)Ll20/v1;
|
invoke-static/range {v15 .. v20}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->P(Lcom/squareup/ui/market/core/theme/MarketStylesheet;Lcom/squareup/ui/market/core/components/properties/IconButton$Size;Lcom/squareup/ui/market/core/components/properties/IconButton$Rank;Lcom/squareup/ui/market/core/components/properties/IconButton$Variant;ILjava/lang/Object;)Ln20/w1;
|
||||||
|
|
||||||
move-result-object v4
|
move-result-object v4
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
:cond_5
|
:cond_5
|
||||||
move-object v9, v4
|
move-object v9, v4
|
||||||
|
|
||||||
check-cast v9, Ll20/v1;
|
check-cast v9, Ln20/w1;
|
||||||
|
|
||||||
sget v2, Lcom/tidal/android/feature/playerscreen/ui/R$string;->lyrics:I
|
sget v2, Lcom/tidal/android/feature/playerscreen/ui/R$string;->lyrics:I
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@
|
|||||||
|
|
||||||
const/4 v8, 0x0
|
const/4 v8, 0x0
|
||||||
|
|
||||||
invoke-static/range {v1 .. v13}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->c(Ltl0/a;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;ZLcom/squareup/ui/market/components/n;Ltl0/a;Ljava/lang/String;Ll20/v1;Ltl0/p;Landroidx/compose/runtime/Composer;II)V
|
invoke-static/range {v1 .. v13}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->c(Lyl0/a;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;ZLcom/squareup/ui/market/components/n;Lyl0/a;Ljava/lang/String;Ln20/w1;Lyl0/p;Landroidx/compose/runtime/Composer;II)V
|
||||||
|
|
||||||
invoke-static {}, Landroidx/compose/runtime/ComposerKt;->isTraceInProgress()Z
|
invoke-static {}, Landroidx/compose/runtime/ComposerKt;->isTraceInProgress()Z
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
.source "SourceFile"
|
.source "SourceFile"
|
||||||
|
|
||||||
# interfaces
|
# interfaces
|
||||||
.implements Ltl0/p;
|
.implements Lyl0/p;
|
||||||
|
|
||||||
|
|
||||||
# virtual methods
|
# virtual methods
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.class public final Lradiant/SpvFactory;
|
.class public final Lradiant/SpvFactory;
|
||||||
.super Ljava/lang/Object;
|
.super Ljava/lang/Object;
|
||||||
.implements Ltl0/l;
|
.implements Lyl0/l;
|
||||||
|
|
||||||
|
|
||||||
# static fields
|
# static fields
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
--- a/com/tidal/android/feature/playerscreen/ui/g0.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/h0.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/g0.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/h0.smali
|
||||||
@@ -666,8 +666,23 @@
|
@@ -669,8 +669,23 @@
|
||||||
move-object v5, v1
|
move-object v5, v1
|
||||||
|
|
||||||
.line 288
|
.line 289
|
||||||
+ const v1, 0x52414443 # group key
|
+ const v1, 0x52414443 # group key
|
||||||
+
|
+
|
||||||
+ invoke-interface {v7, v1}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open group around the cover
|
+ invoke-interface {v7, v1}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open group around the cover
|
||||||
+
|
+
|
||||||
+ iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/g0;->b:Lcom/tidal/android/feature/playerscreen/ui/r$a; # player state
|
+ iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/h0;->b:Lcom/tidal/android/feature/playerscreen/ui/r$a; # player state
|
||||||
+
|
+
|
||||||
+ iget-object v1, v1, Lcom/tidal/android/feature/playerscreen/ui/r$a;->j:Lcom/tidal/android/feature/playerscreen/ui/g; # current view mode
|
+ iget-object v1, v1, Lcom/tidal/android/feature/playerscreen/ui/r$a;->j:Lcom/tidal/android/feature/playerscreen/ui/g; # current view mode
|
||||||
+
|
+
|
||||||
+ instance-of v1, v1, Lcom/tidal/android/feature/playerscreen/ui/g$a; # only render when on cover mode
|
+ instance-of v1, v1, Lcom/tidal/android/feature/playerscreen/ui/g$a; # cover mode only
|
||||||
+
|
+
|
||||||
+ if-eqz v1, :radiant_after_cover # lyrics/credits mode -> skip cover
|
+ if-eqz v1, :radiant_after_cover # lyrics/credits mode -> skip cover
|
||||||
+
|
+
|
||||||
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/CoverPagerKt;->c(Lcom/tidal/android/feature/playerscreen/ui/d;Ltl0/l;FLandroidx/compose/ui/Modifier;ZLandroidx/compose/runtime/Composer;II)V
|
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/CoverPagerKt;->c(Lcom/tidal/android/feature/playerscreen/ui/d;Lyl0/l;FLandroidx/compose/ui/Modifier;ZLandroidx/compose/runtime/Composer;II)V
|
||||||
|
|
||||||
+ :radiant_after_cover
|
+ :radiant_after_cover # skip target
|
||||||
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close group
|
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close group
|
||||||
+
|
+
|
||||||
.line 289
|
|
||||||
.line 290
|
.line 290
|
||||||
.line 291
|
.line 291
|
||||||
|
.line 292
|
||||||
|
|||||||
@@ -1,11 +1,37 @@
|
|||||||
--- a/com/tidal/android/feature/playerscreen/ui/composables/k1.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/composables/o1.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/composables/k1.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/composables/o1.smali
|
||||||
@@ -64,7 +64,7 @@
|
@@ -64,26 +64,29 @@
|
||||||
|
|
||||||
.line 16
|
.line 16
|
||||||
.line 17
|
.line 17
|
||||||
- iget v2, p0, Lcom/tidal/android/feature/playerscreen/ui/composables/k1;->a:F
|
- iget v2, p0, Lcom/tidal/android/feature/playerscreen/ui/composables/o1;->a:F
|
||||||
+ const/high16 v2, 0x43480000 # hardcode top fade region to 200dp (decouple from contentPadding)
|
+ const/high16 v2, 0x43200000 # 160f start dp
|
||||||
|
|
||||||
.line 18
|
.line 18
|
||||||
.line 19
|
.line 19
|
||||||
|
invoke-interface {p1, v2}, Landroidx/compose/ui/unit/Density;->toPx-0680j_4(F)F
|
||||||
|
|
||||||
|
.line 20
|
||||||
|
.line 21
|
||||||
|
.line 22
|
||||||
|
- move-result v3
|
||||||
|
+ move-result v2 # startY in px
|
||||||
|
+
|
||||||
|
+ const/high16 v3, 0x435c0000 # 220f end dp
|
||||||
|
+
|
||||||
|
+ invoke-interface {p1, v3}, Landroidx/compose/ui/unit/Density;->toPx-0680j_4(F)F # dp to px
|
||||||
|
+
|
||||||
|
+ move-result v3 # endY in px
|
||||||
|
|
||||||
|
.line 23
|
||||||
|
const/16 v5, 0x8
|
||||||
|
|
||||||
|
.line 24
|
||||||
|
.line 25
|
||||||
|
const/4 v6, 0x0
|
||||||
|
|
||||||
|
- .line 26
|
||||||
|
- const/4 v2, 0x0
|
||||||
|
-
|
||||||
|
.line 27
|
||||||
|
const/4 v4, 0x0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- a/com/tidal/android/feature/playerscreen/ui/b0.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/c0.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/b0.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/c0.smali
|
||||||
@@ -45,7 +45,7 @@
|
@@ -47,7 +47,7 @@
|
||||||
|
|
||||||
# virtual methods
|
# virtual methods
|
||||||
.method public final invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
.method public final invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
|
|
||||||
.line 1
|
.line 1
|
||||||
move-object/from16 v0, p0
|
move-object/from16 v0, p0
|
||||||
@@ -460,6 +460,64 @@
|
@@ -461,6 +461,64 @@
|
||||||
.line 200
|
.line 200
|
||||||
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/LyricsKt;->a(Lcom/tidal/android/feature/playerscreen/ui/g;Ltl0/l;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;Ltl0/l;Landroidx/compose/runtime/Composer;II)V
|
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/LyricsKt;->a(Lcom/tidal/android/feature/playerscreen/ui/g;Lyl0/l;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;Lyl0/l;Landroidx/compose/runtime/Composer;II)V
|
||||||
|
|
||||||
+ sget-object v17, Lradiant/SpvFactory;->a:Lradiant/SpvFactory; # progress view factory
|
+ sget-object v17, Lradiant/SpvFactory;->a:Lradiant/SpvFactory; # progress view factory
|
||||||
+
|
+
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
+
|
+
|
||||||
+ const/16 v24, 0x0 # synthetic null
|
+ const/16 v24, 0x0 # synthetic null
|
||||||
+
|
+
|
||||||
+ invoke-static/range {v18 .. v24}, Landroidx/compose/foundation/ClickableKt;->clickable-XHw0xAI$default(Landroidx/compose/ui/Modifier;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Ltl0/a;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; # apply clickable
|
+ invoke-static/range {v18 .. v24}, Landroidx/compose/foundation/ClickableKt;->clickable-XHw0xAI$default(Landroidx/compose/ui/Modifier;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Lyl0/a;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; # apply clickable
|
||||||
+
|
+
|
||||||
+ move-result-object v23 # clickable modifier
|
+ move-result-object v23 # clickable modifier
|
||||||
+
|
+
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
+
|
+
|
||||||
+ const/16 v22, 0x4 # default mask
|
+ const/16 v22, 0x4 # default mask
|
||||||
+
|
+
|
||||||
+ invoke-static/range {v17 .. v22}, Landroidx/compose/ui/viewinterop/AndroidView_androidKt;->AndroidView(Ltl0/l;Landroidx/compose/ui/Modifier;Ltl0/l;Landroidx/compose/runtime/Composer;II)V # mount progress pill
|
+ invoke-static/range {v17 .. v22}, Landroidx/compose/ui/viewinterop/AndroidView_androidKt;->AndroidView(Lyl0/l;Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/runtime/Composer;II)V # mount progress pill
|
||||||
+
|
+
|
||||||
.line 201
|
.line 201
|
||||||
.line 202
|
.line 202
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 79
|
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 79
|
||||||
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
@@ -4931,7 +4931,11 @@
|
@@ -4945,7 +4945,11 @@
|
||||||
const/4 v10, 0x0
|
const/4 v7, 0x0
|
||||||
|
|
||||||
.line 226
|
.line 226
|
||||||
- invoke-static {v10, v9, v4, v2, v7}, Lcom/tidal/android/feature/playerscreen/ui/composables/h1;->a(Landroidx/compose/ui/Modifier;Ltl0/a;ZLandroidx/compose/runtime/Composer;I)V
|
- invoke-static {v7, v9, v4, v2, v10}, Lcom/tidal/android/feature/playerscreen/ui/composables/k1;->a(Landroidx/compose/ui/Modifier;Lyl0/a;ZLandroidx/compose/runtime/Composer;I)V
|
||||||
+ const v10, 0x52414448 # empty group key
|
+ const v10, 0x52414448 # empty group key
|
||||||
+
|
+
|
||||||
+ invoke-interface {v2, v10}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
|
+ invoke-interface {v2, v10}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
|
||||||
@@ -14,21 +14,21 @@
|
|||||||
|
|
||||||
.line 227
|
.line 227
|
||||||
invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
|
invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
|
||||||
@@ -5838,6 +5838,22 @@
|
@@ -5720,6 +5724,22 @@
|
||||||
:cond_51
|
:cond_51
|
||||||
check-cast v4, Ltl0/a;
|
check-cast v4, Lyl0/a;
|
||||||
|
|
||||||
const/4 v2, 0x0
|
const/4 v2, 0x0
|
||||||
|
|
||||||
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/h3;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Ltl0/a;)V
|
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/l3;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
|
||||||
+
|
+
|
||||||
+ new-instance v74, Lc8/j; # lyrics-toggle lambda
|
+ new-instance v74, Lcom/tidal/android/feature/playerscreen/ui/g0; # lyrics toggle lambda
|
||||||
+
|
+
|
||||||
+ move-object/from16 v75, p5 # lambda receiver
|
+ move-object/from16 v75, p5 # action dispatcher
|
||||||
+
|
+
|
||||||
+ const/16 v76, 0x1 # lyrics action
|
+ const/16 v76, 0x0 # lyrics action disc
|
||||||
+
|
+
|
||||||
+ invoke-direct/range {v74 .. v76}, Lc8/j;-><init>(Ljava/lang/Object;I)V # build lambda
|
+ invoke-direct/range {v74 .. v76}, Lcom/tidal/android/feature/playerscreen/ui/g0;-><init>(Ljava/lang/Object;I)V # build lambda
|
||||||
+
|
+
|
||||||
+ const/16 v71, 0x0 # changed flags
|
+ const/16 v71, 0x0 # changed flags
|
||||||
+
|
+
|
||||||
@@ -36,4 +36,4 @@
|
|||||||
+
|
+
|
||||||
+ const/16 v73, 0x0 # null modifier
|
+ const/16 v73, 0x0 # null modifier
|
||||||
+
|
+
|
||||||
+ invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Ltl0/a;)V # render sparkle button
|
+ invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V # render sparkle button
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
@@ -5086,7 +5086,11 @@
|
@@ -5094,7 +5094,11 @@
|
||||||
const/4 v13, 0x0
|
const/4 v13, 0x0
|
||||||
|
|
||||||
.line 247
|
.line 247
|
||||||
- invoke-static {v9, v0, v13, v2, v10}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Ltl0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
|
- invoke-static {v9, v0, v10, v2, v13}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Lyl0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
|
||||||
+ const v9, 0x52414244 # empty group key
|
+ const v9, 0x52414244 # empty group key
|
||||||
+
|
+
|
||||||
+ invoke-interface {v2, v9}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
|
+ invoke-interface {v2, v9}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
|
||||||
@@ -13,39 +13,38 @@
|
|||||||
|
|
||||||
.line 248
|
.line 248
|
||||||
invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endNode()V
|
invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endNode()V
|
||||||
@@ -5758,17 +5758,19 @@
|
@@ -5770,16 +5774,20 @@
|
||||||
|
.line 335
|
||||||
:cond_53
|
:cond_53
|
||||||
- new-instance v4, Landroidx/compose/foundation/text/input/internal/selection/l;
|
- new-instance v4, Lcom/aspiro/wamp/tidalconnect/playback/i;
|
||||||
-
|
-
|
||||||
- const/4 v6, 0x2
|
- invoke-direct {v4, v11, v1}, Lcom/aspiro/wamp/tidalconnect/playback/i;-><init>(Ljava/lang/Object;I)V
|
||||||
-
|
|
||||||
- invoke-direct {v4, v11, v6}, Landroidx/compose/foundation/text/input/internal/selection/l;-><init>(Ljava/lang/Object;I)V
|
|
||||||
-
|
-
|
||||||
- .line 336
|
- .line 336
|
||||||
- invoke-interface {v7, v4}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V
|
- invoke-interface {v7, v4}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V
|
||||||
-
|
-
|
||||||
- .line 337
|
- .line 337
|
||||||
- :cond_54
|
- :cond_54
|
||||||
- check-cast v4, Ltl0/a;
|
- check-cast v4, Lyl0/a;
|
||||||
-
|
-
|
||||||
- const/4 v2, 0x0
|
- const/4 v2, 0x0
|
||||||
-
|
-
|
||||||
- invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/u4;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Ltl0/a;)V
|
- invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/x4;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
|
||||||
+ new-instance v4, Lcom/tidal/android/feature/playerscreen/ui/f0; # connect click lambda
|
+ new-instance v4, Lcom/aspiro/wamp/tidalconnect/playback/i; # connect click lambda factory
|
||||||
+
|
+
|
||||||
+ move-object/from16 v6, p5 # action dispatcher
|
+ move-object/from16 v6, p5 # action dispatcher
|
||||||
+
|
+
|
||||||
+ const/4 v8, 0x0 # connect-clicked discriminator
|
+ const/4 v8, 0x1 # connect-clicked disc
|
||||||
+
|
+
|
||||||
+ invoke-direct {v4, v6, v8}, Lcom/tidal/android/feature/playerscreen/ui/f0;-><init>(Ljava/lang/Object;I)V # build lambda
|
+ invoke-direct {v4, v6, v8}, Lcom/aspiro/wamp/tidalconnect/playback/i;-><init>(Ljava/lang/Object;I)V # build lambda
|
||||||
+
|
+
|
||||||
+ invoke-interface {v7, v4}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V # cache lambda
|
+ invoke-interface {v7, v4}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V # cache lambda
|
||||||
+
|
+
|
||||||
+ :cond_54
|
+ :cond_54 # cache join
|
||||||
+ check-cast v4, Ltl0/a;
|
+ check-cast v4, Lyl0/a; # cast to Function0
|
||||||
+
|
+
|
||||||
+ iget-object v8, v10, Lcom/tidal/android/feature/playerscreen/ui/r$a;->d:Lcom/tidal/android/feature/playerscreen/ui/b; # broadcast state
|
+ iget-object v8, v10, Lcom/tidal/android/feature/playerscreen/ui/r$a;->d:Lcom/tidal/android/feature/playerscreen/ui/b; # broadcast state
|
||||||
+
|
+
|
||||||
+ const/4 v2, 0x0 # changed flags
|
+ const/4 v2, 0x0 # changed flags
|
||||||
+
|
+
|
||||||
+ invoke-static {v8, v4, v13, v7, v2}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Ltl0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # render connect button
|
+ invoke-static {v8, v4, v13, v7, v2}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Lyl0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # render connect button
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
@@ -5854,17 +5854,38 @@
|
@@ -5725,17 +5725,38 @@
|
||||||
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/h3;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Ltl0/a;)V
|
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/l3;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
|
||||||
+
|
+
|
||||||
+ iget-boolean v2, v10, Lcom/tidal/android/feature/playerscreen/ui/r$a;->i:Z # hasLyrics flag
|
+ iget-boolean v2, v10, Lcom/tidal/android/feature/playerscreen/ui/r$a;->i:Z # hasLyrics flag
|
||||||
+
|
+
|
||||||
@@ -11,13 +11,13 @@
|
|||||||
+
|
+
|
||||||
+ invoke-interface {v7, v2}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open lyrics branch
|
+ invoke-interface {v7, v2}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open lyrics branch
|
||||||
|
|
||||||
new-instance v74, Lc8/j; # lyrics-toggle lambda
|
new-instance v74, Lcom/tidal/android/feature/playerscreen/ui/g0; # lyrics toggle lambda
|
||||||
|
|
||||||
move-object/from16 v75, p5 # lambda receiver
|
move-object/from16 v75, p5 # action dispatcher
|
||||||
|
|
||||||
const/16 v76, 0x1 # lyrics action
|
const/16 v76, 0x0 # lyrics action disc
|
||||||
|
|
||||||
invoke-direct/range {v74 .. v76}, Lc8/j;-><init>(Ljava/lang/Object;I)V # build lambda
|
invoke-direct/range {v74 .. v76}, Lcom/tidal/android/feature/playerscreen/ui/g0;-><init>(Ljava/lang/Object;I)V # build lambda
|
||||||
|
|
||||||
const/16 v71, 0x0 # changed flags
|
const/16 v71, 0x0 # changed flags
|
||||||
|
|
||||||
@@ -25,17 +25,17 @@
|
|||||||
|
|
||||||
const/16 v73, 0x0 # null modifier
|
const/16 v73, 0x0 # null modifier
|
||||||
|
|
||||||
invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Ltl0/a;)V # render sparkle button
|
invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V # render sparkle button
|
||||||
+
|
+
|
||||||
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close lyrics branch
|
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close lyrics branch
|
||||||
+
|
+
|
||||||
+ goto :goto_sparkle_done # skip empty branch
|
+ goto :goto_sparkle_done # skip empty branch
|
||||||
+
|
+
|
||||||
+ :cond_sparkle_no_lyrics
|
+ :cond_sparkle_no_lyrics # no-lyrics branch
|
||||||
+ const v2, 0x3057f75c # group key (no lyrics)
|
+ const v2, 0x3057f75c # group key (no lyrics)
|
||||||
+
|
+
|
||||||
+ invoke-interface {v7, v2}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
|
+ invoke-interface {v7, v2}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
|
||||||
+
|
+
|
||||||
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
|
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
|
||||||
+
|
+
|
||||||
+ :goto_sparkle_done
|
+ :goto_sparkle_done # join target
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 71
|
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 71
|
||||||
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
|
||||||
@@ -4164,6 +4164,133 @@
|
@@ -4172,6 +4172,133 @@
|
||||||
|
|
||||||
invoke-static {v5, v3, v4}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Ltl0/p;)V
|
invoke-static {v5, v3, v4}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lyl0/p;)V
|
||||||
|
|
||||||
+ const v3, 0x52414449 # group key for slot table
|
+ const v3, 0x52414449 # slot table key
|
||||||
+
|
+
|
||||||
+ invoke-interface {v10, v3}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open group
|
+ invoke-interface {v10, v3}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open group
|
||||||
+
|
+
|
||||||
@@ -13,75 +13,75 @@
|
|||||||
+
|
+
|
||||||
+ iget-object v3, v3, Lcom/tidal/android/feature/playerscreen/ui/r$a;->c:Lcom/tidal/android/feature/playerscreen/ui/d; # cover pager
|
+ iget-object v3, v3, Lcom/tidal/android/feature/playerscreen/ui/r$a;->c:Lcom/tidal/android/feature/playerscreen/ui/d; # cover pager
|
||||||
+
|
+
|
||||||
+ iget-object v4, v3, Lcom/tidal/android/feature/playerscreen/ui/d;->a:Lon0/b; # item list
|
+ iget-object v4, v3, Lcom/tidal/android/feature/playerscreen/ui/d;->a:Ltn0/b; # item list
|
||||||
+
|
+
|
||||||
+ iget v5, v3, Lcom/tidal/android/feature/playerscreen/ui/d;->b:I # current index
|
+ iget v5, v3, Lcom/tidal/android/feature/playerscreen/ui/d;->b:I # current index
|
||||||
+
|
+
|
||||||
+ invoke-interface {v4}, Ljava/util/List;->size()I
|
+ invoke-interface {v4}, Ljava/util/List;->size()I # list size
|
||||||
+
|
+
|
||||||
+ move-result v6
|
+ move-result v6 # size value
|
||||||
+
|
+
|
||||||
+ if-le v6, v5, :radiant_skip # index out of bounds -> skip
|
+ if-le v6, v5, :radiant_skip # bounds check
|
||||||
+
|
+
|
||||||
+ if-ltz v5, :radiant_skip
|
+ if-ltz v5, :radiant_skip # negative check
|
||||||
+
|
+
|
||||||
+ invoke-interface {v4, v5}, Ljava/util/List;->get(I)Ljava/lang/Object;
|
+ invoke-interface {v4, v5}, Ljava/util/List;->get(I)Ljava/lang/Object; # current item
|
||||||
+
|
+
|
||||||
+ move-result-object v4
|
+ move-result-object v4 # current item
|
||||||
+
|
+
|
||||||
+ instance-of v6, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a; # only album covers
|
+ instance-of v6, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a; # only album covers
|
||||||
+
|
+
|
||||||
+ if-eqz v6, :radiant_skip
|
+ if-eqz v6, :radiant_skip # skip non-albums
|
||||||
+
|
+
|
||||||
+ check-cast v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;
|
+ check-cast v4, Lcom/tidal/android/feature/playerscreen/ui/c$a; # narrow type
|
||||||
+
|
+
|
||||||
+ iget v5, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;->b:I # album id
|
+ iget v5, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;->b:I # album id
|
||||||
+
|
+
|
||||||
+ iget-object v4, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;->c:Ljava/lang/String; # cover uuid
|
+ iget-object v4, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;->c:Ljava/lang/String; # cover uuid
|
||||||
+
|
+
|
||||||
+ new-instance v6, Lcom/tidal/android/feature/playerscreen/ui/composables/p0; # tidal's cover request
|
+ new-instance v6, Lcom/tidal/android/feature/playerscreen/ui/composables/n0; # cover request lambda
|
||||||
+
|
+
|
||||||
+ invoke-direct {v6, v5, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/p0;-><init>(ILjava/lang/String;)V
|
+ invoke-direct {v6, v5, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/n0;-><init>(ILjava/lang/String;)V # build request
|
||||||
+
|
+
|
||||||
+ sget-object v5, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion;
|
+ sget-object v5, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion; # base modifier
|
||||||
+
|
+
|
||||||
+ const/4 v7, 0x0
|
+ const/4 v7, 0x0 # fraction unused
|
||||||
+
|
+
|
||||||
+ const/4 v8, 0x1
|
+ const/4 v8, 0x1 # default fraction
|
||||||
+
|
+
|
||||||
+ const/4 v3, 0x0
|
+ const/4 v3, 0x0 # synthetic null
|
||||||
+
|
+
|
||||||
+ invoke-static {v5, v7, v8, v3}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier; # fill the player root
|
+ invoke-static {v5, v7, v8, v3}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier; # fill the player root
|
||||||
+
|
+
|
||||||
+ move-result-object v5
|
+ move-result-object v5 # filled modifier
|
||||||
+
|
+
|
||||||
+ const/high16 v7, 0x42b40000 # 90f (blur radius dp)
|
+ const/high16 v7, 0x42b40000 # 90f blur dp
|
||||||
+
|
+
|
||||||
+ invoke-static {v7}, Landroidx/compose/ui/unit/Dp;->constructor-impl(F)F
|
+ invoke-static {v7}, Landroidx/compose/ui/unit/Dp;->constructor-impl(F)F # to Dp
|
||||||
+
|
+
|
||||||
+ move-result v7
|
+ move-result v7 # blur dp value
|
||||||
+
|
+
|
||||||
+ sget-object v8, Landroidx/compose/ui/draw/BlurredEdgeTreatment;->Companion:Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion;
|
+ sget-object v8, Landroidx/compose/ui/draw/BlurredEdgeTreatment;->Companion:Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion; # blur edge companion
|
||||||
+
|
+
|
||||||
+ invoke-virtual {v8}, Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion;->getRectangle---Goahg()Landroidx/compose/ui/graphics/Shape;
|
+ invoke-virtual {v8}, Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion;->getRectangle---Goahg()Landroidx/compose/ui/graphics/Shape; # rectangle treatment
|
||||||
+
|
+
|
||||||
+ move-result-object v8
|
+ move-result-object v8 # edge shape
|
||||||
+
|
+
|
||||||
+ invoke-static {v5, v7, v8}, Landroidx/compose/ui/draw/BlurKt;->blur-F8QBwvs(Landroidx/compose/ui/Modifier;FLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier; # apply blur
|
+ invoke-static {v5, v7, v8}, Landroidx/compose/ui/draw/BlurKt;->blur-F8QBwvs(Landroidx/compose/ui/Modifier;FLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier; # apply blur
|
||||||
+
|
+
|
||||||
+ move-result-object v5
|
+ move-result-object v5 # blurred modifier
|
||||||
+
|
+
|
||||||
+ sget-object v7, Landroidx/compose/ui/layout/ContentScale;->Companion:Landroidx/compose/ui/layout/ContentScale$Companion;
|
+ sget-object v7, Landroidx/compose/ui/layout/ContentScale;->Companion:Landroidx/compose/ui/layout/ContentScale$Companion; # scale companion
|
||||||
+
|
+
|
||||||
+ invoke-virtual {v7}, Landroidx/compose/ui/layout/ContentScale$Companion;->getCrop()Landroidx/compose/ui/layout/ContentScale; # cover-crop scaling
|
+ invoke-virtual {v7}, Landroidx/compose/ui/layout/ContentScale$Companion;->getCrop()Landroidx/compose/ui/layout/ContentScale; # cover-crop scaling
|
||||||
+
|
+
|
||||||
+ move-result-object v7
|
+ move-result-object v7 # crop scale
|
||||||
+
|
+
|
||||||
+ move-object/from16 v61, v6 # request
|
+ move-object/from16 v61, v6 # request
|
||||||
+
|
+
|
||||||
+ const/16 v62, 0x0 # contentDescription
|
+ const/16 v62, 0x0 # contentDescription
|
||||||
+
|
+
|
||||||
+ move-object/from16 v63, v5 # modifier (blurred + fillMaxSize)
|
+ move-object/from16 v63, v5 # blurred modifier
|
||||||
+
|
+
|
||||||
+ const/16 v64, 0x0 # colorFilter
|
+ const/16 v64, 0x0 # colorFilter
|
||||||
+
|
+
|
||||||
@@ -89,49 +89,49 @@
|
|||||||
+
|
+
|
||||||
+ move-object/from16 v66, v4 # cover uuid
|
+ move-object/from16 v66, v4 # cover uuid
|
||||||
+
|
+
|
||||||
+ const/16 v67, 0x0
|
+ const/16 v67, 0x0 # null onError
|
||||||
+
|
+
|
||||||
+ move-object/from16 v68, v10 # composer
|
+ move-object/from16 v68, v10 # composer
|
||||||
+
|
+
|
||||||
+ const/16 v69, 0x0
|
+ const/16 v69, 0x0 # changed flags
|
||||||
+
|
+
|
||||||
+ const/16 v70, 0x48
|
+ const/16 v70, 0x48 # default mask
|
||||||
+
|
+
|
||||||
+ invoke-static/range {v61 .. v70}, Lsd0/f;->a(Ltl0/l;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/ColorFilter;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/Object;Ltl0/a;Landroidx/compose/runtime/Composer;II)V # render blurred cover
|
+ invoke-static/range {v61 .. v70}, Lxd0/f;->a(Lyl0/l;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/ColorFilter;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/Object;Lyl0/a;Landroidx/compose/runtime/Composer;II)V # render blurred cover
|
||||||
+
|
+
|
||||||
+ sget-object v3, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion; # scrim chain start
|
+ sget-object v3, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion; # scrim chain start
|
||||||
+
|
+
|
||||||
+ const/4 v4, 0x0 # fraction unused
|
+ const/4 v4, 0x0 # fraction unused
|
||||||
+
|
+
|
||||||
+ const/4 v5, 0x1 # $default mask
|
+ const/4 v5, 0x1 # default mask
|
||||||
+
|
+
|
||||||
+ const/4 v6, 0x0 # null obj
|
+ const/4 v6, 0x0 # null obj
|
||||||
+
|
+
|
||||||
+ invoke-static {v3, v4, v5, v6}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier; # fill screen
|
+ invoke-static {v3, v4, v5, v6}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier; # fill screen
|
||||||
+
|
+
|
||||||
+ move-result-object v3 # modifier
|
+ move-result-object v3 # fullscreen modifier
|
||||||
+
|
+
|
||||||
+ const v6, -0x80000000 # 0x80000000 = 50% black
|
+ const v6, -0x80000000 # 50% black ARGB
|
||||||
+
|
+
|
||||||
+ invoke-static {v6}, Landroidx/compose/ui/graphics/ColorKt;->Color(I)J # pack ARGB long
|
+ invoke-static {v6}, Landroidx/compose/ui/graphics/ColorKt;->Color(I)J # pack color long
|
||||||
+
|
+
|
||||||
+ move-result-wide v6 # color
|
+ move-result-wide v6 # color long
|
||||||
+
|
+
|
||||||
+ invoke-static {}, Landroidx/compose/ui/graphics/RectangleShapeKt;->getRectangleShape()Landroidx/compose/ui/graphics/Shape; # rect shape
|
+ invoke-static {}, Landroidx/compose/ui/graphics/RectangleShapeKt;->getRectangleShape()Landroidx/compose/ui/graphics/Shape; # rect shape
|
||||||
+
|
+
|
||||||
+ move-result-object v4 # shape
|
+ move-result-object v4 # rect shape
|
||||||
+
|
+
|
||||||
+ invoke-static {v3, v6, v7, v4}, Landroidx/compose/foundation/BackgroundKt;->background-bw27NRU(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier; # tint with scrim
|
+ invoke-static {v3, v6, v7, v4}, Landroidx/compose/foundation/BackgroundKt;->background-bw27NRU(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier; # tint with scrim
|
||||||
+
|
+
|
||||||
+ move-result-object v3 # modifier
|
+ move-result-object v3 # tinted modifier
|
||||||
+
|
+
|
||||||
+ const/4 v4, 0x0 # $changed flags
|
+ const/4 v4, 0x0 # changed flags
|
||||||
+
|
+
|
||||||
+ invoke-static {v3, v10, v4}, Landroidx/compose/foundation/layout/SpacerKt;->Spacer(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # draw scrim
|
+ invoke-static {v3, v10, v4}, Landroidx/compose/foundation/layout/SpacerKt;->Spacer(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # draw scrim
|
||||||
+
|
+
|
||||||
+ :radiant_skip
|
+ :radiant_skip # skip target
|
||||||
+ invoke-interface {v10}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close group
|
+ invoke-interface {v10}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close group
|
||||||
+
|
+
|
||||||
.line 138
|
.line 138
|
||||||
sget-object v3, Landroidx/compose/foundation/layout/BoxScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/BoxScopeInstance;
|
sget-object v3, Landroidx/compose/foundation/layout/BoxScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/BoxScopeInstance;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user