From a3140c2d3e86537864d49d20bdf094360a6a8fd0 Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Fri, 20 Dec 2024 20:33:09 +0400
Subject: [PATCH] ui prohibit sending to member if connection is not ready
(#5399)
---
.../Chat/Group/GroupMemberInfoView.swift | 73 ++++++++++++-------
apps/ios/SimpleXChat/APITypes.swift | 4 +
apps/ios/SimpleXChat/ChatTypes.swift | 8 ++
.../chat/simplex/common/model/ChatModel.kt | 7 ++
.../chat/simplex/common/model/SimpleXAPI.kt | 3 +
.../views/chat/group/GroupMemberInfoView.kt | 50 ++++++++-----
.../commonMain/resources/MR/base/strings.xml | 1 +
7 files changed, 98 insertions(+), 48 deletions(-)
diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
index a18de1b349..30972f7242 100644
--- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
+++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
@@ -162,7 +162,7 @@ struct GroupMemberInfoView: View {
}
.disabled(
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil }
- || connStats.ratchetSyncSendProhibited
+ || !member.sendMsgEnabled
)
if connStats.rcvQueuesInfo.contains(where: { $0.rcvSwitchStatus != nil }) {
Button("Abort changing address") {
@@ -170,7 +170,7 @@ struct GroupMemberInfoView: View {
}
.disabled(
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil && !$0.canAbortSwitch }
- || connStats.ratchetSyncSendProhibited
+ || !member.sendMsgEnabled
)
}
smpServers("Receiving via", connStats.rcvQueuesInfo.map { $0.rcvServer }, theme.colors.secondary)
@@ -297,7 +297,7 @@ struct GroupMemberInfoView: View {
if let contactId = member.memberContactId {
newDirectChatButton(contactId, width: buttonWidth)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
- createMemberContactButton(width: buttonWidth)
+ createMemberContactButton(member, width: buttonWidth)
}
InfoViewButton(image: "phone.fill", title: "call", disabledLook: true, width: buttonWidth) { showSendMessageToEnableCallsAlert()
}
@@ -379,32 +379,41 @@ struct GroupMemberInfoView: View {
}
}
- func createMemberContactButton(width: CGFloat) -> some View {
- InfoViewButton(image: "message.fill", title: "message", width: width) {
- if let connStats = connectionStats {
- if connStats.ratchetSyncState == .ok {
- progressIndicator = true
- Task {
- do {
- let memberContact = try await apiCreateMemberContact(groupInfo.apiId, groupMember.groupMemberId)
- await MainActor.run {
- progressIndicator = false
- chatModel.addChat(Chat(chatInfo: .direct(contact: memberContact)))
- ItemsModel.shared.loadOpenChat(memberContact.id) {
- dismissAllSheets(animated: true)
- }
- NetworkModel.shared.setContactNetworkStatus(memberContact, .connected)
- }
- } catch let error {
- logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))")
- let a = getErrorAlert(error, "Error creating member contact")
- await MainActor.run {
- progressIndicator = false
- alert = .error(title: a.title, error: a.message)
+ func createMemberContactButton(_ member: GroupMember, width: CGFloat) -> some View {
+ InfoViewButton(
+ image: "message.fill",
+ title: "message",
+ disabledLook:
+ !(
+ member.sendMsgEnabled ||
+ (member.activeConn?.connectionStats?.ratchetSyncAllowed ?? false)
+ ),
+ width: width
+ ) {
+ if member.sendMsgEnabled {
+ progressIndicator = true
+ Task {
+ do {
+ let memberContact = try await apiCreateMemberContact(groupInfo.apiId, groupMember.groupMemberId)
+ await MainActor.run {
+ progressIndicator = false
+ chatModel.addChat(Chat(chatInfo: .direct(contact: memberContact)))
+ ItemsModel.shared.loadOpenChat(memberContact.id) {
+ dismissAllSheets(animated: true)
}
+ NetworkModel.shared.setContactNetworkStatus(memberContact, .connected)
+ }
+ } catch let error {
+ logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))")
+ let a = getErrorAlert(error, "Error creating member contact")
+ await MainActor.run {
+ progressIndicator = false
+ alert = .error(title: a.title, error: a.message)
}
}
- } else if connStats.ratchetSyncAllowed {
+ }
+ } else if let connStats = connectionStats {
+ if connStats.ratchetSyncAllowed {
alert = .someAlert(alert: SomeAlert(
alert: Alert(
title: Text("Fix connection?"),
@@ -416,13 +425,21 @@ struct GroupMemberInfoView: View {
),
id: "can't message member, fix connection"
))
- } else {
+ } else if connStats.ratchetSyncInProgress {
alert = .someAlert(alert: SomeAlert(
alert: mkAlert(
title: "Can't message member",
message: "Encryption renegotiation in progress."
),
- id: "can't message contact, encryption renegotiation in progress"
+ id: "can't message member, encryption renegotiation in progress"
+ ))
+ } else {
+ alert = .someAlert(alert: SomeAlert(
+ alert: mkAlert(
+ title: "Can't message member",
+ message: "Connection not ready."
+ ),
+ id: "can't message member, connection not ready"
))
}
}
diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift
index 66edb9f2b2..b6a8edb201 100644
--- a/apps/ios/SimpleXChat/APITypes.swift
+++ b/apps/ios/SimpleXChat/APITypes.swift
@@ -2034,6 +2034,10 @@ public struct ConnectionStats: Decodable, Hashable {
public var ratchetSyncSendProhibited: Bool {
[.required, .started, .agreed].contains(ratchetSyncState)
}
+
+ public var ratchetSyncInProgress: Bool {
+ [.started, .agreed].contains(ratchetSyncState)
+ }
}
public struct RcvQueueInfo: Codable, Hashable {
diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift
index b81b0b7662..b1a318c896 100644
--- a/apps/ios/SimpleXChat/ChatTypes.swift
+++ b/apps/ios/SimpleXChat/ChatTypes.swift
@@ -2010,6 +2010,14 @@ public struct GroupMember: Identifiable, Decodable, Hashable {
public var activeConn: Connection?
public var id: String { "#\(groupId) @\(groupMemberId)" }
+ public var ready: Bool { get { activeConn?.connStatus == .ready } }
+ public var sndReady: Bool { get { ready || activeConn?.connStatus == .sndReady } }
+ public var sendMsgEnabled: Bool { get {
+ sndReady
+ && memberCurrent
+ && !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?? false)
+ && !(activeConn?.connDisabled ?? true)
+ } }
public var displayName: String {
get {
let p = memberProfile
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 d407174e52..db90c2e573 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
@@ -1575,6 +1575,13 @@ data class GroupMember (
var activeConn: Connection? = null
): NamedChat {
val id: String get() = "#$groupId @$groupMemberId"
+ val ready get() = activeConn?.connStatus == ConnStatus.Ready
+ val sndReady get() = ready || activeConn?.connStatus == ConnStatus.SndReady
+ val sendMsgEnabled get() =
+ sndReady
+ && memberCurrent
+ && !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?: false)
+ && !(activeConn?.connDisabled ?: true)
override val displayName: String
get() {
val p = memberProfile
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 e95fdb446f..7e3d8597b4 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
@@ -6032,6 +6032,9 @@ class ConnectionStats(
val ratchetSyncSendProhibited: Boolean get() =
listOf(RatchetSyncState.Required, RatchetSyncState.Started, RatchetSyncState.Agreed).contains(ratchetSyncState)
+
+ val ratchetSyncInProgress: Boolean get() =
+ listOf(RatchetSyncState.Started, RatchetSyncState.Agreed).contains(ratchetSyncState)
}
@Serializable
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt
index c9ac464438..e4e5494364 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt
@@ -89,29 +89,34 @@ fun GroupMemberInfoView(
}
},
createMemberContact = {
- if (connectionStats != null) {
- if (connectionStats.ratchetSyncState == RatchetSyncState.Ok) {
- withBGApi {
- progressIndicator = true
- val memberContact = chatModel.controller.apiCreateMemberContact(rhId, groupInfo.apiId, member.groupMemberId)
- if (memberContact != null) {
- val memberChat = Chat(remoteHostId = rhId, ChatInfo.Direct(memberContact), chatItems = arrayListOf())
- withChats {
- addChat(memberChat)
- openLoadedChat(memberChat)
- }
- closeAll()
- chatModel.setContactNetworkStatus(memberContact, NetworkStatus.Connected())
+ if (member.sendMsgEnabled) {
+ withBGApi {
+ progressIndicator = true
+ val memberContact = chatModel.controller.apiCreateMemberContact(rhId, groupInfo.apiId, member.groupMemberId)
+ if (memberContact != null) {
+ val memberChat = Chat(remoteHostId = rhId, ChatInfo.Direct(memberContact), chatItems = arrayListOf())
+ withChats {
+ addChat(memberChat)
+ openLoadedChat(memberChat)
}
- progressIndicator = false
+ closeAll()
+ chatModel.setContactNetworkStatus(memberContact, NetworkStatus.Connected())
}
- } else if (connectionStats.ratchetSyncAllowed) {
+ progressIndicator = false
+ }
+ } else if (connectionStats != null) {
+ if (connectionStats.ratchetSyncAllowed) {
showFixConnectionAlert(syncConnection = { syncMemberConnection() })
- } else {
+ } else if (connectionStats.ratchetSyncInProgress) {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.cant_send_message_to_member_alert_title),
generalGetString(MR.strings.encryption_renegotiation_in_progress)
)
+ } else {
+ AlertManager.shared.showAlertMsg(
+ generalGetString(MR.strings.cant_send_message_to_member_alert_title),
+ generalGetString(MR.strings.connection_not_ready)
+ )
}
}
},
@@ -366,7 +371,11 @@ fun GroupMemberInfoLayout(
if (contactId != null) {
OpenChatButton(modifier = Modifier.fillMaxWidth(0.33f), onClick = { openDirectChat(contactId) }) // legacy - only relevant for direct contacts created when joining group
} else {
- OpenChatButton(modifier = Modifier.fillMaxWidth(0.33f), onClick = { createMemberContact() })
+ OpenChatButton(
+ modifier = Modifier.fillMaxWidth(0.33f),
+ disabledLook = !(member.sendMsgEnabled || (member.activeConn?.connectionStats?.ratchetSyncAllowed ?: false)),
+ onClick = { createMemberContact() }
+ )
}
InfoViewActionButton(modifier = Modifier.fillMaxWidth(0.5f), painterResource(MR.images.ic_call), generalGetString(MR.strings.info_view_call_button), disabled = false, disabledLook = true, onClick = {
showSendMessageToEnableCallsAlert()
@@ -437,12 +446,12 @@ fun GroupMemberInfoLayout(
SectionDividerSpaced()
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) {
SwitchAddressButton(
- disabled = cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null } || cStats.ratchetSyncSendProhibited,
+ disabled = cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null } || !member.sendMsgEnabled,
switchAddress = switchMemberAddress
)
if (cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null }) {
AbortSwitchAddressButton(
- disabled = cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null && !it.canAbortSwitch } || cStats.ratchetSyncSendProhibited,
+ disabled = cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null && !it.canAbortSwitch } || !member.sendMsgEnabled,
abortSwitchAddress = abortSwitchMemberAddress
)
}
@@ -602,6 +611,7 @@ fun RemoveMemberButton(onClick: () -> Unit) {
@Composable
fun OpenChatButton(
modifier: Modifier,
+ disabledLook: Boolean = false,
onClick: () -> Unit
) {
InfoViewActionButton(
@@ -609,7 +619,7 @@ fun OpenChatButton(
icon = painterResource(MR.images.ic_chat_bubble),
title = generalGetString(MR.strings.info_view_message_button),
disabled = false,
- disabledLook = false,
+ disabledLook = disabledLook,
onClick = onClick
)
}
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 34788b5bde..a209126a89 100644
--- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
+++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
@@ -1696,6 +1696,7 @@
Can\'t call group member
Send message to enable calls.
Can\'t message group member
+ Connection not ready.
Welcome message