diff --git a/app/src/main/java/app/revanced/manager/MainActivity.kt b/app/src/main/java/app/revanced/manager/MainActivity.kt index 72f046dc..2dfc1f58 100644 --- a/app/src/main/java/app/revanced/manager/MainActivity.kt +++ b/app/src/main/java/app/revanced/manager/MainActivity.kt @@ -1,10 +1,13 @@ package app.revanced.manager +import android.content.ActivityNotFoundException import android.os.Bundle import android.os.Parcelable import androidx.activity.ComponentActivity +import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable @@ -46,12 +49,22 @@ class MainActivity : ComponentActivity() { installSplashScreen() val vm: MainViewModel = getActivityViewModel() - vm.importLegacySettings(this) setContent { + val launcher = rememberLauncherForActivityResult( + ActivityResultContracts.StartActivityForResult(), + onResult = vm::applyLegacySettings + ) val theme by vm.prefs.theme.getAsState() val dynamicColor by vm.prefs.dynamicColor.getAsState() + EventEffect(vm.legacyImportActivityFlow) { + try { + launcher.launch(it) + } catch (_: ActivityNotFoundException) { + } + } + ReVancedManagerTheme( darkTheme = theme == Theme.SYSTEM && isSystemInDarkTheme() || theme == Theme.DARK, dynamicColor = dynamicColor diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt index d665efb0..dd87c084 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt @@ -2,13 +2,10 @@ package app.revanced.manager.ui.viewmodel import android.app.Activity import android.app.Application -import android.content.ActivityNotFoundException import android.content.Intent import android.util.Base64 import android.util.Log -import androidx.activity.ComponentActivity import androidx.activity.result.ActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.revanced.manager.R @@ -28,6 +25,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json class MainViewModel( @@ -36,10 +34,13 @@ class MainViewModel( private val downloadedAppRepository: DownloadedAppRepository, private val keystoreManager: KeystoreManager, private val app: Application, - val prefs: PreferencesManager + val prefs: PreferencesManager, + private val json: Json ) : ViewModel() { private val appSelectChannel = Channel() val appSelectFlow = appSelectChannel.receiveAsFlow() + private val legacyImportActivityChannel = Channel() + val legacyImportActivityFlow = legacyImportActivityChannel.receiveAsFlow() private suspend fun suggestedVersion(packageName: String) = patchBundleRepository.suggestedVersions.first()[packageName] @@ -50,7 +51,8 @@ class MainViewModel( val suggestedVersion = suggestedVersion(app.packageName) ?: return null val downloadedApp = - downloadedAppRepository.get(app.packageName, suggestedVersion, markUsed = true) ?: return null + downloadedAppRepository.get(app.packageName, suggestedVersion, markUsed = true) + ?: return null return SelectedApp.Local( downloadedApp.packageName, downloadedApp.version, @@ -67,42 +69,46 @@ class MainViewModel( selectApp(SelectedApp.Search(packageName, suggestedVersion(packageName))) } - fun importLegacySettings(componentActivity: ComponentActivity) { - if (!prefs.firstLaunch.getBlocking()) return - - try { - val launcher = componentActivity.registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result: ActivityResult -> - if (result.resultCode == Activity.RESULT_OK) { - result.data?.getStringExtra("data")?.let { - applyLegacySettings(it) - } ?: app.toast(app.getString(R.string.legacy_import_failed)) - } else { - app.toast(app.getString(R.string.legacy_import_failed)) - } - } - - val intent = Intent().apply { + init { + viewModelScope.launch { + if (!prefs.firstLaunch.get()) return@launch + legacyImportActivityChannel.send(Intent().apply { setClassName( "app.revanced.manager.flutter", "app.revanced.manager.flutter.ExportSettingsActivity" ) - } - - launcher.launch(intent) - } catch (e: Exception) { - if (e !is ActivityNotFoundException) { - app.toast(app.getString(R.string.legacy_import_failed)) - Log.e(tag, "Failed to launch legacy import activity: $e") - } + }) } } - private fun applyLegacySettings(data: String) = viewModelScope.launch { - val json = Json { ignoreUnknownKeys = true } - val settings = json.decodeFromString(data) + fun applyLegacySettings(result: ActivityResult) { + if (result.resultCode != Activity.RESULT_OK) { + app.toast(app.getString(R.string.legacy_import_failed)) + Log.e( + tag, + "Got unknown result code while importing legacy settings: ${result.resultCode}" + ) + return + } + val jsonStr = result.data?.getStringExtra("data") + if (jsonStr == null) { + app.toast(app.getString(R.string.legacy_import_failed)) + Log.e(tag, "Legacy settings data is null") + return + } + val settings = try { + json.decodeFromString(jsonStr) + } catch (e: SerializationException) { + app.toast(app.getString(R.string.legacy_import_failed)) + Log.e(tag, "Legacy settings data could not be deserialized", e) + return + } + + applyLegacySettings(settings) + } + + private fun applyLegacySettings(settings: LegacySettings) = viewModelScope.launch { settings.themeMode?.let { theme -> val themeMap = mapOf( 0 to Theme.SYSTEM, @@ -145,6 +151,7 @@ class MainViewModel( settings.patches?.let { selection -> patchSelectionRepository.import(0, selection) } + Log.d(tag, "Imported legacy settings") } @Serializable