From 5a42c0c1d2c1f5143f1d1192f64454f3385ab600 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:37:55 +0900 Subject: [PATCH] android, desktop: show database import/export errors (#4601) * android, desktop: show database import/export errors * no line --- .../common/views/database/DatabaseView.kt | 42 ++++++++++++++++--- .../views/migration/MigrateFromDevice.kt | 22 +++++++--- .../common/views/migration/MigrateToDevice.kt | 5 +-- .../commonMain/resources/MR/base/strings.xml | 7 +++- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 3ade14bdce..ecf2aaf371 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -522,9 +522,17 @@ private fun exportArchive( progressIndicator.value = true withLongRunningApi { try { - val archiveFile = exportChatArchive(m, null, chatArchiveName, chatArchiveTime, chatArchiveFile) + val (archiveFile, archiveErrors) = exportChatArchive(m, null, chatArchiveName, chatArchiveTime, chatArchiveFile) chatArchiveFile.value = archiveFile - saveArchiveLauncher.launch(archiveFile.substringAfterLast(File.separator)) + if (archiveErrors.isEmpty()) { + saveArchiveLauncher.launch(archiveFile.substringAfterLast(File.separator)) + } else { + showArchiveExportedWithErrorsAlert(generalGetString(MR.strings.chat_database_exported_save), archiveErrors) { + withLongRunningApi { + saveArchiveLauncher.launch(archiveFile.substringAfterLast(File.separator)) + } + } + } progressIndicator.value = false } catch (e: Error) { AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_exporting_chat_database), e.toString()) @@ -539,7 +547,7 @@ suspend fun exportChatArchive( chatArchiveName: MutableState, chatArchiveTime: MutableState, chatArchiveFile: MutableState -): String { +): Pair> { val archiveTime = Clock.System.now() val ts = SimpleDateFormat("yyyy-MM-dd'T'HHmmss", Locale.US).format(Date.from(archiveTime.toJavaInstant())) val archiveName = "simplex-chat.$ts.zip" @@ -550,7 +558,7 @@ suspend fun exportChatArchive( controller.apiSaveAppSettings(AppSettings.current.prepareForExport()) } wallpapersDir.mkdirs() - m.controller.apiExportArchive(config) + val archiveErrors = m.controller.apiExportArchive(config) if (storagePath == null) { deleteOldArchive(m) m.controller.appPrefs.chatArchiveName.set(archiveName) @@ -559,7 +567,7 @@ suspend fun exportChatArchive( chatArchiveName.value = archiveName chatArchiveTime.value = archiveTime chatArchiveFile.value = archivePath - return archivePath + return archivePath to archiveErrors } private fun deleteOldArchive(m: ChatModel) { @@ -592,6 +600,28 @@ private fun importArchiveAlert( ) } +fun showArchiveImportedWithErrorsAlert(archiveErrors: List) { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.chat_database_imported), + text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database) + "\n\n" + generalGetString(MR.strings.non_fatal_errors_occured_during_import) + archiveErrorsText(archiveErrors)) +} + +fun showArchiveExportedWithErrorsAlert(description: String, archiveErrors: List, onConfirm: () -> Unit) { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.chat_database_exported_title), + text = description + "\n\n" + generalGetString(MR.strings.chat_database_exported_not_all_files) + archiveErrorsText(archiveErrors), + confirmText = generalGetString(MR.strings.chat_database_exported_continue), + onConfirm = onConfirm + ) +} + +private fun archiveErrorsText(errs: List): String = "\n" + errs.map { + when (it) { + is ArchiveError.ArchiveErrorImport -> it.importError + is ArchiveError.ArchiveErrorFile -> "${it.file}: ${it.fileError}" + } +}.joinToString(separator = "\n") + private fun importArchive( m: ChatModel, importedArchiveURI: URI, @@ -621,7 +651,7 @@ private fun importArchive( } } else { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(MR.strings.non_fatal_errors_occured_during_import)) + showArchiveImportedWithErrorsAlert(archiveErrors) } } } catch (e: Error) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt index 3cc5468bbb..c60723ee36 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt @@ -480,12 +480,13 @@ private fun MutableState.exportArchive() { withLongRunningApi { try { getMigrationTempFilesDirectory().mkdir() - val archivePath = exportChatArchive(chatModel, getMigrationTempFilesDirectory(), mutableStateOf(""), mutableStateOf(Instant.DISTANT_PAST), mutableStateOf("")) - val totalBytes = File(archivePath).length() - if (totalBytes > 0L) { - state = MigrationFromState.DatabaseInit(totalBytes, archivePath) + val (archivePath, archiveErrors) = exportChatArchive(chatModel, getMigrationTempFilesDirectory(), mutableStateOf(""), mutableStateOf(Instant.DISTANT_PAST), mutableStateOf("")) + if (archiveErrors.isEmpty()) { + uploadArchive(archivePath) } else { - AlertManager.shared.showAlertMsg(generalGetString(MR.strings.migrate_from_device_exported_file_doesnt_exist)) + showArchiveExportedWithErrorsAlert(generalGetString(MR.strings.chat_database_exported_migrate), archiveErrors) { + uploadArchive(archivePath) + } state = MigrationFromState.UploadConfirmation } } catch (e: Exception) { @@ -498,6 +499,17 @@ private fun MutableState.exportArchive() { } } +private fun MutableState.uploadArchive(archivePath: String) { + val totalBytes = File(archivePath).length() + if (totalBytes > 0L) { + state = MigrationFromState.DatabaseInit(totalBytes, archivePath) + } else { + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.migrate_from_device_exported_file_doesnt_exist)) + state = MigrationFromState.UploadConfirmation + } + +} + suspend fun initTemporaryDatabase(tempDatabaseFile: File, netCfg: NetCfg): Pair? { val (status, ctrl) = chatInitTemporaryDatabase(tempDatabaseFile.absolutePath) showErrorOnMigrationIfNeeded(status) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt index bfb5c350a5..1a1e8426d4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt @@ -597,10 +597,7 @@ private fun MutableState.importArchive(archivePath: String, n val config = ArchiveConfig(archivePath, parentTempDirectory = databaseExportDir.toString()) val archiveErrors = controller.apiImportArchive(config) if (archiveErrors.isNotEmpty()) { - AlertManager.shared.showAlertMsg( - generalGetString(MR.strings.chat_database_imported), - generalGetString(MR.strings.non_fatal_errors_occured_during_import) - ) + showArchiveImportedWithErrorsAlert(archiveErrors) } state = MigrationToState.Passphrase("", netCfg) MigrationToDeviceState.save(MigrationToDeviceState.Passphrase(netCfg)) diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 6a6d8b120f..8c7b772089 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1196,7 +1196,7 @@ Error importing chat database Chat database imported Restart the app to use imported chat database. - Some non-fatal errors occurred during import - you may see Chat console for more details. + Some non-fatal errors occurred during import: Delete chat profile? This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost. Chat database deleted @@ -1222,6 +1222,11 @@ This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes. Delete messages Error changing setting + Chat database exported + You may save the exported archive. + You may migrate the exported database. + Some file(s) were not exported + Continue Save passphrase in Keystore