feat: settings migration (compose) (#1309)

This commit is contained in:
Benjamin 2023-10-13 10:39:10 -07:00 committed by GitHub
parent 5762859906
commit 56a4a7043d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 10 deletions

View file

@ -1,24 +1,36 @@
package app.revanced.manager
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import app.revanced.manager.ui.component.AutoUpdatesDialog
import app.revanced.manager.ui.destination.Destination
import app.revanced.manager.ui.screen.AppInfoScreen
import app.revanced.manager.ui.screen.VersionSelectorScreen
import app.revanced.manager.ui.screen.AppSelectorScreen
import app.revanced.manager.ui.screen.DashboardScreen
import app.revanced.manager.ui.screen.InstallerScreen
import app.revanced.manager.ui.screen.PatchesSelectorScreen
import app.revanced.manager.ui.screen.SettingsScreen
import app.revanced.manager.ui.screen.VersionSelectorScreen
import app.revanced.manager.ui.theme.ReVancedManagerTheme
import app.revanced.manager.ui.theme.Theme
import app.revanced.manager.ui.viewmodel.MainViewModel
import app.revanced.manager.util.tag
import app.revanced.manager.util.toast
import dev.olshevski.navigation.reimagined.AnimatedNavHost
import dev.olshevski.navigation.reimagined.NavBackHandler
import dev.olshevski.navigation.reimagined.navigate
@ -51,9 +63,48 @@ class MainActivity : ComponentActivity() {
NavBackHandler(navController)
val showAutoUpdatesDialog by vm.prefs.showAutoUpdatesDialog.getAsState()
if (showAutoUpdatesDialog) {
AutoUpdatesDialog(vm::applyAutoUpdatePrefs)
val firstLaunch by vm.prefs.firstLaunch.getAsState()
if (firstLaunch) {
var legacyActivityState by rememberSaveable { mutableStateOf(LegacyActivity.NOT_LAUNCHED) }
if (legacyActivityState == LegacyActivity.NOT_LAUNCHED) {
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { result: ActivityResult ->
if (result.resultCode == RESULT_OK) {
if (result.data != null) {
val jsonData = result.data!!.getStringExtra("data")!!
vm.applyLegacySettings(jsonData)
}
} else {
legacyActivityState = LegacyActivity.FAILED
toast(getString(R.string.legacy_import_failed))
}
}
val intent = Intent().apply {
setClassName(
"app.revanced.manager.flutter",
"app.revanced.manager.flutter.ExportSettingsActivity"
)
}
LaunchedEffect(Unit) {
try {
launcher.launch(intent)
} catch (e: Exception) {
if (e !is ActivityNotFoundException) {
toast(getString(R.string.legacy_import_failed))
Log.e(tag, "Failed to launch legacy import activity: $e")
}
legacyActivityState = LegacyActivity.FAILED
}
}
legacyActivityState = LegacyActivity.LAUNCHED
} else if (legacyActivityState == LegacyActivity.FAILED){
AutoUpdatesDialog(vm::applyAutoUpdatePrefs)
}
}
AnimatedNavHost(
@ -120,4 +171,10 @@ class MainActivity : ComponentActivity() {
}
}
}
}
private enum class LegacyActivity {
NOT_LAUNCHED,
LAUNCHED,
FAILED
}
}

View file

@ -19,7 +19,7 @@ class PreferencesManager(
val preferSplits = booleanPreference("prefer_splits", false)
val showAutoUpdatesDialog = booleanPreference("show_auto_updates_dialog", true)
val firstLaunch = booleanPreference("first_launch", true)
val managerAutoUpdates = booleanPreference("manager_auto_updates", false)
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)

View file

@ -1,21 +1,28 @@
package app.revanced.manager.ui.viewmodel
import android.util.Base64
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.revanced.manager.domain.bundles.PatchBundleSource.Companion.asRemoteOrNull
import app.revanced.manager.domain.manager.KeystoreManager
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.repository.PatchBundleRepository
import kotlinx.coroutines.Dispatchers
import app.revanced.manager.domain.repository.PatchSelectionRepository
import app.revanced.manager.domain.repository.SerializedSelection
import app.revanced.manager.ui.theme.Theme
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
class MainViewModel(
private val patchBundleRepository: PatchBundleRepository,
private val patchSelectionRepository: PatchSelectionRepository,
private val keystoreManager: KeystoreManager,
val prefs: PreferencesManager
) : ViewModel() {
fun applyAutoUpdatePrefs(manager: Boolean, patches: Boolean) = viewModelScope.launch {
prefs.showAutoUpdatesDialog.update(false)
prefs.firstLaunch.update(false)
prefs.managerAutoUpdates.update(manager)
if (patches) {
@ -30,4 +37,66 @@ class MainViewModel(
}
}
}
}
fun applyLegacySettings(data: String) = viewModelScope.launch {
val json = Json { ignoreUnknownKeys = true }
val settings = json.decodeFromString<LegacySettings>(data)
settings.themeMode?.let { theme ->
val themeMap = mapOf(
0 to Theme.SYSTEM,
1 to Theme.LIGHT,
2 to Theme.DARK
)
prefs.theme.update(themeMap[theme]!!)
}
settings.useDynamicTheme?.let { dynamicColor ->
prefs.dynamicColor.update(dynamicColor)
}
settings.apiUrl?.let { api ->
prefs.api.update(api.removeSuffix("/"))
}
settings.experimentalPatchesEnabled?.let { allowExperimental ->
prefs.allowExperimental.update(allowExperimental)
}
settings.patchesAutoUpdate?.let { autoUpdate ->
with(patchBundleRepository) {
sources
.first()
.find { it.uid == 0 }
?.asRemoteOrNull
?.setAutoUpdate(autoUpdate)
updateCheck()
}
}
settings.patchesChangeEnabled?.let { disableSelectionWarning ->
prefs.disableSelectionWarning.update(disableSelectionWarning)
}
settings.keystore?.let { keystore ->
val keystoreBytes = Base64.decode(keystore, Base64.DEFAULT)
keystoreManager.import(
"ReVanced",
settings.keystorePassword,
keystoreBytes.inputStream()
)
}
settings.patches?.let { selection ->
patchSelectionRepository.import(0, selection)
}
prefs.firstLaunch.update(false)
}
@Serializable
private data class LegacySettings(
val keystorePassword: String,
val themeMode: Int? = null,
val useDynamicTheme: Boolean? = null,
val apiUrl: String? = null,
val experimentalPatchesEnabled: Boolean? = null,
val patchesAutoUpdate: Boolean? = null,
val patchesChangeEnabled: Boolean? = null,
val keystore: String? = null,
val patches: SerializedSelection? = null,
)
}

View file

@ -24,6 +24,8 @@
<string name="bundle_missing">Missing</string>
<string name="bundle_error">Error</string>
<string name="legacy_import_failed">Could not import legacy settings</string>
<string name="auto_updates_dialog_title">Select updates to receive</string>
<string name="auto_updates_dialog_description">Periodically connect to update providers to check for updates.</string>
<string name="auto_updates_dialog_manager">ReVanced Manager</string>