mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-28 02:54:34 +00:00
migrations UI
This commit is contained in:
+67
-59
@@ -14,11 +14,13 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.app.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.AppPreferences
|
||||
import chat.simplex.app.model.DBEncryptionConfig
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.usersettings.NotificationsMode
|
||||
@@ -40,45 +42,45 @@ fun DatabaseErrorView(
|
||||
var useKeychain by remember { mutableStateOf(appPreferences.storeDBPassphrase.get()) }
|
||||
val context = LocalContext.current
|
||||
val restoreDbFromBackup = remember { mutableStateOf(shouldShowRestoreDbButton(appPreferences, context)) }
|
||||
val saveAndRunChatOnClick: () -> Unit = {
|
||||
|
||||
fun callRunChat(confirmMigrations: MigrationConfirmation? = null) {
|
||||
runChat(dbKey.value, confirmMigrations, chatDbStatus, progressIndicator, appPreferences)
|
||||
}
|
||||
|
||||
fun saveAndRunChatOnClick() {
|
||||
DatabaseUtils.setDatabaseKey(dbKey.value)
|
||||
storedDBKey = dbKey.value
|
||||
appPreferences.storeDBPassphrase.set(true)
|
||||
useKeychain = true
|
||||
appPreferences.initialRandomDBPassphrase.set(false)
|
||||
runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences)
|
||||
callRunChat()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DatabaseErrorDetails(@StringRes title: Int, content: @Composable ColumnScope.() -> Unit) {
|
||||
Text(
|
||||
generalGetString(title),
|
||||
Modifier.padding(start = 16.dp, top = 16.dp, bottom = 24.dp),
|
||||
style = MaterialTheme.typography.h1
|
||||
)
|
||||
SectionView(null, padding = PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF), content)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun fileNameText(dbFile: String) {
|
||||
Text(String.format(generalGetString(R.string.file_with_path), dbFile))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun migrationsText(ms: List<String>) {
|
||||
Text(String.format(generalGetString(R.string.database_migrations), ms.joinToString(", ")))
|
||||
}
|
||||
// val status = chatDbStatus.value
|
||||
// val title = when (status) {
|
||||
// is DBMigrationResult.OK -> ""
|
||||
// is DBMigrationResult.ErrorNotADatabase -> if (useKeychain && !storedDBKey.isNullOrEmpty())
|
||||
// generalGetString(R.string.wrong_passphrase)
|
||||
// else
|
||||
// generalGetString(R.string.encrypted_database)
|
||||
// is DBMigrationResult.ErrorMigration -> when (status.migrationError) {
|
||||
// is MigrationError.Upgrade -> generalGetString(R.string.database_upgrade)
|
||||
// is MigrationError.Downgrade -> generalGetString(R.string.database_downgrade)
|
||||
// is MigrationError.Error -> generalGetString(R.string.incompatible_database_version)
|
||||
// }
|
||||
// is DBMigrationResult.ErrorSQL -> generalGetString(R.string.database_error)
|
||||
// is DBMigrationResult.ErrorKeychain -> generalGetString(R.string.keychain_error)
|
||||
// this can only happen if incorrect parameter is passed
|
||||
// is DBMigrationResult.InvalidConfirmation -> "Invalid migration confirmation"
|
||||
// is DBMigrationResult.Unknown -> generalGetString(R.string.database_error)
|
||||
// null -> "" // should never be here
|
||||
// }
|
||||
|
||||
Column(
|
||||
Modifier.fillMaxSize().verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
// Text(
|
||||
// title,
|
||||
// Modifier.padding(start = 16.dp, top = 16.dp, bottom = 24.dp),
|
||||
// style = MaterialTheme.typography.h1
|
||||
// )
|
||||
// SectionView(null, padding = PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)) {
|
||||
val buttonEnabled = validKey(dbKey.value) && !progressIndicator.value
|
||||
when (val status = chatDbStatus.value) {
|
||||
is DBMigrationResult.ErrorNotADatabase ->
|
||||
@@ -88,40 +90,49 @@ fun DatabaseErrorView(
|
||||
DatabaseKeyField(dbKey, buttonEnabled) {
|
||||
saveAndRunChatOnClick()
|
||||
}
|
||||
SaveAndOpenButton(buttonEnabled, saveAndRunChatOnClick)
|
||||
SaveAndOpenButton(buttonEnabled, ::saveAndRunChatOnClick)
|
||||
SectionSpacer()
|
||||
Text(String.format(generalGetString(R.string.file_with_path), status.dbFile))
|
||||
fileNameText(status.dbFile)
|
||||
}
|
||||
} else {
|
||||
DatabaseErrorDetails(R.string.encrypted_database) {
|
||||
Text(generalGetString(R.string.database_passphrase_is_required))
|
||||
DatabaseKeyField(dbKey, buttonEnabled) {
|
||||
if (useKeychain) saveAndRunChatOnClick() else runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences)
|
||||
}
|
||||
if (useKeychain) {
|
||||
SaveAndOpenButton(buttonEnabled, saveAndRunChatOnClick)
|
||||
DatabaseKeyField(dbKey, buttonEnabled, ::saveAndRunChatOnClick)
|
||||
SaveAndOpenButton(buttonEnabled, ::saveAndRunChatOnClick)
|
||||
} else {
|
||||
OpenChatButton(buttonEnabled) { runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences) }
|
||||
DatabaseKeyField(dbKey, buttonEnabled, { callRunChat() })
|
||||
OpenChatButton(buttonEnabled) { callRunChat() }
|
||||
}
|
||||
}
|
||||
}
|
||||
is DBMigrationResult.ErrorMigration -> when (status.migrationError) {
|
||||
is DBMigrationResult.ErrorMigration -> when (val err = status.migrationError) {
|
||||
is MigrationError.Upgrade ->
|
||||
DatabaseErrorDetails(R.string.database_upgrade) {
|
||||
|
||||
TextButton({ callRunChat(MigrationConfirmation.YesUp) }, Modifier.align(Alignment.CenterHorizontally), enabled = !progressIndicator.value) {
|
||||
Text(generalGetString(R.string.upgrade_and_open_chat))
|
||||
}
|
||||
fileNameText(status.dbFile)
|
||||
migrationsText(err.upMigrations.map { it.upName })
|
||||
}
|
||||
is MigrationError.Downgrade ->
|
||||
DatabaseErrorDetails(R.string.database_downgrade) {
|
||||
|
||||
Text(generalGetString(R.string.database_downgrade_warning), fontWeight = FontWeight.Bold)
|
||||
TextButton({ callRunChat(MigrationConfirmation.YesUpDown) }, Modifier.align(Alignment.CenterHorizontally), enabled = !progressIndicator.value) {
|
||||
Text(generalGetString(R.string.downgrade_and_open_chat))
|
||||
}
|
||||
fileNameText(status.dbFile)
|
||||
migrationsText(err.downMigrations)
|
||||
}
|
||||
is MigrationError.Error ->
|
||||
DatabaseErrorDetails(R.string.incompatible_database_version) {
|
||||
|
||||
fileNameText(status.dbFile)
|
||||
Text(String.format(generalGetString(R.string.error_with_info), mtrErrorDescription(err.mtrError)))
|
||||
}
|
||||
}
|
||||
is DBMigrationResult.ErrorSQL ->
|
||||
DatabaseErrorDetails(R.string.database_error) {
|
||||
Text(String.format(generalGetString(R.string.file_with_path), status.dbFile))
|
||||
fileNameText(status.dbFile)
|
||||
Text(String.format(generalGetString(R.string.error_with_info), status.migrationSQLError))
|
||||
}
|
||||
is DBMigrationResult.ErrorKeychain ->
|
||||
@@ -153,7 +164,6 @@ fun DatabaseErrorView(
|
||||
)
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
if (progressIndicator.value) {
|
||||
Box(
|
||||
@@ -171,18 +181,9 @@ fun DatabaseErrorView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DatabaseErrorDetails(@StringRes title: Int, content: @Composable ColumnScope.() -> Unit) {
|
||||
Text(
|
||||
generalGetString(title),
|
||||
Modifier.padding(start = 16.dp, top = 16.dp, bottom = 24.dp),
|
||||
style = MaterialTheme.typography.h1
|
||||
)
|
||||
SectionView(null, padding = PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF), content)
|
||||
}
|
||||
|
||||
private fun runChat(
|
||||
dbKey: String,
|
||||
confirmMigrations: MigrationConfirmation? = null,
|
||||
chatDbStatus: State<DBMigrationResult?>,
|
||||
progressIndicator: MutableState<Boolean>,
|
||||
prefs: AppPreferences
|
||||
@@ -191,7 +192,7 @@ private fun runChat(
|
||||
if (progressIndicator.value) return@launch
|
||||
progressIndicator.value = true
|
||||
try {
|
||||
SimplexApp.context.initChatController(dbKey)
|
||||
SimplexApp.context.initChatController(dbKey, confirmMigrations)
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "initializeChat ${e.stackTraceToString()}")
|
||||
}
|
||||
@@ -204,18 +205,17 @@ private fun runChat(
|
||||
NotificationsMode.PERIODIC.name -> SimplexApp.context.schedulePeriodicWakeUp()
|
||||
}
|
||||
}
|
||||
is DBMigrationResult.ErrorNotADatabase -> {
|
||||
is DBMigrationResult.ErrorNotADatabase ->
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.wrong_passphrase_title), generalGetString(R.string.enter_correct_passphrase))
|
||||
}
|
||||
is DBMigrationResult.ErrorSQL -> {
|
||||
is DBMigrationResult.ErrorSQL ->
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.database_error), status.migrationSQLError)
|
||||
}
|
||||
is DBMigrationResult.ErrorKeychain -> {
|
||||
is DBMigrationResult.ErrorKeychain ->
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.keychain_error))
|
||||
}
|
||||
is DBMigrationResult.Unknown -> {
|
||||
is DBMigrationResult.Unknown ->
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), status.json)
|
||||
}
|
||||
is DBMigrationResult.InvalidConfirmation ->
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.invalid_migration_confirmation))
|
||||
is DBMigrationResult.ErrorMigration -> {}
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,14 @@ private fun restoreDb(restoreDbFromBackup: MutableState<Boolean>, prefs: AppPref
|
||||
}
|
||||
}
|
||||
|
||||
private fun mtrErrorDescription(err: MTRError): String =
|
||||
when (err) {
|
||||
is MTRError.NoDown ->
|
||||
String.format(generalGetString(R.string.mtr_error_no_down_migration), err.dbMigrations.joinToString(", "))
|
||||
is MTRError.Different ->
|
||||
String.format(generalGetString(R.string.mtr_error_different), err.appMigration, err.dbMigration)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DatabaseKeyField(text: MutableState<String>, enabled: Boolean, onClick: (() -> Unit)? = null) {
|
||||
PassphraseField(
|
||||
|
||||
@@ -829,6 +829,12 @@
|
||||
<string name="incompatible_database_version">Incompatible database version</string>
|
||||
<string name="confirm_database_upgrades">Confirm database upgrades</string>
|
||||
<string name="invalid_migration_confirmation">"Invalid migration confirmation"</string>
|
||||
<string name="upgrade_and_open_chat">Upgrade and open chat</string>
|
||||
<string name="downgrade_and_open_chat">Downgrade and open chat</string>
|
||||
<string name="mtr_error_no_down_migration">database version is newer than the app, but no down migration for: %s</string>
|
||||
<string name="mtr_error_different">different migration in the app/database: %s / %s</string>
|
||||
<string name="database_migrations">Migrations: %s</string>
|
||||
<string name="database_downgrade_warning">"Warning: you may lose some data!"</string>
|
||||
|
||||
<!-- ChatModel.chatRunning interactions -->
|
||||
<string name="chat_is_stopped_indication">Chat is stopped</string>
|
||||
|
||||
Reference in New Issue
Block a user