From 9580b4110deb80ffbf9d54504f596c2b836c55bc Mon Sep 17 00:00:00 2001 From: Jesse Horne Date: Thu, 30 Nov 2023 07:43:01 -0500 Subject: [PATCH 1/2] desktop: remember window position and size (#3465) * initial work on storing desktop window position and size * removed useless imports * updated to use app preferences * vars to vals * defensive programming * fixed default * removed default json * do nothing if encoding to json while storing fails * names, clean up * move comment * changes --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Co-authored-by: Avently <7953703+avently@users.noreply.github.com> --- .../chat/simplex/common/model/SimpleXAPI.kt | 3 ++ .../kotlin/chat/simplex/common/DesktopApp.kt | 29 ++++++++++++--- .../chat/simplex/common/StoreWindowState.kt | 36 +++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/StoreWindowState.kt 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 83ae90cb2..4438329a6 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 @@ -173,6 +173,8 @@ class AppPreferences { val connectRemoteViaMulticastAuto = mkBoolPreference(SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST_AUTO, true) val offerRemoteMulticast = mkBoolPreference(SHARED_PREFS_OFFER_REMOTE_MULTICAST, true) + val desktopWindowState = mkStrPreference(SHARED_PREFS_DESKTOP_WINDOW_STATE, null) + private fun mkIntPreference(prefName: String, default: Int) = SharedPreference( get = fun() = settings.getInt(prefName, default), @@ -317,6 +319,7 @@ class AppPreferences { private const val SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST = "ConnectRemoteViaMulticast" private const val SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "ConnectRemoteViaMulticastAuto" private const val SHARED_PREFS_OFFER_REMOTE_MULTICAST = "OfferRemoteMulticast" + private const val SHARED_PREFS_DESKTOP_WINDOW_STATE = "DesktopWindowState" } } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt index 33453f5e8..d6cc9c7bb 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* import chat.simplex.common.model.ChatController import chat.simplex.common.model.ChatModel -import chat.simplex.common.platform.desktopPlatform import chat.simplex.common.ui.theme.DEFAULT_START_MODAL_WIDTH import chat.simplex.common.ui.theme.SimpleXTheme import chat.simplex.common.views.TerminalView @@ -31,10 +30,30 @@ import java.io.File val simplexWindowState = SimplexWindowState() fun showApp() = application { - // For some reason on Linux actual width will be 10.dp less after specifying it here. If we specify 1366, - // it will show 1356. But after that we can still update it to 1366 by changing window state. Just making it +10 now here - val width = if (desktopPlatform.isLinux()) 1376.dp else 1366.dp - val windowState = rememberWindowState(placement = WindowPlacement.Floating, width = width, height = 768.dp) + // Creates file if not exists; comes with proper defaults + val state = getStoredWindowState() + + val windowState: WindowState = rememberWindowState( + placement = WindowPlacement.Floating, + width = state.width.dp, + height = state.height.dp, + position = WindowPosition(state.x.dp, state.y.dp) + ) + + LaunchedEffect( + windowState.position.x.value, + windowState.position.y.value, + windowState.size.width.value, + windowState.size.height.value + ) { + storeWindowState(WindowPositionSize( + x = windowState.position.x.value.toInt(), + y = windowState.position.y.value.toInt(), + width = windowState.size.width.value.toInt(), + height = windowState.size.height.value.toInt() + )) + } + simplexWindowState.windowState = windowState // Reload all strings in all @Composable's after language change at runtime if (remember { ChatController.appPrefs.appLanguage.state }.value != "") { diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/StoreWindowState.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/StoreWindowState.kt new file mode 100644 index 000000000..2a1a26df9 --- /dev/null +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/StoreWindowState.kt @@ -0,0 +1,36 @@ +package chat.simplex.common + +import chat.simplex.common.model.json +import chat.simplex.common.platform.appPreferences +import chat.simplex.common.platform.desktopPlatform +import kotlinx.serialization.* + +@Serializable +data class WindowPositionSize( + val width: Int = 1366, + val height: Int = 768, + val x: Int = 0, + val y: Int = 0, +) + +fun getStoredWindowState(): WindowPositionSize = + try { + val str = appPreferences.desktopWindowState.get() + var state = if (str == null) { + WindowPositionSize() + } else { + json.decodeFromString(str) + } + + // For some reason on Linux actual width will be 10.dp less after specifying it here. If we specify 1366, + // it will show 1356. But after that we can still update it to 1366 by changing window state. Just making it +10 now here + if (desktopPlatform.isLinux() && state.width == 1366) { + state = state.copy(width = 1376) + } + state + } catch (e: Throwable) { + WindowPositionSize() + } + +fun storeWindowState(state: WindowPositionSize) = + appPreferences.desktopWindowState.set(json.encodeToString(state)) From 5819e423052edbf4cac6d5660d095701a1b794b6 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:31:32 +0400 Subject: [PATCH 2/2] core: remove CRNewContactConnection response; mobile, desktop: create pending connections based on api responses (CRNewContactConnection was being used as "event" in UI) (#3489) --- apps/ios/Shared/Model/SimpleXAPI.swift | 28 +++++--------- .../Shared/Views/NewChat/CreateLinkView.swift | 1 + .../Shared/Views/NewChat/NewChatButton.swift | 8 +++- apps/ios/SimpleXChat/APITypes.swift | 13 +++---- .../chat/simplex/common/model/SimpleXAPI.kt | 38 +++++++------------ .../common/views/newchat/CreateLinkView.kt | 1 + .../common/views/newchat/ScanToConnectView.kt | 8 ++-- .../typescript/src/response.ts | 7 ---- src/Simplex/Chat.hs | 7 +--- src/Simplex/Chat/Controller.hs | 5 +-- src/Simplex/Chat/View.hs | 5 +-- 11 files changed, 46 insertions(+), 75 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index bb01b631b..19030a284 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -605,27 +605,29 @@ func apiConnectPlan(connReq: String) async throws -> ConnectionPlan { throw r } -func apiConnect(incognito: Bool, connReq: String) async -> ConnReqType? { - let (connReqType, alert) = await apiConnect_(incognito: incognito, connReq: connReq) +func apiConnect(incognito: Bool, connReq: String) async -> (ConnReqType, PendingContactConnection)? { + let (r, alert) = await apiConnect_(incognito: incognito, connReq: connReq) if let alert = alert { AlertManager.shared.showAlert(alert) return nil } else { - return connReqType + return r } } -func apiConnect_(incognito: Bool, connReq: String) async -> (ConnReqType?, Alert?) { +func apiConnect_(incognito: Bool, connReq: String) async -> ((ConnReqType, PendingContactConnection)?, Alert?) { guard let userId = ChatModel.shared.currentUser?.userId else { logger.error("apiConnect: no current user") return (nil, nil) } let r = await chatSendCmd(.apiConnect(userId: userId, incognito: incognito, connReq: connReq)) + let m = ChatModel.shared switch r { - case .sentConfirmation: return (.invitation, nil) - case .sentInvitation: return (.contact, nil) + case let .sentConfirmation(_, connection): + return ((.invitation, connection), nil) + case let .sentInvitation(_, connection): + return ((.contact, connection), nil) case let .contactAlreadyExists(_, contact): - let m = ChatModel.shared if let c = m.getContactChat(contact.contactId) { await MainActor.run { m.chatId = c.id } } @@ -1362,18 +1364,6 @@ func processReceivedMsg(_ res: ChatResponse) async { let m = ChatModel.shared logger.debug("processReceivedMsg: \(res.responseType)") switch res { - case let .newContactConnection(user, connection): - if active(user) { - await MainActor.run { - m.updateContactConnection(connection) - } - } - case let .contactConnectionDeleted(user, connection): - if active(user) { - await MainActor.run { - m.removeChat(connection.id) - } - } case let .contactDeletedByContact(user, contact): if active(user) && contact.directOrUsed { await MainActor.run { diff --git a/apps/ios/Shared/Views/NewChat/CreateLinkView.swift b/apps/ios/Shared/Views/NewChat/CreateLinkView.swift index 0b9cfe7a1..3be9e1c3b 100644 --- a/apps/ios/Shared/Views/NewChat/CreateLinkView.swift +++ b/apps/ios/Shared/Views/NewChat/CreateLinkView.swift @@ -73,6 +73,7 @@ struct CreateLinkView: View { Task { if let (connReq, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) { await MainActor.run { + m.updateContactConnection(pcc) connReqInvitation = connReq contactConnection = pcc m.connReqInv = connReq diff --git a/apps/ios/Shared/Views/NewChat/NewChatButton.swift b/apps/ios/Shared/Views/NewChat/NewChatButton.swift index 637c01032..170805b48 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatButton.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatButton.swift @@ -52,6 +52,9 @@ struct NewChatButton: View { func addContactAction() { Task { if let (connReq, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) { + await MainActor.run { + ChatModel.shared.updateContactConnection(pcc) + } actionSheet = .createLink(link: connReq, connection: pcc) } } @@ -346,7 +349,10 @@ private func connectContactViaAddress_(_ contact: Contact, dismiss: Bool, incogn private func connectViaLink(_ connectionLink: String, connectionPlan: ConnectionPlan?, dismiss: Bool, incognito: Bool) { Task { - if let connReqType = await apiConnect(incognito: incognito, connReq: connectionLink) { + if let (connReqType, pcc) = await apiConnect(incognito: incognito, connReq: connectionLink) { + await MainActor.run { + ChatModel.shared.updateContactConnection(pcc) + } let crt: ConnReqType if let plan = connectionPlan { crt = planToConnReqType(plan) diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 9128f67f2..3d2c21392 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -505,8 +505,8 @@ public enum ChatResponse: Decodable, Error { case invitation(user: UserRef, connReqInvitation: String, connection: PendingContactConnection) case connectionIncognitoUpdated(user: UserRef, toConnection: PendingContactConnection) case connectionPlan(user: UserRef, connectionPlan: ConnectionPlan) - case sentConfirmation(user: UserRef) - case sentInvitation(user: UserRef) + case sentConfirmation(user: UserRef, connection: PendingContactConnection) + case sentInvitation(user: UserRef, connection: PendingContactConnection) case sentInvitationToContact(user: UserRef, contact: Contact, customUserProfile: Profile?) case contactAlreadyExists(user: UserRef, contact: Contact) case contactRequestAlreadyAccepted(user: UserRef, contact: Contact) @@ -605,7 +605,6 @@ public enum ChatResponse: Decodable, Error { case ntfTokenStatus(status: NtfTknStatus) case ntfToken(token: DeviceToken, status: NtfTknStatus, ntfMode: NotificationsMode) case ntfMessages(user_: User?, connEntity: ConnectionEntity?, msgTs: Date?, ntfMessages: [NtfMsgInfo]) - case newContactConnection(user: UserRef, connection: PendingContactConnection) case contactConnectionDeleted(user: UserRef, connection: PendingContactConnection) // remote desktop responses/events case remoteCtrlList(remoteCtrls: [RemoteCtrlInfo]) @@ -752,7 +751,6 @@ public enum ChatResponse: Decodable, Error { case .ntfTokenStatus: return "ntfTokenStatus" case .ntfToken: return "ntfToken" case .ntfMessages: return "ntfMessages" - case .newContactConnection: return "newContactConnection" case .contactConnectionDeleted: return "contactConnectionDeleted" case .remoteCtrlList: return "remoteCtrlList" case .remoteCtrlFound: return "remoteCtrlFound" @@ -803,11 +801,11 @@ public enum ChatResponse: Decodable, Error { case let .contactCode(u, contact, connectionCode): return withUser(u, "contact: \(String(describing: contact))\nconnectionCode: \(connectionCode)") case let .groupMemberCode(u, groupInfo, member, connectionCode): return withUser(u, "groupInfo: \(String(describing: groupInfo))\nmember: \(String(describing: member))\nconnectionCode: \(connectionCode)") case let .connectionVerified(u, verified, expectedCode): return withUser(u, "verified: \(verified)\nconnectionCode: \(expectedCode)") - case let .invitation(u, connReqInvitation, _): return withUser(u, connReqInvitation) + case let .invitation(u, connReqInvitation, connection): return withUser(u, "connReqInvitation: \(connReqInvitation)\nconnection: \(connection)") case let .connectionIncognitoUpdated(u, toConnection): return withUser(u, String(describing: toConnection)) case let .connectionPlan(u, connectionPlan): return withUser(u, String(describing: connectionPlan)) - case .sentConfirmation: return noDetails - case .sentInvitation: return noDetails + case let .sentConfirmation(u, connection): return withUser(u, String(describing: connection)) + case let .sentInvitation(u, connection): return withUser(u, String(describing: connection)) case let .sentInvitationToContact(u, contact, _): return withUser(u, String(describing: contact)) case let .contactAlreadyExists(u, contact): return withUser(u, String(describing: contact)) case let .contactRequestAlreadyAccepted(u, contact): return withUser(u, String(describing: contact)) @@ -900,7 +898,6 @@ public enum ChatResponse: Decodable, Error { case let .ntfTokenStatus(status): return String(describing: status) case let .ntfToken(token, status, ntfMode): return "token: \(token)\nstatus: \(status.rawValue)\nntfMode: \(ntfMode.rawValue)" case let .ntfMessages(u, connEntity, msgTs, ntfMessages): return withUser(u, "connEntity: \(String(describing: connEntity))\nmsgTs: \(String(describing: msgTs))\nntfMessages: \(String(describing: ntfMessages))") - case let .newContactConnection(u, connection): return withUser(u, String(describing: connection)) case let .contactConnectionDeleted(u, connection): return withUser(u, String(describing: connection)) case let .remoteCtrlList(remoteCtrls): return String(describing: remoteCtrls) case let .remoteCtrlFound(remoteCtrl, ctrlAppInfo_, appVersion, compatible): return "remoteCtrl:\n\(String(describing: remoteCtrl))\nctrlAppInfo_:\n\(String(describing: ctrlAppInfo_))\nappVersion: \(appVersion)\ncompatible: \(compatible)" 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 4438329a6..34b6fd99f 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 @@ -894,20 +894,21 @@ object ChatController { return null } - suspend fun apiConnect(rh: Long?, incognito: Boolean, connReq: String): Boolean { + suspend fun apiConnect(rh: Long?, incognito: Boolean, connReq: String): PendingContactConnection? { val userId = chatModel.currentUser.value?.userId ?: run { Log.e(TAG, "apiConnect: no current user") - return false + return null } val r = sendCmd(rh, CC.APIConnect(userId, incognito, connReq)) when { - r is CR.SentConfirmation || r is CR.SentInvitation -> return true + r is CR.SentConfirmation -> return r.connection + r is CR.SentInvitation -> return r.connection r is CR.ContactAlreadyExists -> { AlertManager.shared.showAlertMsg( generalGetString(MR.strings.contact_already_exists), String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), r.contact.displayName) ) - return false + return null } r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat && r.chatError.errorType is ChatErrorType.InvalidConnReq -> { @@ -915,7 +916,7 @@ object ChatController { generalGetString(MR.strings.invalid_connection_link), generalGetString(MR.strings.please_check_correct_link_and_maybe_ask_for_a_new_one) ) - return false + return null } r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent && r.chatError.agentError is AgentErrorType.SMP @@ -924,13 +925,13 @@ object ChatController { generalGetString(MR.strings.connection_error_auth), generalGetString(MR.strings.connection_error_auth_desc) ) - return false + return null } else -> { if (!(networkErrorAlert(r))) { apiErrorAlert("apiConnect", generalGetString(MR.strings.connection_error), r) } - return false + return null } } } @@ -1529,16 +1530,6 @@ object ChatController { fun active(user: UserLike): Boolean = activeUser(rhId, user) chatModel.addTerminalItem(TerminalItem.resp(rhId, r)) when (r) { - is CR.NewContactConnection -> { - if (active(r.user)) { - chatModel.updateContactConnection(rhId, r.connection) - } - } - is CR.ContactConnectionDeleted -> { - if (active(r.user)) { - chatModel.removeChat(rhId, r.connection.id) - } - } is CR.ContactDeletedByContact -> { if (active(r.user) && r.contact.directOrUsed) { chatModel.updateContact(rhId, r.contact) @@ -3710,8 +3701,8 @@ sealed class CR { @Serializable @SerialName("invitation") class Invitation(val user: UserRef, val connReqInvitation: String, val connection: PendingContactConnection): CR() @Serializable @SerialName("connectionIncognitoUpdated") class ConnectionIncognitoUpdated(val user: UserRef, val toConnection: PendingContactConnection): CR() @Serializable @SerialName("connectionPlan") class CRConnectionPlan(val user: UserRef, val connectionPlan: ConnectionPlan): CR() - @Serializable @SerialName("sentConfirmation") class SentConfirmation(val user: UserRef): CR() - @Serializable @SerialName("sentInvitation") class SentInvitation(val user: UserRef): CR() + @Serializable @SerialName("sentConfirmation") class SentConfirmation(val user: UserRef, val connection: PendingContactConnection): CR() + @Serializable @SerialName("sentInvitation") class SentInvitation(val user: UserRef, val connection: PendingContactConnection): CR() @Serializable @SerialName("sentInvitationToContact") class SentInvitationToContact(val user: UserRef, val contact: Contact, val customUserProfile: Profile?): CR() @Serializable @SerialName("contactAlreadyExists") class ContactAlreadyExists(val user: UserRef, val contact: Contact): CR() @Serializable @SerialName("contactRequestAlreadyAccepted") class ContactRequestAlreadyAccepted(val user: UserRef, val contact: Contact): CR() @@ -3805,7 +3796,6 @@ sealed class CR { @Serializable @SerialName("callAnswer") class CallAnswer(val user: UserRef, val contact: Contact, val answer: WebRTCSession): CR() @Serializable @SerialName("callExtraInfo") class CallExtraInfo(val user: UserRef, val contact: Contact, val extraInfo: WebRTCExtraInfo): CR() @Serializable @SerialName("callEnded") class CallEnded(val user: UserRef, val contact: Contact): CR() - @Serializable @SerialName("newContactConnection") class NewContactConnection(val user: UserRef, val connection: PendingContactConnection): CR() @Serializable @SerialName("contactConnectionDeleted") class ContactConnectionDeleted(val user: UserRef, val connection: PendingContactConnection): CR() // remote events (desktop) @Serializable @SerialName("remoteHostList") class RemoteHostList(val remoteHosts: List): CR() @@ -3954,7 +3944,6 @@ sealed class CR { is CallAnswer -> "callAnswer" is CallExtraInfo -> "callExtraInfo" is CallEnded -> "callEnded" - is NewContactConnection -> "newContactConnection" is ContactConnectionDeleted -> "contactConnectionDeleted" is RemoteHostList -> "remoteHostList" is CurrentRemoteHost -> "currentRemoteHost" @@ -4009,11 +3998,11 @@ sealed class CR { is ContactCode -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionCode: $connectionCode") is GroupMemberCode -> withUser(user, "groupInfo: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionCode: $connectionCode") is ConnectionVerified -> withUser(user, "verified: $verified\nconnectionCode: $expectedCode") - is Invitation -> withUser(user, connReqInvitation) + is Invitation -> withUser(user, "connReqInvitation: $connReqInvitation\nconnection: $connection") is ConnectionIncognitoUpdated -> withUser(user, json.encodeToString(toConnection)) is CRConnectionPlan -> withUser(user, json.encodeToString(connectionPlan)) - is SentConfirmation -> withUser(user, noDetails()) - is SentInvitation -> withUser(user, noDetails()) + is SentConfirmation -> withUser(user, json.encodeToString(connection)) + is SentInvitation -> withUser(user, json.encodeToString(connection)) is SentInvitationToContact -> withUser(user, json.encodeToString(contact)) is ContactAlreadyExists -> withUser(user, json.encodeToString(contact)) is ContactRequestAlreadyAccepted -> withUser(user, json.encodeToString(contact)) @@ -4101,7 +4090,6 @@ sealed class CR { is CallAnswer -> withUser(user, "contact: ${contact.id}\nanswer: ${json.encodeToString(answer)}") is CallExtraInfo -> withUser(user, "contact: ${contact.id}\nextraInfo: ${json.encodeToString(extraInfo)}") is CallEnded -> withUser(user, "contact: ${contact.id}") - is NewContactConnection -> withUser(user, json.encodeToString(connection)) is ContactConnectionDeleted -> withUser(user, json.encodeToString(connection)) // remote events (mobile) is RemoteHostList -> json.encodeToString(remoteHosts) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt index a16275271..6f3caf467 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt @@ -108,6 +108,7 @@ private fun createInvitation( withApi { val r = m.controller.apiAddContact(rhId, incognito = m.controller.appPrefs.incognito.get()) if (r != null) { + m.updateContactConnection(rhId, r.second) connReqInvitation.value = r.first contactConnection.value = r.second } else { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt index 4deeda3e2..2439b16c3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt @@ -283,10 +283,11 @@ suspend fun connectViaUri( incognito: Boolean, connectionPlan: ConnectionPlan?, close: (() -> Unit)? -): Boolean { - val r = chatModel.controller.apiConnect(rhId, incognito, uri.toString()) +) { + val pcc = chatModel.controller.apiConnect(rhId, incognito, uri.toString()) val connLinkType = if (connectionPlan != null) planToConnectionLinkType(connectionPlan) else ConnectionLinkType.INVITATION - if (r) { + if (pcc != null) { + chatModel.updateContactConnection(rhId, pcc) close?.invoke() AlertManager.shared.showAlertMsg( title = generalGetString(MR.strings.connection_request_sent), @@ -299,7 +300,6 @@ suspend fun connectViaUri( hostDevice = hostDevice(rhId), ) } - return r } fun planToConnectionLinkType(connectionPlan: ConnectionPlan): ConnectionLinkType { diff --git a/packages/simplex-chat-client/typescript/src/response.ts b/packages/simplex-chat-client/typescript/src/response.ts index 0e1b2799b..b50b2e294 100644 --- a/packages/simplex-chat-client/typescript/src/response.ts +++ b/packages/simplex-chat-client/typescript/src/response.ts @@ -86,7 +86,6 @@ export type ChatResponse = | CRGroupUpdated | CRUserContactLinkSubscribed | CRUserContactLinkSubError - | CRNewContactConnection | CRContactConnectionDeleted | CRMessageError | CRChatCmdError @@ -731,12 +730,6 @@ export interface CRUserContactLinkSubError extends CR { chatError: ChatError } -export interface CRNewContactConnection extends CR { - type: "newContactConnection" - user: User - connection: PendingContactConnection -} - export interface CRContactConnectionDeleted extends CR { type: "contactConnectionDeleted" user: User diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 0a8b64682..aa489e9a9 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -1403,7 +1403,6 @@ processChatCommand = \case subMode <- chatReadVar subscriptionMode (connId, cReq) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation Nothing subMode conn <- withStore' $ \db -> createDirectConnection db user connId cReq ConnNew incognitoProfile subMode - toView $ CRNewContactConnection user conn pure $ CRInvitation user cReq conn AddContact incognito -> withUser $ \User {userId} -> processChatCommand $ APIAddContact userId incognito @@ -1433,8 +1432,7 @@ processChatCommand = \case dm <- directMessage $ XInfo profileToSend connId <- withAgent $ \a -> joinConnection a (aUserId user) True cReq dm subMode conn <- withStore' $ \db -> createDirectConnection db user connId cReq ConnJoined (incognitoProfile $> profileToSend) subMode - toView $ CRNewContactConnection user conn - pure $ CRSentConfirmation user + pure $ CRSentConfirmation user conn APIConnect userId incognito (Just (ACR SCMContact cReq)) -> withUserId userId $ \user -> connectViaContact user incognito cReq APIConnect _ _ Nothing -> throwChatError CEInvalidConnReq Connect incognito aCReqUri@(Just cReqUri) -> withUser $ \user@User {userId} -> do @@ -2106,8 +2104,7 @@ processChatCommand = \case connect' groupLinkId cReqHash xContactId = do (connId, incognitoProfile, subMode) <- requestContact user incognito cReq xContactId conn <- withStore' $ \db -> createConnReqConnection db userId connId cReqHash xContactId incognitoProfile groupLinkId subMode - toView $ CRNewContactConnection user conn - pure $ CRSentInvitation user incognitoProfile + pure $ CRSentInvitation user conn incognitoProfile connectContactViaAddress :: User -> IncognitoEnabled -> Contact -> ConnectionRequestUri 'CMContact -> m ChatResponse connectContactViaAddress user incognito ct cReq = withChatLock "connectViaContact" $ do diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 4ae6636e4..fb2ff89a2 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -557,8 +557,8 @@ data ChatResponse | CRInvitation {user :: User, connReqInvitation :: ConnReqInvitation, connection :: PendingContactConnection} | CRConnectionIncognitoUpdated {user :: User, toConnection :: PendingContactConnection} | CRConnectionPlan {user :: User, connectionPlan :: ConnectionPlan} - | CRSentConfirmation {user :: User} - | CRSentInvitation {user :: User, customUserProfile :: Maybe Profile} + | CRSentConfirmation {user :: User, connection :: PendingContactConnection} + | CRSentInvitation {user :: User, connection :: PendingContactConnection, customUserProfile :: Maybe Profile} | CRSentInvitationToContact {user :: User, contact :: Contact, customUserProfile :: Maybe Profile} | CRContactUpdated {user :: User, fromContact :: Contact, toContact :: Contact} | CRGroupMemberUpdated {user :: User, groupInfo :: GroupInfo, fromMember :: GroupMember, toMember :: GroupMember} @@ -655,7 +655,6 @@ data ChatResponse | CRNtfTokenStatus {status :: NtfTknStatus} | CRNtfToken {token :: DeviceToken, status :: NtfTknStatus, ntfMode :: NotificationsMode} | CRNtfMessages {user_ :: Maybe User, connEntity :: Maybe ConnectionEntity, msgTs :: Maybe UTCTime, ntfMessages :: [NtfMsgInfo]} - | CRNewContactConnection {user :: User, connection :: PendingContactConnection} | CRContactConnectionDeleted {user :: User, connection :: PendingContactConnection} | CRRemoteHostList {remoteHosts :: [RemoteHostInfo]} | CRCurrentRemoteHost {remoteHost_ :: Maybe RemoteHostInfo} diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 1363fcced..7eeddefbc 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -164,8 +164,8 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe CRInvitation u cReq _ -> ttyUser u $ viewConnReqInvitation cReq CRConnectionIncognitoUpdated u c -> ttyUser u $ viewConnectionIncognitoUpdated c CRConnectionPlan u connectionPlan -> ttyUser u $ viewConnectionPlan connectionPlan - CRSentConfirmation u -> ttyUser u ["confirmation sent!"] - CRSentInvitation u customUserProfile -> ttyUser u $ viewSentInvitation customUserProfile testView + CRSentConfirmation u _ -> ttyUser u ["confirmation sent!"] + CRSentInvitation u _ customUserProfile -> ttyUser u $ viewSentInvitation customUserProfile testView CRSentInvitationToContact u _c customUserProfile -> ttyUser u $ viewSentInvitation customUserProfile testView CRContactDeleted u c -> ttyUser u [ttyContact' c <> ": contact is deleted"] CRContactDeletedByContact u c -> ttyUser u [ttyFullContact c <> " deleted contact with you"] @@ -275,7 +275,6 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe CRCallInvitations _ -> [] CRUserContactLinkSubscribed -> ["Your address is active! To show: " <> highlight' "/sa"] CRUserContactLinkSubError e -> ["user address error: " <> sShow e, "to delete your address: " <> highlight' "/da"] - CRNewContactConnection u _ -> ttyUser u [] CRContactConnectionDeleted u PendingContactConnection {pccConnId} -> ttyUser u ["connection :" <> sShow pccConnId <> " deleted"] CRNtfTokenStatus status -> ["device token status: " <> plain (smpEncode status)] CRNtfToken _ status mode -> ["device token status: " <> plain (smpEncode status) <> ", notifications mode: " <> plain (strEncode mode)]