mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-17 08:41:55 +00:00
ui: fix channel contributor being able to "send message" without relays (#7139)
This commit is contained in:
@@ -392,38 +392,31 @@ struct ComposeView: View {
|
||||
}
|
||||
|
||||
let ownerState = ownerRelayState
|
||||
let subscriberState = subscriberRelayState
|
||||
if let gInfo = chat.chatInfo.groupInfo, gInfo.useRelays,
|
||||
![.memRejected, .memLeft, .memRemoved, .memGroupDeleted].contains(gInfo.membership.memberStatus) {
|
||||
if gInfo.membership.memberRole == .owner {
|
||||
if let s = ownerState, s.relays.isEmpty || s.activeCount < s.relays.count {
|
||||
ownerChannelRelayBar(relays: s.relays, activeCount: s.activeCount, failedCount: s.failedCount, removedCount: s.removedCount)
|
||||
}
|
||||
} else {
|
||||
let hostnames = (chatModel.channelRelayHostnames[gInfo.groupId] ?? []).sorted()
|
||||
let relayMembers = chatModel.groupMembers
|
||||
.filter { $0.wrapped.memberRole == .relay && ![.memRemoved, .memGroupDeleted].contains($0.wrapped.memberStatus) }
|
||||
.sorted { hostFromRelayLink($0.wrapped.relayLink ?? "") < hostFromRelayLink($1.wrapped.relayLink ?? "") }
|
||||
} else if let s = subscriberState {
|
||||
let showProgress = !gInfo.nextConnectPrepared || composeState.inProgress
|
||||
let removedCount = relayMembers.filter { relayMemberRemoved($0.wrapped.memberStatus) }.count
|
||||
let connectedCount = relayMembers.filter { !relayMemberRemoved($0.wrapped.memberStatus) && $0.wrapped.activeConn?.connStatus == .ready && $0.wrapped.activeConn?.connFailedErr == nil }.count
|
||||
let failedCount = relayMembers.filter { !relayMemberRemoved($0.wrapped.memberStatus) && $0.wrapped.activeConn?.connFailedErr != nil }.count
|
||||
let resolvedCount = connectedCount + removedCount + failedCount
|
||||
let total = relayMembers.count > 0 ? relayMembers.count : hostnames.count
|
||||
if total == 0 || removedCount + failedCount > 0 || resolvedCount < total {
|
||||
let resolvedCount = s.connectedCount + s.removedCount + s.failedCount
|
||||
if s.total == 0 || s.removedCount + s.failedCount > 0 || resolvedCount < s.total {
|
||||
subscriberChannelRelayBar(
|
||||
hostnames: hostnames,
|
||||
relayMembers: relayMembers,
|
||||
connectedCount: connectedCount,
|
||||
removedCount: removedCount,
|
||||
failedCount: failedCount,
|
||||
total: total,
|
||||
hostnames: s.hostnames,
|
||||
relayMembers: s.relayMembers,
|
||||
connectedCount: s.connectedCount,
|
||||
removedCount: s.removedCount,
|
||||
failedCount: s.failedCount,
|
||||
total: s.total,
|
||||
showProgress: showProgress
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let userCantSendReason = chat.chatInfo.userCantSendReason(allRelaysBroken: ownerState?.noActiveRelays ?? false)
|
||||
let userCantSendReason = chat.chatInfo.userCantSendReason(allRelaysBroken: (ownerState?.noActiveRelays ?? subscriberState?.noActiveRelays) ?? false)
|
||||
let composeEnabled = (
|
||||
userCantSendReason == nil ||
|
||||
(chat.chatInfo.groupInfo?.nextConnectPrepared ?? false) ||
|
||||
@@ -748,8 +741,25 @@ struct ComposeView: View {
|
||||
return (relays, activeCount, failedCount, removedCount, noActiveRelays)
|
||||
}
|
||||
|
||||
private var subscriberRelayState: (hostnames: [String], relayMembers: [GMember], connectedCount: Int, removedCount: Int, failedCount: Int, total: Int, noActiveRelays: Bool)? {
|
||||
guard let gInfo = chat.chatInfo.groupInfo, gInfo.useRelays,
|
||||
gInfo.membership.memberRole != .owner,
|
||||
![.memRejected, .memLeft, .memRemoved, .memGroupDeleted].contains(gInfo.membership.memberStatus)
|
||||
else { return nil }
|
||||
let hostnames = (chatModel.channelRelayHostnames[gInfo.groupId] ?? []).sorted()
|
||||
let relayMembers = chatModel.groupMembers
|
||||
.filter { $0.wrapped.memberRole == .relay && ![.memRemoved, .memGroupDeleted].contains($0.wrapped.memberStatus) }
|
||||
.sorted { hostFromRelayLink($0.wrapped.relayLink ?? "") < hostFromRelayLink($1.wrapped.relayLink ?? "") }
|
||||
let removedCount = relayMembers.filter { relayMemberRemoved($0.wrapped.memberStatus) }.count
|
||||
let connectedCount = relayMembers.filter { !relayMemberRemoved($0.wrapped.memberStatus) && $0.wrapped.activeConn?.connStatus == .ready && $0.wrapped.activeConn?.connFailedErr == nil }.count
|
||||
let failedCount = relayMembers.filter { !relayMemberRemoved($0.wrapped.memberStatus) && $0.wrapped.activeConn?.connFailedErr != nil }.count
|
||||
let total = relayMembers.count > 0 ? relayMembers.count : hostnames.count
|
||||
let noActiveRelays = connectedCount == 0 && (removedCount + failedCount) == total
|
||||
return (hostnames, relayMembers, connectedCount, removedCount, failedCount, total, noActiveRelays)
|
||||
}
|
||||
|
||||
private var disabledText: LocalizedStringKey? {
|
||||
chat.chatInfo.userCantSendReason(allRelaysBroken: ownerRelayState?.noActiveRelays ?? false)?.composeLabel
|
||||
chat.chatInfo.userCantSendReason(allRelaysBroken: (ownerRelayState?.noActiveRelays ?? subscriberRelayState?.noActiveRelays) ?? false)?.composeLabel
|
||||
}
|
||||
|
||||
@ViewBuilder private func ownerChannelRelayBar(relays: [GroupRelay], activeCount: Int, failedCount: Int, removedCount: Int) -> some View {
|
||||
|
||||
@@ -1720,11 +1720,11 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable {
|
||||
if groupInfo.membership.memberActive {
|
||||
switch(groupChatScope) {
|
||||
case .none:
|
||||
if allRelaysBroken && groupInfo.useRelays { return ("can't broadcast", nil) }
|
||||
if groupInfo.membership.memberPending { return ("reviewed by admins", "Please contact group admin.") }
|
||||
if groupInfo.membership.memberRole == .observer {
|
||||
return groupInfo.useRelays ? ("you are subscriber", nil) : ("you are observer", "Please contact group admin.")
|
||||
}
|
||||
if allRelaysBroken && groupInfo.useRelays { return ("can't broadcast", nil) }
|
||||
return nil
|
||||
case let .some(.memberSupport(groupMember_: .some(supportMember))):
|
||||
if supportMember.versionRange.maxVersion < GROUP_KNOCKING_VERSION && !supportMember.memberPending {
|
||||
|
||||
+3
-3
@@ -1660,9 +1660,6 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
if (groupInfo.membership.memberActive) {
|
||||
when (groupChatScope) {
|
||||
null -> {
|
||||
if (allRelaysBroken && groupInfo.useRelays) {
|
||||
return generalGetString(MR.strings.cant_broadcast_message) to null
|
||||
}
|
||||
if (groupInfo.membership.memberPending) {
|
||||
return generalGetString(MR.strings.reviewed_by_admins) to generalGetString(MR.strings.observer_cant_send_message_desc)
|
||||
}
|
||||
@@ -1673,6 +1670,9 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
generalGetString(MR.strings.observer_cant_send_message_title) to generalGetString(MR.strings.observer_cant_send_message_desc)
|
||||
}
|
||||
}
|
||||
if (allRelaysBroken && groupInfo.useRelays) {
|
||||
return generalGetString(MR.strings.cant_broadcast_message) to null
|
||||
}
|
||||
return null
|
||||
}
|
||||
is GroupChatScopeInfo.MemberSupport ->
|
||||
|
||||
+35
-13
@@ -1203,8 +1203,9 @@ fun ComposeView(
|
||||
}
|
||||
|
||||
val ownerRelayState = ownerRelayState(chat, chatModel)
|
||||
val subscriberRelayState = subscriberRelayState(chat, chatModel)
|
||||
|
||||
val userCantSendReason = rememberUpdatedState(chat.chatInfo.userCantSendReason(ownerRelayState?.noActiveRelays == true))
|
||||
val userCantSendReason = rememberUpdatedState(chat.chatInfo.userCantSendReason((ownerRelayState?.noActiveRelays ?: subscriberRelayState?.noActiveRelays) == true))
|
||||
val sendMsgEnabled = rememberUpdatedState(userCantSendReason.value == null)
|
||||
val nextSendGrpInv = rememberUpdatedState(chat.nextSendGrpInv)
|
||||
|
||||
@@ -1575,18 +1576,12 @@ fun ComposeView(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val hostnames = (chatModel.channelRelayHostnames[gInfo.groupId] ?: emptyList()).sorted()
|
||||
val relayMembers = chatModel.groupMembers.value
|
||||
.filter { it.memberRole == GroupMemberRole.Relay && it.memberStatus !in listOf(GroupMemberStatus.MemRemoved, GroupMemberStatus.MemGroupDeleted) }
|
||||
.sortedBy { hostFromRelayLink(it.relayLink ?: "") }
|
||||
val showProgress = !gInfo.nextConnectPrepared || composeState.value.inProgress
|
||||
val removedCount = relayMembers.count { relayMemberRemoved(it.memberStatus) }
|
||||
val connectedCount = relayMembers.count { !relayMemberRemoved(it.memberStatus) && it.activeConn?.connStatus == ConnStatus.Ready && it.activeConn?.connFailedErr == null }
|
||||
val failedCount = relayMembers.count { !relayMemberRemoved(it.memberStatus) && it.activeConn?.connFailedErr != null }
|
||||
val resolvedCount = connectedCount + removedCount + failedCount
|
||||
val total = if (relayMembers.isNotEmpty()) relayMembers.size else hostnames.size
|
||||
if (total == 0 || removedCount + failedCount > 0 || resolvedCount < total) {
|
||||
SubscriberChannelRelayBar(hostnames, relayMembers, connectedCount, removedCount, failedCount, total, showProgress, relayListExpanded)
|
||||
subscriberRelayState?.let { s ->
|
||||
val showProgress = !gInfo.nextConnectPrepared || composeState.value.inProgress
|
||||
val resolvedCount = s.connectedCount + s.removedCount + s.failedCount
|
||||
if (s.total == 0 || s.removedCount + s.failedCount > 0 || resolvedCount < s.total) {
|
||||
SubscriberChannelRelayBar(s.hostnames, s.relayMembers, s.connectedCount, s.removedCount, s.failedCount, s.total, showProgress, relayListExpanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2052,6 +2047,33 @@ private data class OwnerRelayState(
|
||||
val noActiveRelays: Boolean
|
||||
)
|
||||
|
||||
private fun subscriberRelayState(chat: Chat, chatModel: ChatModel): SubscriberRelayState? {
|
||||
val gInfo = (chat.chatInfo as? ChatInfo.Group)?.groupInfo ?: return null
|
||||
if (!gInfo.useRelays || gInfo.membership.memberRole == GroupMemberRole.Owner ||
|
||||
gInfo.membership.memberStatus in listOf(GroupMemberStatus.MemRejected, GroupMemberStatus.MemLeft, GroupMemberStatus.MemRemoved, GroupMemberStatus.MemGroupDeleted)
|
||||
) return null
|
||||
val hostnames = (chatModel.channelRelayHostnames[gInfo.groupId] ?: emptyList()).sorted()
|
||||
val relayMembers = chatModel.groupMembers.value
|
||||
.filter { it.memberRole == GroupMemberRole.Relay && it.memberStatus !in listOf(GroupMemberStatus.MemRemoved, GroupMemberStatus.MemGroupDeleted) }
|
||||
.sortedBy { hostFromRelayLink(it.relayLink ?: "") }
|
||||
val removedCount = relayMembers.count { relayMemberRemoved(it.memberStatus) }
|
||||
val connectedCount = relayMembers.count { !relayMemberRemoved(it.memberStatus) && it.activeConn?.connStatus == ConnStatus.Ready && it.activeConn?.connFailedErr == null }
|
||||
val failedCount = relayMembers.count { !relayMemberRemoved(it.memberStatus) && it.activeConn?.connFailedErr != null }
|
||||
val total = if (relayMembers.isNotEmpty()) relayMembers.size else hostnames.size
|
||||
val noActiveRelays = connectedCount == 0 && (removedCount + failedCount) == total
|
||||
return SubscriberRelayState(hostnames, relayMembers, connectedCount, removedCount, failedCount, total, noActiveRelays)
|
||||
}
|
||||
|
||||
private data class SubscriberRelayState(
|
||||
val hostnames: List<String>,
|
||||
val relayMembers: List<GroupMember>,
|
||||
val connectedCount: Int,
|
||||
val removedCount: Int,
|
||||
val failedCount: Int,
|
||||
val total: Int,
|
||||
val noActiveRelays: Boolean
|
||||
)
|
||||
|
||||
private fun relayMemberRemoved(status: GroupMemberStatus?): Boolean =
|
||||
status in listOf(GroupMemberStatus.MemLeft, GroupMemberStatus.MemRemoved, GroupMemberStatus.MemGroupDeleted)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user