From c0be36737d8bae7191736f03523f28e3f714036e Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 10 Nov 2023 10:16:28 +0400 Subject: [PATCH] android: connect with contact via address (for preset simplex contact) (#3330) --- .../chat/simplex/common/model/ChatModel.kt | 41 ++++++--- .../chat/simplex/common/model/SimpleXAPI.kt | 45 ++++++++-- .../simplex/common/views/chat/ChatInfoView.kt | 2 +- .../views/chat/item/CIRcvDecryptionError.kt | 2 +- .../views/chatlist/ChatListNavLinkView.kt | 87 ++++++++++++++++--- .../common/views/chatlist/ChatListView.kt | 5 -- .../common/views/chatlist/ChatPreviewView.kt | 14 +-- .../views/chatlist/ShareListNavLinkView.kt | 2 +- .../common/views/newchat/ScanToConnectView.kt | 13 ++- .../commonMain/resources/MR/base/strings.xml | 2 + 10 files changed, 165 insertions(+), 48 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 4d95bfd49..91b4a8d8f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -147,12 +147,13 @@ object ChatModel { val currentCInfo = chats[i].chatInfo var newCInfo = cInfo if (currentCInfo is ChatInfo.Direct && newCInfo is ChatInfo.Direct) { - val currentStats = currentCInfo.contact.activeConn.connectionStats - val newStats = newCInfo.contact.activeConn.connectionStats - if (currentStats != null && newStats == null) { + val currentStats = currentCInfo.contact.activeConn?.connectionStats + val newConn = newCInfo.contact.activeConn + val newStats = newConn?.connectionStats + if (currentStats != null && newConn != null && newStats == null) { newCInfo = newCInfo.copy( contact = newCInfo.contact.copy( - activeConn = newCInfo.contact.activeConn.copy( + activeConn = newConn.copy( connectionStats = currentStats ) ) @@ -168,7 +169,7 @@ object ChatModel { fun updateContact(contact: Contact) = updateChat(ChatInfo.Direct(contact), addMissing = contact.directOrUsed) fun updateContactConnectionStats(contact: Contact, connectionStats: ConnectionStats) { - val updatedConn = contact.activeConn.copy(connectionStats = connectionStats) + val updatedConn = contact.activeConn?.copy(connectionStats = connectionStats) val updatedContact = contact.copy(activeConn = updatedConn) updateContact(updatedContact) } @@ -570,11 +571,19 @@ object ChatModel { } fun setContactNetworkStatus(contact: Contact, status: NetworkStatus) { - networkStatuses[contact.activeConn.agentConnId] = status + val conn = contact.activeConn + if (conn != null) { + networkStatuses[conn.agentConnId] = status + } } - fun contactNetworkStatus(contact: Contact): NetworkStatus = - networkStatuses[contact.activeConn.agentConnId] ?: NetworkStatus.Unknown() + fun contactNetworkStatus(contact: Contact): NetworkStatus { + val conn = contact.activeConn + return if (conn != null) + networkStatuses[conn.agentConnId] ?: NetworkStatus.Unknown() + else + NetworkStatus.Unknown() + } fun addTerminalItem(item: TerminalItem) { if (terminalItems.size >= 500) { @@ -891,7 +900,7 @@ data class Contact( val contactId: Long, override val localDisplayName: String, val profile: LocalProfile, - val activeConn: Connection, + val activeConn: Connection? = null, val viaGroup: Long? = null, val contactUsed: Boolean, val contactStatus: ContactStatus, @@ -906,10 +915,10 @@ data class Contact( override val chatType get() = ChatType.Direct override val id get() = "@$contactId" override val apiId get() = contactId - override val ready get() = activeConn.connStatus == ConnStatus.Ready + override val ready get() = activeConn?.connStatus == ConnStatus.Ready val active get() = contactStatus == ContactStatus.Active override val sendMsgEnabled get() = - (ready && active && !(activeConn.connectionStats?.ratchetSyncSendProhibited ?: false)) + (ready && active && !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?: false)) || nextSendGrpInv val nextSendGrpInv get() = contactGroupMemberId != null && !contactGrpInvSent override val ntfsEnabled get() = chatSettings.enableNtfs == MsgFilter.All @@ -927,13 +936,17 @@ data class Contact( override val image get() = profile.image val contactLink: String? = profile.contactLink override val localAlias get() = profile.localAlias - val verified get() = activeConn.connectionCode != null + val verified get() = activeConn?.connectionCode != null val directOrUsed: Boolean get() = - (activeConn.connLevel == 0 && !activeConn.viaGroupLink) || contactUsed + if (activeConn != null) { + (activeConn.connLevel == 0 && !activeConn.viaGroupLink) || contactUsed + } else { + true + } val contactConnIncognito = - activeConn.customUserProfileId != null + activeConn?.customUserProfileId != null fun allowsFeature(feature: ChatFeature): Boolean = when (feature) { ChatFeature.TimedMessages -> mergedPreferences.timedMessages.contactPreference.allow != FeatureAllowed.NO 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 431ddf1e2..1fa8c35d5 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 @@ -907,6 +907,23 @@ object ChatController { } } + suspend fun apiConnectContactViaAddress(incognito: Boolean, contactId: Long): Contact? { + val userId = chatModel.currentUser.value?.userId ?: run { + Log.e(TAG, "apiConnectContactViaAddress: no current user") + return null + } + val r = sendCmd(CC.ApiConnectContactViaAddress(userId, incognito, contactId)) + when { + r is CR.SentInvitationToContact -> return r.contact + else -> { + if (!(networkErrorAlert(r))) { + apiErrorAlert("apiConnectContactViaAddress", generalGetString(MR.strings.connection_error), r) + } + return null + } + } + } + suspend fun apiDeleteChat(type: ChatType, id: Long, notify: Boolean? = null): Boolean { val r = sendCmd(CC.ApiDeleteChat(type, id, notify)) when { @@ -1413,8 +1430,11 @@ object ChatController { is CR.ContactConnected -> { if (active(r.user) && r.contact.directOrUsed) { chatModel.updateContact(r.contact) - chatModel.dismissConnReqView(r.contact.activeConn.id) - chatModel.removeChat(r.contact.activeConn.id) + val conn = r.contact.activeConn + if (conn != null) { + chatModel.dismissConnReqView(conn.id) + chatModel.removeChat(conn.id) + } } if (r.contact.directOrUsed) { ntfManager.notifyContactConnected(r.user, r.contact) @@ -1424,8 +1444,11 @@ object ChatController { is CR.ContactConnecting -> { if (active(r.user) && r.contact.directOrUsed) { chatModel.updateContact(r.contact) - chatModel.dismissConnReqView(r.contact.activeConn.id) - chatModel.removeChat(r.contact.activeConn.id) + val conn = r.contact.activeConn + if (conn != null) { + chatModel.dismissConnReqView(conn.id) + chatModel.removeChat(conn.id) + } } } is CR.ReceivedContactRequest -> { @@ -1556,9 +1579,10 @@ object ChatController { if (!active(r.user)) return chatModel.updateGroup(r.groupInfo) - if (r.hostContact != null) { - chatModel.dismissConnReqView(r.hostContact.activeConn.id) - chatModel.removeChat(r.hostContact.activeConn.id) + val conn = r.hostContact?.activeConn + if (conn != null) { + chatModel.dismissConnReqView(conn.id) + chatModel.removeChat(conn.id) } } is CR.GroupLinkConnecting -> { @@ -1946,6 +1970,7 @@ sealed class CC { class ApiSetConnectionIncognito(val connId: Long, val incognito: Boolean): CC() class APIConnectPlan(val userId: Long, val connReq: String): CC() class APIConnect(val userId: Long, val incognito: Boolean, val connReq: String): CC() + class ApiConnectContactViaAddress(val userId: Long, val incognito: Boolean, val contactId: Long): CC() class ApiDeleteChat(val type: ChatType, val id: Long, val notify: Boolean?): CC() class ApiClearChat(val type: ChatType, val id: Long): CC() class ApiListContacts(val userId: Long): CC() @@ -2057,6 +2082,7 @@ sealed class CC { is ApiSetConnectionIncognito -> "/_set incognito :$connId ${onOff(incognito)}" is APIConnectPlan -> "/_connect plan $userId $connReq" is APIConnect -> "/_connect $userId incognito=${onOff(incognito)} $connReq" + is ApiConnectContactViaAddress -> "/_connect contact $userId incognito=${onOff(incognito)} $contactId" is ApiDeleteChat -> if (notify != null) { "/_delete ${chatRef(type, id)} notify=${onOff(notify)}" } else { @@ -2164,6 +2190,7 @@ sealed class CC { is ApiSetConnectionIncognito -> "apiSetConnectionIncognito" is APIConnectPlan -> "apiConnectPlan" is APIConnect -> "apiConnect" + is ApiConnectContactViaAddress -> "apiConnectContactViaAddress" is ApiDeleteChat -> "apiDeleteChat" is ApiClearChat -> "apiClearChat" is ApiListContacts -> "apiListContacts" @@ -3379,6 +3406,7 @@ sealed class 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("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() @Serializable @SerialName("contactDeleted") class ContactDeleted(val user: UserRef, val contact: Contact): CR() @@ -3517,6 +3545,7 @@ sealed class CR { is CRConnectionPlan -> "connectionPlan" is SentConfirmation -> "sentConfirmation" is SentInvitation -> "sentInvitation" + is SentInvitationToContact -> "sentInvitationToContact" is ContactAlreadyExists -> "contactAlreadyExists" is ContactRequestAlreadyAccepted -> "contactRequestAlreadyAccepted" is ContactDeleted -> "contactDeleted" @@ -3650,6 +3679,7 @@ sealed class CR { is CRConnectionPlan -> withUser(user, json.encodeToString(connectionPlan)) is SentConfirmation -> withUser(user, noDetails()) is SentInvitation -> withUser(user, noDetails()) + is SentInvitationToContact -> withUser(user, json.encodeToString(contact)) is ContactAlreadyExists -> withUser(user, json.encodeToString(contact)) is ContactRequestAlreadyAccepted -> withUser(user, json.encodeToString(contact)) is ContactDeleted -> withUser(user, json.encodeToString(contact)) @@ -3785,6 +3815,7 @@ sealed class ContactAddressPlan { @Serializable @SerialName("connectingConfirmReconnect") object ConnectingConfirmReconnect: ContactAddressPlan() @Serializable @SerialName("connectingProhibit") class ConnectingProhibit(val contact: Contact): ContactAddressPlan() @Serializable @SerialName("known") class Known(val contact: Contact): ContactAddressPlan() + @Serializable @SerialName("contactViaAddress") class ContactViaAddress(val contact: Contact): ContactAddressPlan() } @Serializable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt index 4564a4a6e..b7c5e66a6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt @@ -150,7 +150,7 @@ fun ChatInfoView( val (verified, existingCode) = r chatModel.updateContact( ct.copy( - activeConn = ct.activeConn.copy( + activeConn = ct.activeConn?.copy( connectionCode = if (verified) SecurityCode(existingCode, Clock.System.now()) else null ) ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt index 8de309fc8..ecf7f10dd 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt @@ -57,7 +57,7 @@ fun CIRcvDecryptionError( if (cInfo is ChatInfo.Direct) { val modelCInfo = findModelChat(cInfo.id)?.chatInfo if (modelCInfo is ChatInfo.Direct) { - val modelContactStats = modelCInfo.contact.activeConn.connectionStats + val modelContactStats = modelCInfo.contact.activeConn?.connectionStats if (modelContactStats != null) { if (modelContactStats.ratchetSyncAllowed) { DecryptionErrorItemFixButton( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt index bcabb7cfd..13380a664 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt @@ -30,6 +30,7 @@ import chat.simplex.common.views.newchat.* import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.datetime.Clock +import java.net.URI @Composable fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { @@ -61,8 +62,8 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { val contactNetworkStatus = chatModel.contactNetworkStatus(chat.chatInfo.contact) ChatListNavLinkLayout( chatLinkPreview = { ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, contactNetworkStatus, stopped, linkMode, inProgress = false, progressByTimeout = false) }, - click = { directChatAction(chat.chatInfo, chatModel) }, - dropdownMenuItems = { ContactMenuItems(chat, chatModel, showMenu, showMarkRead) }, + click = { directChatAction(chat.chatInfo.contact, chatModel) }, + dropdownMenuItems = { ContactMenuItems(chat, chat.chatInfo.contact, chatModel, showMenu, showMarkRead) }, showMenu, stopped, selectedChat @@ -118,8 +119,11 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { } } -fun directChatAction(chatInfo: ChatInfo, chatModel: ChatModel) { - withBGApi { openChat(chatInfo, chatModel) } +fun directChatAction(contact: Contact, chatModel: ChatModel) { + when { + contact.activeConn == null && contact.profile.contactLink != null -> askCurrentOrIncognitoProfileConnectContactViaAddress(chatModel, contact, close = null, openChat = true) + else -> withBGApi { openChat(ChatInfo.Direct(contact), chatModel) } + } } fun groupChatAction(groupInfo: GroupInfo, chatModel: ChatModel, inProgress: MutableState? = null) { @@ -192,15 +196,17 @@ suspend fun setGroupMembers(groupInfo: GroupInfo, chatModel: ChatModel) { } @Composable -fun ContactMenuItems(chat: Chat, chatModel: ChatModel, showMenu: MutableState, showMarkRead: Boolean) { - if (showMarkRead) { - MarkReadChatAction(chat, chatModel, showMenu) - } else { - MarkUnreadChatAction(chat, chatModel, showMenu) +fun ContactMenuItems(chat: Chat, contact: Contact, chatModel: ChatModel, showMenu: MutableState, showMarkRead: Boolean) { + if (contact.activeConn != null) { + if (showMarkRead) { + MarkReadChatAction(chat, chatModel, showMenu) + } else { + MarkUnreadChatAction(chat, chatModel, showMenu) + } + ToggleFavoritesChatAction(chat, chatModel, chat.chatInfo.chatSettings?.favorite == true, showMenu) + ToggleNotificationsChatAction(chat, chatModel, chat.chatInfo.ntfsEnabled, showMenu) + ClearChatAction(chat, chatModel, showMenu) } - ToggleFavoritesChatAction(chat, chatModel, chat.chatInfo.chatSettings?.favorite == true, showMenu) - ToggleNotificationsChatAction(chat, chatModel, chat.chatInfo.ntfsEnabled, showMenu) - ClearChatAction(chat, chatModel, showMenu) DeleteContactAction(chat, chatModel, showMenu) } @@ -591,6 +597,63 @@ fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) { ) } +fun askCurrentOrIncognitoProfileConnectContactViaAddress( + chatModel: ChatModel, + contact: Contact, + close: (() -> Unit)?, + openChat: Boolean +) { + AlertManager.shared.showAlertDialogButtonsColumn( + title = String.format(generalGetString(MR.strings.connect_with_contact_name_question), contact.chatViewName), + buttons = { + Column { + SectionItemView({ + AlertManager.shared.hideAlert() + withApi { + close?.invoke() + val ok = connectContactViaAddress(chatModel, contact.contactId, incognito = false) + if (ok && openChat) { + openDirectChat(contact.contactId, chatModel) + } + } + }) { + Text(generalGetString(MR.strings.connect_use_current_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + SectionItemView({ + AlertManager.shared.hideAlert() + withApi { + close?.invoke() + val ok = connectContactViaAddress(chatModel, contact.contactId, incognito = true) + if (ok && openChat) { + openDirectChat(contact.contactId, chatModel) + } + } + }) { + Text(generalGetString(MR.strings.connect_use_new_incognito_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + SectionItemView({ + AlertManager.shared.hideAlert() + }) { + Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + } + } + ) +} + +suspend fun connectContactViaAddress(chatModel: ChatModel, contactId: Long, incognito: Boolean): Boolean { + val contact = chatModel.controller.apiConnectContactViaAddress(incognito, contactId) + if (contact != null) { + chatModel.updateContact(contact) + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.connection_request_sent), + text = generalGetString(MR.strings.you_will_be_connected_when_your_connection_request_is_accepted) + ) + return true + } + return false +} + fun acceptGroupInvitationAlertDialog(groupInfo: GroupInfo, chatModel: ChatModel, inProgress: MutableState? = null) { AlertManager.shared.showAlertDialog( title = generalGetString(MR.strings.join_group_question), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 4df62e12e..7af4d2670 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -146,11 +146,6 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf @Composable private fun OnboardingButtons(openNewChatSheet: () -> Unit) { Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING), horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.Bottom) { - val uriHandler = LocalUriHandler.current - ConnectButton(generalGetString(MR.strings.chat_with_developers)) { - uriHandler.openVerifiedSimplexUri(simplexTeamUri) - } - Spacer(Modifier.height(DEFAULT_PADDING)) ConnectButton(generalGetString(MR.strings.tap_to_start_new_chat), openNewChatSheet) val color = MaterialTheme.colors.primaryVariant Canvas(modifier = Modifier.width(40.dp).height(10.dp), onDraw = { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt index d3413e2e0..af1f49a08 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt @@ -185,10 +185,14 @@ fun ChatPreviewView( } else { when (cInfo) { is ChatInfo.Direct -> - if (cInfo.contact.nextSendGrpInv) { - Text(stringResource(MR.strings.member_contact_send_direct_message), color = MaterialTheme.colors.secondary) - } else if (!cInfo.ready && cInfo.contact.active) { - Text(stringResource(MR.strings.contact_connection_pending), color = MaterialTheme.colors.secondary) + if (cInfo.contact.activeConn == null && cInfo.contact.profile.contactLink != null) { + Text(stringResource(MR.strings.contact_tap_to_connect), color = MaterialTheme.colors.primary) + } else if (!cInfo.ready && cInfo.contact.activeConn != null) { + if (cInfo.contact.nextSendGrpInv) { + Text(stringResource(MR.strings.member_contact_send_direct_message), color = MaterialTheme.colors.secondary) + } else if (cInfo.contact.active) { + Text(stringResource(MR.strings.contact_connection_pending), color = MaterialTheme.colors.secondary) + } } is ChatInfo.Group -> when (cInfo.groupInfo.membership.memberStatus) { @@ -215,7 +219,7 @@ fun ChatPreviewView( @Composable fun chatStatusImage() { if (cInfo is ChatInfo.Direct) { - if (cInfo.contact.active) { + if (cInfo.contact.active && cInfo.contact.activeConn != null) { val descr = contactNetworkStatus?.statusString when (contactNetworkStatus) { is NetworkStatus.Connected -> diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt index b9b8ea54b..e423a591d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListNavLinkView.kt @@ -20,7 +20,7 @@ fun ShareListNavLinkView(chat: Chat, chatModel: ChatModel) { is ChatInfo.Direct -> ShareListNavLinkLayout( chatLinkPreview = { SharePreviewView(chat) }, - click = { directChatAction(chat.chatInfo, chatModel) }, + click = { directChatAction(chat.chatInfo.contact, chatModel) }, stopped ) is ChatInfo.Group -> 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 2f52c2cac..7629256fc 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 @@ -19,8 +19,7 @@ import androidx.compose.ui.unit.dp import chat.simplex.common.model.* import chat.simplex.common.platform.TAG import chat.simplex.common.ui.theme.* -import chat.simplex.common.views.chatlist.openDirectChat -import chat.simplex.common.views.chatlist.openGroupChat +import chat.simplex.common.views.chatlist.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.* import chat.simplex.res.MR @@ -171,6 +170,16 @@ suspend fun planAndConnect( String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), contact.displayName) ) } + is ContactAddressPlan.ContactViaAddress -> { + Log.d(TAG, "planAndConnect, .ContactAddress, .ContactViaAddress, incognito=$incognito") + val contact = connectionPlan.contactAddressPlan.contact + if (incognito != null) { + close?.invoke() + connectContactViaAddress(chatModel, contact.contactId, incognito) + } else { + askCurrentOrIncognitoProfileConnectContactViaAddress(chatModel, contact, close, openChat = false) + } + } } is ConnectionPlan.GroupLink -> when (connectionPlan.groupLinkPlan) { GroupLinkPlan.Ok -> { 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 ff34934e4..fa2782531 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -289,6 +289,8 @@ Chat with the developers You have no chats No filtered chats + Tap to Connect + Connect with %1$s? No selected chat