From 5ca21dea13d9827948a115ca36f405e60e81712c Mon Sep 17 00:00:00 2001
From: JRoberts <8711996+jr-simplex@users.noreply.github.com>
Date: Sat, 5 Nov 2022 17:48:57 +0400
Subject: [PATCH] mobile: seamless transition from group link to group; ios:
group link alert (#1296)
---
.../java/chat/simplex/app/model/SimpleXAPI.kt | 13 +++++---
.../newchat/ContactConnectionInfoView.kt | 4 ++-
.../app/src/main/res/values-de/strings.xml | 1 +
.../app/src/main/res/values-ru/strings.xml | 5 +--
.../app/src/main/res/values/strings.xml | 1 +
apps/ios/Shared/Model/SimpleXAPI.swift | 12 ++++---
.../ChatList/ContactConnectionInfo.swift | 5 ++-
.../Shared/Views/NewChat/NewChatButton.swift | 33 +++++++++++++++++++
.../Views/NewChat/PasteToConnectView.swift | 9 ++++-
.../Views/NewChat/ScanToConnectView.swift | 8 ++++-
apps/ios/SimpleXChat/APITypes.swift | 2 +-
11 files changed, 78 insertions(+), 15 deletions(-)
diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
index 2a4a003608..26da52a4ea 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
@@ -952,11 +952,11 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
is CR.ContactConnected -> {
if (!r.contact.viaGroupLink) {
chatModel.updateContact(r.contact)
+ chatModel.dismissConnReqView(r.contact.activeConn.id)
+ chatModel.removeChat(r.contact.activeConn.id)
chatModel.updateNetworkStatus(r.contact.id, Chat.NetworkStatus.Connected())
ntfManager.notifyContactConnected(r.contact)
}
- chatModel.dismissConnReqView(r.contact.activeConn.id)
- chatModel.removeChat(r.contact.activeConn.id)
}
is CR.ContactConnecting -> {
if (!r.contact.viaGroupLink) {
@@ -1038,8 +1038,13 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
chatModel.addChat(Chat(chatInfo = ChatInfo.Group(r.groupInfo), chatItems = listOf()))
// TODO NtfManager.shared.notifyGroupInvitation
}
- is CR.UserAcceptedGroupSent ->
+ is CR.UserAcceptedGroupSent -> {
chatModel.updateGroup(r.groupInfo)
+ if (r.hostContact != null) {
+ chatModel.dismissConnReqView(r.hostContact.activeConn.id)
+ chatModel.removeChat(r.hostContact.activeConn.id)
+ }
+ }
is CR.JoinedGroupMemberConnecting ->
chatModel.upsertGroupMember(r.groupInfo, r.member)
is CR.DeletedMemberUser -> // TODO update user member
@@ -1860,7 +1865,7 @@ sealed class CR {
// group events
@Serializable @SerialName("groupCreated") class GroupCreated(val groupInfo: GroupInfo): CR()
@Serializable @SerialName("sentGroupInvitation") class SentGroupInvitation(val groupInfo: GroupInfo, val contact: Contact, val member: GroupMember): CR()
- @Serializable @SerialName("userAcceptedGroupSent") class UserAcceptedGroupSent (val groupInfo: GroupInfo): CR()
+ @Serializable @SerialName("userAcceptedGroupSent") class UserAcceptedGroupSent (val groupInfo: GroupInfo, val hostContact: Contact? = null): CR()
@Serializable @SerialName("userDeletedMember") class UserDeletedMember(val groupInfo: GroupInfo, val member: GroupMember): CR()
@Serializable @SerialName("leftMemberUser") class LeftMemberUser(val groupInfo: GroupInfo): CR()
@Serializable @SerialName("groupMembers") class GroupMembers(val group: Group): CR()
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt
index f68287ff92..036289cbd4 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt
@@ -91,7 +91,9 @@ private fun ContactConnectionInfoLayout(
}
Text(
stringResource(
- if (contactConnection.viaContactUri) R.string.you_will_be_connected_when_your_connection_request_is_accepted
+ if (contactConnection.viaContactUri)
+ if (contactConnection.groupLinkId != null) R.string.you_will_be_connected_when_group_host_device_is_online
+ else R.string.you_will_be_connected_when_your_connection_request_is_accepted
else R.string.you_will_be_connected_when_your_contacts_device_is_online
),
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING)
diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml
index d52ed1bcb6..96ad1f5fac 100644
--- a/apps/android/app/src/main/res/values-de/strings.xml
+++ b/apps/android/app/src/main/res/values-de/strings.xml
@@ -323,6 +323,7 @@
Ungültiger Link!
Dieser Link ist kein gültiger Verbindungslink!
Verbindungsanfrage gesendet!
+ ***You will be connected to group when the group host\'s device is online, please wait or check later!
Sie werden verbunden, sobald Ihre Verbindungsanfrage akzeptiert wird, bitte warten oder schauen Sie später nochmal nach!
Sie werden verbunden, wenn das Gerät Ihres Kontakts online ist, bitte warten oder schauen Sie später nochmal nach!
Zeigen Sie Ihrem Kontakt den QR-Code aus der App zum Scannen.
diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml
index b74bc6c110..f0744b9438 100644
--- a/apps/android/app/src/main/res/values-ru/strings.xml
+++ b/apps/android/app/src/main/res/values-ru/strings.xml
@@ -323,8 +323,9 @@
Неверная ссылка!
Эта ссылка не является ссылкой-приглашением!
Запрос на соединение послан!
- Соединение будет установлено когда ваш запрос будет принят. Пожалуйста, подождите или проверьте позже!
- Соединение будет установлено когда ваш контакт будет онлайн. Пожалуйста, подождите или проверьте позже!
+ Соединение с группой будет установлено, когда хост группы будет онлайн. Пожалуйста, подождите или проверьте позже!
+ Соединение будет установлено, когда ваш запрос будет принят. Пожалуйста, подождите или проверьте позже!
+ Соединение будет установлено, когда ваш контакт будет онлайн. Пожалуйста, подождите или проверьте позже!
Ваш контакт может сосканировать QR код в приложении.
Если вы не можете встретиться лично, вы можете показать QR код во время видеозвонка или поделиться ссылкой.
Ваш профиль будет отправлен\nвашему контакту
diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml
index 45c8a61a7d..6da6fa7248 100644
--- a/apps/android/app/src/main/res/values/strings.xml
+++ b/apps/android/app/src/main/res/values/strings.xml
@@ -323,6 +323,7 @@
Invalid link!
This link is not a valid connection link!
Connection request sent!
+ You will be connected to group when the group host\'s device is online, please wait or check later!
You will be connected when your connection request is accepted, please wait or check later!
You will be connected when your contact\'s device is online, please wait or check later!
Your contact can scan QR code from the app.
diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index ce53f60fbb..fac0a7dc54 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -716,7 +716,7 @@ enum JoinGroupResult {
func apiJoinGroup(_ groupId: Int64) async throws -> JoinGroupResult {
let r = await chatSendCmd(.apiJoinGroup(groupId: groupId))
switch r {
- case let .userAcceptedGroupSent(groupInfo): return .joined(groupInfo: groupInfo)
+ case let .userAcceptedGroupSent(groupInfo, _): return .joined(groupInfo: groupInfo)
case .chatCmdError(.errorAgent(.SMP(.AUTH))): return .invitationRemoved
case .chatCmdError(.errorStore(.groupNotFound)): return .groupNotFound
default: throw r
@@ -893,11 +893,11 @@ func processReceivedMsg(_ res: ChatResponse) async {
case let .contactConnected(contact, _):
if !contact.viaGroupLink {
m.updateContact(contact)
+ m.dismissConnReqView(contact.activeConn.id)
+ m.removeChat(contact.activeConn.id)
m.updateNetworkStatus(contact.id, .connected)
NtfManager.shared.notifyContactConnected(contact)
}
- m.dismissConnReqView(contact.activeConn.id)
- m.removeChat(contact.activeConn.id)
case let .contactConnecting(contact):
if !contact.viaGroupLink {
m.updateContact(contact)
@@ -991,8 +991,12 @@ func processReceivedMsg(_ res: ChatResponse) async {
chatItems: []
))
// NtfManager.shared.notifyContactRequest(contactRequest) // TODO notifyGroupInvitation?
- case let .userAcceptedGroupSent(groupInfo):
+ case let .userAcceptedGroupSent(groupInfo, hostContact):
m.updateGroup(groupInfo)
+ if let hostContact = hostContact {
+ m.dismissConnReqView(hostContact.activeConn.id)
+ m.removeChat(hostContact.activeConn.id)
+ }
case let .joinedGroupMemberConnecting(groupInfo, _, member):
_ = m.upsertGroupMember(groupInfo, member)
case let .deletedMemberUser(groupInfo, _): // TODO update user member
diff --git a/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift b/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift
index bf311b1719..72be57b3f7 100644
--- a/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift
+++ b/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift
@@ -125,7 +125,10 @@ struct ContactConnectionInfo: View {
private func contactConnectionText(_ contactConnection: PendingContactConnection) -> LocalizedStringKey {
contactConnection.viaContactUri
- ? "You will be connected when your connection request is accepted, please wait or check later!"
+ ? (contactConnection.groupLinkId != nil
+ ? "You will be connected to group when the group host's device is online, please wait or check later!"
+ : "You will be connected when your connection request is accepted, please wait or check later!"
+ )
: "You will be connected when your contact's device is online, please wait or check later!"
}
}
diff --git a/apps/ios/Shared/Views/NewChat/NewChatButton.swift b/apps/ios/Shared/Views/NewChat/NewChatButton.swift
index 10da2ce209..ff6b94dffd 100644
--- a/apps/ios/Shared/Views/NewChat/NewChatButton.swift
+++ b/apps/ios/Shared/Views/NewChat/NewChatButton.swift
@@ -78,6 +78,39 @@ func connectViaLink(_ connectionLink: String, _ dismiss: DismissAction? = nil) {
}
}
+struct CRData: Decodable {
+ var type: String
+ var groupLinkId: String?
+}
+
+func parseLinkQueryData(_ connectionLink: String) -> CRData? {
+ if let hashIndex = connectionLink.firstIndex(of: "#"),
+ let urlQuery = URL(string: String(connectionLink[connectionLink.index(after: hashIndex)...])),
+ let components = URLComponents(url: urlQuery, resolvingAgainstBaseURL: false),
+ let data = components.queryItems?.first(where: { $0.name == "data" })?.value,
+ let d = data.data(using: .utf8),
+ let crData = try? getJSONDecoder().decode(CRData.self, from: d) {
+ return crData
+ } else {
+ return nil
+ }
+}
+
+func checkCRDataGroup(_ crData: CRData) -> Bool {
+ return crData.type == "group" && crData.groupLinkId != nil
+}
+
+func groupLinkAlert(_ connectionLink: String) -> Alert {
+ return Alert(
+ title: Text("Connect via group link?"),
+ message: Text("You will join a group this link refers to and connect to its group members."),
+ primaryButton: .default(Text("Connect")) {
+ connectViaLink(connectionLink)
+ },
+ secondaryButton: .cancel()
+ )
+}
+
func connectionReqSentAlert(_ type: ConnReqType) {
AlertManager.shared.showAlertMsg(
title: "Connection request sent!",
diff --git a/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift b/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift
index 4be3f91ce0..de390ebad9 100644
--- a/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift
+++ b/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift
@@ -81,7 +81,14 @@ struct PasteToConnectView: View {
}
private func connect() {
- connectViaLink(connectionLink.trimmingCharacters(in: .whitespaces), dismiss)
+ let link = connectionLink.trimmingCharacters(in: .whitespaces)
+ if let crData = parseLinkQueryData(link),
+ checkCRDataGroup(crData) {
+ dismiss()
+ AlertManager.shared.showAlert(groupLinkAlert(link))
+ } else {
+ connectViaLink(link, dismiss)
+ }
}
}
diff --git a/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift b/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift
index 2725faed07..2213dff203 100644
--- a/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift
+++ b/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift
@@ -52,7 +52,13 @@ struct ScanToConnectView: View {
func processQRCode(_ resp: Result) {
switch resp {
case let .success(r):
- Task { connectViaLink(r.string, dismiss) }
+ if let crData = parseLinkQueryData(r.string),
+ checkCRDataGroup(crData) {
+ dismiss()
+ AlertManager.shared.showAlert(groupLinkAlert(r.string))
+ } else {
+ Task { connectViaLink(r.string, dismiss) }
+ }
case let .failure(e):
logger.error("ConnectContactView.processQRCode QR code error: \(e.localizedDescription)")
dismiss()
diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift
index a74241b445..f81c7266fc 100644
--- a/apps/ios/SimpleXChat/APITypes.swift
+++ b/apps/ios/SimpleXChat/APITypes.swift
@@ -329,7 +329,7 @@ public enum ChatResponse: Decodable, Error {
// group events
case groupCreated(groupInfo: GroupInfo)
case sentGroupInvitation(groupInfo: GroupInfo, contact: Contact, member: GroupMember)
- case userAcceptedGroupSent(groupInfo: GroupInfo)
+ case userAcceptedGroupSent(groupInfo: GroupInfo, hostContact: Contact?)
case userDeletedMember(groupInfo: GroupInfo, member: GroupMember)
case leftMemberUser(groupInfo: GroupInfo)
case groupMembers(group: Group)