ui: show new messages from support scope in main chat preview when invitee is pending (#5909)

This commit is contained in:
spaced4ndy
2025-05-14 15:14:34 +00:00
committed by GitHub
parent d3bc22726a
commit b97e1e0f11
10 changed files with 45 additions and 55 deletions
+1 -1
View File
@@ -582,7 +582,7 @@ final class ChatModel: ObservableObject {
// update chat list
if let i = getChatIndex(cInfo.id) {
// update preview
if cInfo.groupChatScope() == nil {
if cInfo.groupChatScope() == nil || cInfo.groupInfo?.membership.memberPending ?? false {
chats[i].chatItems = switch cInfo {
case .group:
if let currentPreviewItem = chats[i].chatItems.first {
@@ -460,7 +460,7 @@ struct ComposeView: View {
if im.secondaryIMFilter == nil {
if chat.userIsPending {
Text("reviewed by moderators")
Text("reviewed by admins")
.italic()
.foregroundColor(theme.colors.secondary)
.padding(.horizontal, 12)
@@ -540,7 +540,7 @@ struct GroupChatInfoView: View {
SecondaryChatView(chat: Chat(chatInfo: .group(groupInfo: groupInfo, groupChatScope: scopeInfo), chatItems: [], chatStats: ChatStats()))
} label: {
HStack {
Label("Chat with admins", systemImage: chat.supportUnreadCount > 0 ? "flag.filled" : "flag")
Label("Chat with admins", systemImage: chat.supportUnreadCount > 0 ? "flag.fill" : "flag")
Spacer()
if chat.supportUnreadCount > 0 {
UnreadBadge(count: chat.supportUnreadCount, color: theme.colors.primary)
@@ -346,6 +346,7 @@ struct ChatPreviewView: View {
case .memRejected: chatPreviewInfoText("rejected")
case .memInvited: groupInvitationPreviewText(groupInfo)
case .memAccepted: chatPreviewInfoText("connecting…")
case .memPendingReview, .memPendingApproval: chatPreviewInfoText("reviewed by admins")
default: EmptyView()
}
default: EmptyView()
@@ -439,9 +440,11 @@ struct ChatPreviewView: View {
if progressByTimeout {
ProgressView()
} else if chat.chatStats.reportsCount > 0 {
groupReportsIcon(size: size * 0.8)
flagIcon(size: size * 0.8, color: .red)
} else if chat.supportUnreadCount > 0 {
GroupSupportUnreadIcon(size: size * 0.8)
flagIcon(size: size * 0.8, color: theme.colors.primary)
} else if chat.chatInfo.groupInfo?.membership.memberPending ?? false {
flagIcon(size: size * 0.8, color: theme.colors.secondary)
} else {
incognitoIcon(chat.chatInfo.incognito, theme.colors.secondary, size: size)
}
@@ -487,25 +490,12 @@ struct ChatPreviewView: View {
}
}
func groupReportsIcon(size: CGFloat) -> some View {
func flagIcon(size: CGFloat, color: Color) -> some View {
Image(systemName: "flag")
.resizable()
.scaledToFit()
.frame(width: size, height: size)
.foregroundColor(.red)
}
struct GroupSupportUnreadIcon: View {
@EnvironmentObject var theme: AppTheme
var size: CGFloat
var body: some View {
Image(systemName: "flag")
.resizable()
.scaledToFit()
.frame(width: size, height: size)
.foregroundColor(theme.colors.primary)
}
.foregroundColor(color)
}
func smallContentPreview(size: CGFloat, _ view: @escaping () -> some View) -> some View {
@@ -200,7 +200,7 @@ actual fun PlatformTextField(
if (composeState.value.preview is ComposePreview.VoicePreview) {
ComposeOverlay(MR.strings.voice_message_send_text, textStyle, padding)
} else if (userIsPending) {
ComposeOverlay(MR.strings.reviewed_by_moderators, textStyle, padding)
ComposeOverlay(MR.strings.reviewed_by_admins, textStyle, padding)
} else if (userIsObserver) {
ComposeOverlay(MR.strings.you_are_observer, textStyle, padding)
}
@@ -442,9 +442,9 @@ object ChatModel {
val i = getChatIndex(rhId, cInfo.id)
val chat: Chat
if (i >= 0) {
chat = chats[i]
// update preview
if (cInfo.groupChatScope() == null) {
chat = chatsContext.chats[i]
// update preview (for chat from main scope to show new items for invitee in pending status)
if (cInfo.groupChatScope() == null || cInfo.groupInfo_?.membership?.memberPending == true) {
val newPreviewItem = when (cInfo) {
is ChatInfo.Group -> {
val currentPreviewItem = chat.chatItems.firstOrNull()
@@ -462,7 +462,7 @@ object ChatModel {
else -> cItem
}
val wasUnread = chat.unreadTag
chats[i] = chat.copy(
chatsContext.chats[i] = chat.copy(
chatItems = arrayListOf(newPreviewItem),
chatStats =
if (cItem.meta.itemStatus is CIStatus.RcvNew) {
@@ -471,11 +471,11 @@ object ChatModel {
} else
chat.chatStats
)
updateChatTagReadInPrimaryContext(chats[i], wasUnread)
updateChatTagReadInPrimaryContext(chatsContext.chats[i], wasUnread)
}
// pop chat
if (appPlatform.isDesktop && cItem.chatDir.sent) {
reorderChat(chats[i], 0)
reorderChat(chatsContext.chats[i], 0)
} else {
popChatCollector.throttlePopChat(chat.remoteHostId, chat.id, currentPosition = i)
}
@@ -1558,7 +1558,13 @@ sealed class ChatInfo: SomeChat, NamedChat {
is Direct -> contact.activeConn == null && contact.profile.contactLink != null && contact.active
else -> false
}
}
val groupInfo_: GroupInfo?
get() = when (this) {
is Group -> groupInfo
else -> null
}
}
@Serializable
sealed class NetworkStatus {
@@ -241,6 +241,8 @@ fun ChatPreviewView(
GroupMemberStatus.MemRejected -> Text(stringResource(MR.strings.group_preview_rejected))
GroupMemberStatus.MemInvited -> Text(groupInvitationPreviewText(currentUserProfileDisplayName, cInfo.groupInfo))
GroupMemberStatus.MemAccepted -> Text(stringResource(MR.strings.group_connection_pending), color = MaterialTheme.colors.secondary)
GroupMemberStatus.MemPendingReview, GroupMemberStatus.MemPendingApproval ->
Text(stringResource(MR.strings.reviewed_by_admins), color = MaterialTheme.colors.secondary)
else -> {}
}
else -> {}
@@ -363,9 +365,11 @@ fun ChatPreviewView(
if (progressByTimeout) {
progressView()
} else if (chat.chatStats.reportsCount > 0) {
GroupReportsIcon()
FlagIcon(color = MaterialTheme.colors.error)
} else if (chat.supportUnreadCount > 0) {
GroupSupportUnreadIcon()
FlagIcon(color = MaterialTheme.colors.primary)
} else if (chat.chatInfo.groupInfo_?.membership?.memberPending == true) {
FlagIcon(color = MaterialTheme.colors.secondary)
} else {
IncognitoIcon(chat.chatInfo.incognito)
}
@@ -550,23 +554,11 @@ fun IncognitoIcon(incognito: Boolean) {
}
@Composable
fun GroupReportsIcon() {
fun FlagIcon(color: Color) {
Icon(
painterResource(MR.images.ic_flag),
contentDescription = null,
tint = MaterialTheme.colors.error,
modifier = Modifier
.size(21.sp.toDp())
.offset(x = 2.sp.toDp())
)
}
@Composable
fun GroupSupportUnreadIcon() {
Icon(
painterResource(MR.images.ic_flag),
contentDescription = null,
tint = MaterialTheme.colors.primary,
tint = color,
modifier = Modifier
.size(21.sp.toDp())
.offset(x = 2.sp.toDp())
@@ -492,7 +492,7 @@
<string name="image_decoding_exception_desc">The image cannot be decoded. Please, try a different image or contact developers.</string>
<string name="video_decoding_exception_desc">The video cannot be decoded. Please, try a different video or contact developers.</string>
<string name="you_are_observer">you are observer</string>
<string name="reviewed_by_moderators">reviewed by moderators</string>
<string name="reviewed_by_admins">reviewed by admins</string>
<string name="observer_cant_send_message_title">You can\'t send messages!</string>
<string name="observer_cant_send_message_desc">Please contact group admin.</string>
<string name="files_and_media_prohibited">Files and media prohibited!</string>
@@ -206,7 +206,7 @@ actual fun PlatformTextField(
if (composeState.value.preview is ComposePreview.VoicePreview) {
ComposeOverlay(MR.strings.voice_message_send_text, textStyle, padding)
} else if (userIsPending) {
ComposeOverlay(MR.strings.reviewed_by_moderators, textStyle, padding)
ComposeOverlay(MR.strings.reviewed_by_admins, textStyle, padding)
} else if (userIsObserver) {
ComposeOverlay(MR.strings.you_are_observer, textStyle, padding)
}
+11 -9
View File
@@ -2121,19 +2121,21 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
processUserAccepted = case acceptance of
GAAccepted -> do
membership' <- withStore' $ \db -> updateGroupMemberAccepted db user membership GSMemConnected role
let scopeInfo = Just $ GCSIMemberSupport {groupMember_ = Nothing}
(ci, cInfo) <- saveRcvChatItemNoParse user (CDGroupRcv gInfo scopeInfo m) msg brokerTs (CIRcvGroupEvent RGEUserAccepted)
let gInfo' = gInfo {membership = membership'}
scopeInfo = Just $ GCSIMemberSupport {groupMember_ = Nothing}
(ci, cInfo) <- saveRcvChatItemNoParse user (CDGroupRcv gInfo' scopeInfo m) msg brokerTs (CIRcvGroupEvent RGEUserAccepted)
groupMsgToView cInfo ci
toView $ CEvtUserJoinedGroup user gInfo {membership = membership'} m
let cd = CDGroupRcv gInfo Nothing m
toView $ CEvtUserJoinedGroup user gInfo' m
let cd = CDGroupRcv gInfo' Nothing m
createInternalChatItem user cd (CIRcvGroupE2EEInfo E2EInfo {pqEnabled = PQEncOff}) Nothing
createGroupFeatureItems user cd CIRcvGroupFeature gInfo
maybeCreateGroupDescrLocal gInfo m
createGroupFeatureItems user cd CIRcvGroupFeature gInfo'
maybeCreateGroupDescrLocal gInfo' m
GAPendingReview -> do
membership' <- withStore' $ \db -> updateGroupMemberAccepted db user membership GSMemPendingReview role
let scopeInfo = Just $ GCSIMemberSupport {groupMember_ = Nothing}
createInternalChatItem user (CDGroupSnd gInfo scopeInfo) (CISndGroupEvent SGEUserPendingReview) Nothing
toView $ CEvtMemberAcceptedByOther user gInfo m membership'
let gInfo' = gInfo {membership = membership'}
scopeInfo = Just $ GCSIMemberSupport {groupMember_ = Nothing}
createInternalChatItem user (CDGroupSnd gInfo' scopeInfo) (CISndGroupEvent SGEUserPendingReview) Nothing
toView $ CEvtMemberAcceptedByOther user gInfo' m membership'
GAPendingApproval ->
messageWarning "x.grp.link.acpt: unexpected group acceptance - pending approval"
introduceToRemainingMembers acceptedMember = do