From 0706e6e4640602547ddf1f14ef2ba8dbca01d0c0 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:02:38 +0700 Subject: [PATCH] android: stopping chat after deleting the last user (#3937) * android: stopping chat after deleting the last user * fix for hidden users + onboarding --- .../common/views/call/CallView.android.kt | 2 +- .../chat/simplex/common/model/SimpleXAPI.kt | 30 +++++++++---------- .../chat/simplex/common/platform/Files.kt | 4 +-- .../chat/simplex/common/views/WelcomeView.kt | 3 +- .../common/views/database/DatabaseView.kt | 2 +- .../views/onboarding/CreateSimpleXAddress.kt | 3 +- .../views/usersettings/UserProfilesView.kt | 1 + .../common/views/call/CallView.desktop.kt | 2 +- 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt index f8f9fe14ed..8a958327d8 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt @@ -154,7 +154,7 @@ actual fun ActiveCallView() { setCallSound(call.soundSpeaker, audioViaBluetooth) } withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) } - } catch (e: Error) { + } catch (e: Throwable) { Log.d(TAG,"call status ${r.state.connectionState} not used") } is WCallResponse.Connected -> { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 85ce8dc00b..0d6420dad2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -75,7 +75,7 @@ class AppPreferences { val value = _callOnLockScreen.get() ?: return CallOnLockScreen.default return try { CallOnLockScreen.valueOf(value) - } catch (e: Error) { + } catch (e: Throwable) { CallOnLockScreen.default } }, @@ -95,7 +95,7 @@ class AppPreferences { val value = _simplexLinkMode.get() ?: return SimplexLinkMode.default return try { SimplexLinkMode.valueOf(value) - } catch (e: Error) { + } catch (e: Throwable) { SimplexLinkMode.default } }, @@ -123,7 +123,7 @@ class AppPreferences { val value = _networkSessionMode.get() ?: return TransportSessionMode.default return try { TransportSessionMode.valueOf(value) - } catch (e: Error) { + } catch (e: Throwable) { TransportSessionMode.default } }, @@ -393,7 +393,7 @@ object ChatController { } Log.d(TAG, "startChat: running") } - } catch (e: Error) { + } catch (e: Throwable) { Log.e(TAG, "failed starting chat $e") throw e } @@ -411,7 +411,7 @@ object ChatController { startReceiver() setLocalDeviceName(appPrefs.deviceNameForRemoteAccess.get()!!) Log.d(TAG, "startChat: started without user") - } catch (e: Error) { + } catch (e: Throwable) { Log.e(TAG, "failed starting chat without user $e") throw e } @@ -628,7 +628,7 @@ object ChatController { when (r) { is CR.ChatStarted -> return true is CR.ChatRunning -> return false - else -> throw Error("failed starting chat: ${r.responseType} ${r.details}") + else -> throw Exception("failed starting chat: ${r.responseType} ${r.details}") } } @@ -636,26 +636,26 @@ object ChatController { val r = sendCmd(null, CC.ApiStopChat()) when (r) { is CR.ChatStopped -> return true - else -> throw Error("failed stopping chat: ${r.responseType} ${r.details}") + else -> throw Exception("failed stopping chat: ${r.responseType} ${r.details}") } } suspend fun apiSetTempFolder(tempFolder: String, ctrl: ChatCtrl? = null) { val r = sendCmd(null, CC.SetTempFolder(tempFolder), ctrl) if (r is CR.CmdOk) return - throw Error("failed to set temp folder: ${r.responseType} ${r.details}") + throw Exception("failed to set temp folder: ${r.responseType} ${r.details}") } suspend fun apiSetFilesFolder(filesFolder: String, ctrl: ChatCtrl? = null) { val r = sendCmd(null, CC.SetFilesFolder(filesFolder), ctrl) if (r is CR.CmdOk) return - throw Error("failed to set files folder: ${r.responseType} ${r.details}") + throw Exception("failed to set files folder: ${r.responseType} ${r.details}") } suspend fun apiSetRemoteHostsFolder(remoteHostsFolder: String) { val r = sendCmd(null, CC.SetRemoteHostsFolder(remoteHostsFolder)) if (r is CR.CmdOk) return - throw Error("failed to set remote hosts folder: ${r.responseType} ${r.details}") + throw Exception("failed to set remote hosts folder: ${r.responseType} ${r.details}") } suspend fun apiSetEncryptLocalFiles(enable: Boolean) = sendCommandOkResp(null, CC.ApiSetEncryptLocalFiles(enable)) @@ -663,13 +663,13 @@ object ChatController { suspend fun apiSaveAppSettings(settings: AppSettings) { val r = sendCmd(null, CC.ApiSaveSettings(settings)) if (r is CR.CmdOk) return - throw Error("failed to set app settings: ${r.responseType} ${r.details}") + throw Exception("failed to set app settings: ${r.responseType} ${r.details}") } suspend fun apiGetAppSettings(settings: AppSettings): AppSettings { val r = sendCmd(null, CC.ApiGetSettings(settings)) if (r is CR.AppSettingsR) return r.appSettings - throw Error("failed to get app settings: ${r.responseType} ${r.details}") + throw Exception("failed to get app settings: ${r.responseType} ${r.details}") } suspend fun apiSetPQEncryption(enable: Boolean) = sendCommandOkResp(null, CC.ApiSetPQEncryption(enable)) @@ -684,19 +684,19 @@ object ChatController { suspend fun apiExportArchive(config: ArchiveConfig) { val r = sendCmd(null, CC.ApiExportArchive(config)) if (r is CR.CmdOk) return - throw Error("failed to export archive: ${r.responseType} ${r.details}") + throw Exception("failed to export archive: ${r.responseType} ${r.details}") } suspend fun apiImportArchive(config: ArchiveConfig): List { val r = sendCmd(null, CC.ApiImportArchive(config)) if (r is CR.ArchiveImported) return r.archiveErrors - throw Error("failed to import archive: ${r.responseType} ${r.details}") + throw Exception("failed to import archive: ${r.responseType} ${r.details}") } suspend fun apiDeleteStorage() { val r = sendCmd(null, CC.ApiDeleteStorage()) if (r is CR.CmdOk) return - throw Error("failed to delete storage: ${r.responseType} ${r.details}") + throw Exception("failed to delete storage: ${r.responseType} ${r.details}") } suspend fun apiStorageEncryption(currentKey: String = "", newKey: String = ""): CR.ChatCmdError? { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt index 7ae2ab23dd..f804f2079c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt @@ -42,7 +42,7 @@ fun copyFileToFile(from: File, to: URI, finally: () -> Unit) { } } showToast(generalGetString(MR.strings.file_saved)) - } catch (e: Error) { + } catch (e: Throwable) { showToast(generalGetString(MR.strings.error_saving_file)) Log.e(TAG, "copyFileToFile error saving file $e") } finally { @@ -58,7 +58,7 @@ fun copyBytesToFile(bytes: ByteArrayInputStream, to: URI, finally: () -> Unit) { } } showToast(generalGetString(MR.strings.file_saved)) - } catch (e: Error) { + } catch (e: Throwable) { showToast(generalGetString(MR.strings.error_saving_file)) Log.e(TAG, "copyBytesToFile error saving file $e") } finally { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt index aa6b22fcde..41b30be640 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt @@ -214,7 +214,8 @@ fun createProfileOnboarding(chatModel: ChatModel, displayName: String, close: () ) ?: return@withBGApi chatModel.localUserCreated.value = true val onboardingStage = chatModel.controller.appPrefs.onboardingStage - if (chatModel.users.isEmpty()) { + // No users or no visible users + if (chatModel.users.none { u -> !u.user.hidden }) { onboardingStage.set(if (appPlatform.isDesktop && chatModel.controller.appPrefs.initialRandomDBPassphrase.get() && !chatModel.desktopOnboardingRandomPassword.value) { OnboardingStage.Step2_5_SetupDatabasePassphrase } else { 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 023d10c539..814ff9969a 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 @@ -388,7 +388,7 @@ fun startChat(m: ChatModel, chatLastStart: MutableState, chatDbChanged m.controller.appPrefs.chatLastStart.set(ts) chatLastStart.value = ts platform.androidChatStartedAfterBeingOff() - } catch (e: Error) { + } catch (e: Throwable) { m.chatRunning.value = false AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_starting_chat), e.toString()) } finally { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt index e8ba5d7b60..5e50475951 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt @@ -169,7 +169,8 @@ private fun ProgressIndicator() { } private fun prepareChatBeforeAddressCreation(rhId: Long?) { - if (chatModel.users.isNotEmpty()) return + // No visible users but may have hidden. In this case chat should be started anyway because it's stopped on this stage with hidden users + if (chatModel.users.any { u -> !u.user.hidden }) return withBGApi { val user = chatModel.controller.apiGetActiveUser(rhId) ?: return@withBGApi chatModel.currentUser.value = user diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt index a7e57662b5..b40cc7db92 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt @@ -356,6 +356,7 @@ private suspend fun doRemoveUser(m: ChatModel, user: User, users: List, de m.controller.apiDeleteUser(user, delSMPQueues, viewPwd) m.controller.changeActiveUser_(user.remoteHostId, null, null) if (appPlatform.isAndroid) { + m.controller.apiStopChat() controller.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) ModalManager.closeAllModalsEverywhere() } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/call/CallView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/call/CallView.desktop.kt index f35b114740..87c2d3e8f2 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/call/CallView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/call/CallView.desktop.kt @@ -75,7 +75,7 @@ actual fun ActiveCallView() { chatModel.activeCall.value = call.copy(callState = CallState.Connected, connectedAt = Clock.System.now()) } withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) } - } catch (e: Error) { + } catch (e: Throwable) { Log.d(TAG, "call status ${r.state.connectionState} not used") } is WCallResponse.Connected -> {