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