Skip to content

Commit

Permalink
feat: settings migration (compose) (#1309)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenjaminHalko committed Oct 13, 2023
1 parent 5762859 commit 56a4a70
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 10 deletions.
67 changes: 62 additions & 5 deletions app/src/main/java/app/revanced/manager/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -120,4 +171,10 @@ class MainActivity : ComponentActivity() {
}
}
}
}

private enum class LegacyActivity {
NOT_LAUNCHED,
LAUNCHED,
FAILED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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,
)
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit 56a4a70

Please sign in to comment.