From 75d62b08ca91ae6b7e171f40b8d2dd322fe23f15 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:25:06 +0000 Subject: [PATCH] ui: group service events channel texts (#6781) --- apps/ios/Shared/Views/Chat/ChatItemView.swift | 12 +- .../Views/ChatList/ChatPreviewView.swift | 2 +- apps/ios/SimpleXChat/ChatTypes.swift | 104 ++++++++++-------- apps/ios/SimpleXChat/Notifications.swift | 6 +- .../chat/simplex/common/model/ChatModel.kt | 35 ++++-- .../simplex/common/platform/NtfManager.kt | 8 +- .../common/views/chat/item/ChatItemView.kt | 12 +- .../common/views/chatlist/ChatPreviewView.kt | 2 +- .../commonMain/resources/MR/base/strings.xml | 4 + 9 files changed, 108 insertions(+), 77 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/ChatItemView.swift b/apps/ios/Shared/Views/Chat/ChatItemView.swift index f72bf083f6..138aed6c65 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemView.swift @@ -195,7 +195,7 @@ struct ChatItemContentView: View { } private func pendingReviewEventItemText() -> Text { - Text(chatItem.content.text) + Text(chatItem.content.text(isChannel: chat.chatInfo.isChannel)) .font(.caption) .foregroundColor(theme.colors.secondary) .fontWeight(.bold) @@ -209,9 +209,9 @@ struct ChatItemContentView: View { .font(.caption) .foregroundColor(secondaryColor) .fontWeight(.light) - + chatEventText(chatItem, secondaryColor) + + chatEventText(chatItem, secondaryColor, isChannel: chat.chatInfo.isChannel) } else { - return chatEventText(chatItem, secondaryColor) + return chatEventText(chatItem, secondaryColor, isChannel: chat.chatInfo.isChannel) } } @@ -234,7 +234,7 @@ struct ChatItemContentView: View { return if count <= 1 { nil } else if ns.count == 0 { - Text("\(count) group events") + chat.chatInfo.isChannel ? Text("\(count) channel events") : Text("\(count) group events") } else if count > ns.count { Text(members) + textSpace + Text("and \(count - ns.count) other events") } else { @@ -275,8 +275,8 @@ func chatEventText(_ eventText: LocalizedStringKey, _ ts: Text, _ secondaryColor chatEventText(Text(eventText) + textSpace + ts, secondaryColor) } -func chatEventText(_ ci: ChatItem, _ secondaryColor: Color) -> Text { - chatEventText("\(ci.content.text)", ci.timestampText, secondaryColor) +func chatEventText(_ ci: ChatItem, _ secondaryColor: Color, isChannel: Bool = false) -> Text { + chatEventText("\(ci.content.text(isChannel: isChannel))", ci.timestampText, secondaryColor) } struct ChatItemView_Previews: PreviewProvider { diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index 112e4099c0..3524ceff18 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -296,7 +296,7 @@ struct ChatPreviewView: View { } func chatItemPreview(_ cItem: ChatItem) -> (Text, Bool) { - let itemText = cItem.meta.itemDeleted == nil ? cItem.text : markedDeletedText() + let itemText = cItem.meta.itemDeleted == nil ? cItem.text(isChannel: chat.chatInfo.isChannel) : markedDeletedText() let itemFormattedText = cItem.meta.itemDeleted == nil ? cItem.formattedText : nil let r = messageText(itemText, itemFormattedText, sender: cItem.meta.showGroupAsSender ? nil : cItem.memberDisplayName, preview: true, mentions: cItem.mentions, userMemberId: chat.chatInfo.groupInfo?.membership.memberId, showSecrets: nil, backgroundColor: UIColor(theme.colors.background), prefix: prefix()) return (Text(AttributedString(r.string)), r.hasSecrets) diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index b3d144b446..4a14d3ae99 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -1652,6 +1652,10 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable { } } + public var isChannel: Bool { + groupInfo?.useRelays == true + } + // this works for features that are common for contacts and groups public func featureEnabled(_ feature: ChatFeature) -> Bool { switch self { @@ -3191,11 +3195,13 @@ public struct ChatItem: Identifiable, Decodable, Hashable { public var timestampText: Text { meta.timestampText } - public var text: String { - switch (content.text, content.msgContent, file) { + public var text: String { text(isChannel: false) } + + public func text(isChannel: Bool) -> String { + switch (content.text(isChannel: isChannel), content.msgContent, file) { case let ("", .some(.voice(_, duration)), _): return "Voice message (\(durationText(duration)))" case let ("", _, .some(file)): return file.fileName - default: return content.text + default: return content.text(isChannel: isChannel) } } @@ -4047,42 +4053,42 @@ public enum CIContent: Decodable, ItemContent, Hashable { case chatBanner case invalidJSON(json: Data?) - public var text: String { - get { - switch self { - case let .sndMsgContent(mc): return mc.text - case let .rcvMsgContent(mc): return mc.text - case .sndDeleted: return NSLocalizedString("deleted", comment: "deleted chat item") - case .rcvDeleted: return NSLocalizedString("deleted", comment: "deleted chat item") - case let .sndCall(status, duration): return status.text(duration) - case let .rcvCall(status, duration): return status.text(duration) - case let .rcvIntegrityError(msgError): return msgError.text - case let .rcvDecryptionError(msgDecryptError, _): return msgDecryptError.text - case let .rcvGroupInvitation(groupInvitation, _): return groupInvitation.text - case let .sndGroupInvitation(groupInvitation, _): return groupInvitation.text - case let .rcvDirectEvent(rcvDirectEvent): return rcvDirectEvent.text - case let .rcvGroupEvent(rcvGroupEvent): return rcvGroupEvent.text - case let .sndGroupEvent(sndGroupEvent): return sndGroupEvent.text - case let .rcvConnEvent(rcvConnEvent): return rcvConnEvent.text - case let .sndConnEvent(sndConnEvent): return sndConnEvent.text - case let .rcvChatFeature(feature, enabled, param): return CIContent.featureText(feature, enabled.text, param) - case let .sndChatFeature(feature, enabled, param): return CIContent.featureText(feature, enabled.text, param) - case let .rcvChatPreference(feature, allowed, param): return CIContent.preferenceText(feature, allowed, param) - case let .sndChatPreference(feature, allowed, param): return CIContent.preferenceText(feature, allowed, param) - case let .rcvGroupFeature(feature, preference, param, role): return CIContent.featureText(feature, preference.enable.text, param, role) - case let .sndGroupFeature(feature, preference, param, role): return CIContent.featureText(feature, preference.enable.text, param, role) - case let .rcvChatFeatureRejected(feature): return String.localizedStringWithFormat("%@: received, prohibited", feature.text) - case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text) - case .sndModerated: return NSLocalizedString("moderated", comment: "moderated chat item") - case .rcvModerated: return NSLocalizedString("moderated", comment: "moderated chat item") - case .rcvBlocked: return NSLocalizedString("blocked by admin", comment: "blocked chat item") - case let .sndDirectE2EEInfo(e2eeInfo): return directE2EEInfoStr(e2eeInfo) - case let .rcvDirectE2EEInfo(e2eeInfo): return directE2EEInfoStr(e2eeInfo) - case .sndGroupE2EEInfo: return e2eeInfoNoPQStr - case .rcvGroupE2EEInfo: return e2eeInfoNoPQStr - case .chatBanner: return "" - case .invalidJSON: return NSLocalizedString("invalid data", comment: "invalid chat item") - } + public var text: String { text(isChannel: false) } + + public func text(isChannel: Bool) -> String { + switch self { + case let .sndMsgContent(mc): return mc.text + case let .rcvMsgContent(mc): return mc.text + case .sndDeleted: return NSLocalizedString("deleted", comment: "deleted chat item") + case .rcvDeleted: return NSLocalizedString("deleted", comment: "deleted chat item") + case let .sndCall(status, duration): return status.text(duration) + case let .rcvCall(status, duration): return status.text(duration) + case let .rcvIntegrityError(msgError): return msgError.text + case let .rcvDecryptionError(msgDecryptError, _): return msgDecryptError.text + case let .rcvGroupInvitation(groupInvitation, _): return groupInvitation.text + case let .sndGroupInvitation(groupInvitation, _): return groupInvitation.text + case let .rcvDirectEvent(rcvDirectEvent): return rcvDirectEvent.text + case let .rcvGroupEvent(rcvGroupEvent): return rcvGroupEvent.text(isChannel: isChannel) + case let .sndGroupEvent(sndGroupEvent): return sndGroupEvent.text(isChannel: isChannel) + case let .rcvConnEvent(rcvConnEvent): return rcvConnEvent.text + case let .sndConnEvent(sndConnEvent): return sndConnEvent.text + case let .rcvChatFeature(feature, enabled, param): return CIContent.featureText(feature, enabled.text, param) + case let .sndChatFeature(feature, enabled, param): return CIContent.featureText(feature, enabled.text, param) + case let .rcvChatPreference(feature, allowed, param): return CIContent.preferenceText(feature, allowed, param) + case let .sndChatPreference(feature, allowed, param): return CIContent.preferenceText(feature, allowed, param) + case let .rcvGroupFeature(feature, preference, param, role): return CIContent.featureText(feature, preference.enable.text, param, role) + case let .sndGroupFeature(feature, preference, param, role): return CIContent.featureText(feature, preference.enable.text, param, role) + case let .rcvChatFeatureRejected(feature): return String.localizedStringWithFormat("%@: received, prohibited", feature.text) + case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text) + case .sndModerated: return NSLocalizedString("moderated", comment: "moderated chat item") + case .rcvModerated: return NSLocalizedString("moderated", comment: "moderated chat item") + case .rcvBlocked: return NSLocalizedString("blocked by admin", comment: "blocked chat item") + case let .sndDirectE2EEInfo(e2eeInfo): return directE2EEInfoStr(e2eeInfo) + case let .rcvDirectE2EEInfo(e2eeInfo): return directE2EEInfoStr(e2eeInfo) + case .sndGroupE2EEInfo: return e2eeInfoNoPQStr + case .rcvGroupE2EEInfo: return e2eeInfoNoPQStr + case .chatBanner: return "" + case .invalidJSON: return NSLocalizedString("invalid data", comment: "invalid chat item") } } @@ -5153,7 +5159,9 @@ public enum RcvGroupEvent: Decodable, Hashable { case memberProfileUpdated(fromProfile: Profile, toProfile: Profile) case newMemberPendingReview - var text: String { + var text: String { text(isChannel: false) } + + func text(isChannel: Bool) -> String { switch self { case let .memberAdded(_, profile): return String.localizedStringWithFormat(NSLocalizedString("invited %@", comment: "rcv group event chat item"), profile.profileViewName) @@ -5175,8 +5183,12 @@ public enum RcvGroupEvent: Decodable, Hashable { case let .memberDeleted(_, profile): return String.localizedStringWithFormat(NSLocalizedString("removed %@", comment: "rcv group event chat item"), profile.profileViewName) case .userDeleted: return NSLocalizedString("removed you", comment: "rcv group event chat item") - case .groupDeleted: return NSLocalizedString("deleted group", comment: "rcv group event chat item") - case .groupUpdated: return NSLocalizedString("updated group profile", comment: "rcv group event chat item") + case .groupDeleted: return isChannel + ? NSLocalizedString("deleted channel", comment: "rcv group event chat item") + : NSLocalizedString("deleted group", comment: "rcv group event chat item") + case .groupUpdated: return isChannel + ? NSLocalizedString("updated channel profile", comment: "rcv group event chat item") + : NSLocalizedString("updated group profile", comment: "rcv group event chat item") case .invitedViaGroupLink: return NSLocalizedString("invited via your group link", comment: "rcv group event chat item") case .memberCreatedContact: return NSLocalizedString("requested connection", comment: "rcv group event chat item") case let .memberProfileUpdated(fromProfile, toProfile): return profileUpdatedText(fromProfile, toProfile) @@ -5208,7 +5220,9 @@ public enum SndGroupEvent: Decodable, Hashable { case memberAccepted(groupMemberId: Int64, profile: Profile) case userPendingReview - var text: String { + var text: String { text(isChannel: false) } + + func text(isChannel: Bool) -> String { switch self { case let .memberRole(_, profile, role): return String.localizedStringWithFormat(NSLocalizedString("you changed role of %@ to %@", comment: "snd group event chat item"), profile.profileViewName, role.text) @@ -5223,7 +5237,9 @@ public enum SndGroupEvent: Decodable, Hashable { case let .memberDeleted(_, profile): return String.localizedStringWithFormat(NSLocalizedString("you removed %@", comment: "snd group event chat item"), profile.profileViewName) case .userLeft: return NSLocalizedString("you left", comment: "snd group event chat item") - case .groupUpdated: return NSLocalizedString("group profile updated", comment: "snd group event chat item") + case .groupUpdated: return isChannel + ? NSLocalizedString("channel profile updated", comment: "snd group event chat item") + : NSLocalizedString("group profile updated", comment: "snd group event chat item") case .memberAccepted: return NSLocalizedString("you accepted this member", comment: "snd group event chat item") case .userPendingReview: return NSLocalizedString("Please wait for group moderators to review your request to join the group.", comment: "snd group event chat item") diff --git a/apps/ios/SimpleXChat/Notifications.swift b/apps/ios/SimpleXChat/Notifications.swift index 24dc58202a..a40e8eda99 100644 --- a/apps/ios/SimpleXChat/Notifications.swift +++ b/apps/ios/SimpleXChat/Notifications.swift @@ -74,7 +74,7 @@ public func createMessageReceivedNtf(_ user: any UserLike, _ cInfo: ChatInfo, _ return createNotification( categoryIdentifier: ntfCategoryMessageReceived, title: title, - body: previewMode == .message ? hideSecrets(cItem) : NSLocalizedString("new message", comment: "notification"), + body: previewMode == .message ? hideSecrets(cItem, isChannel: cInfo.isChannel) : NSLocalizedString("new message", comment: "notification"), targetContentIdentifier: cInfo.id, userInfo: ["userId": user.userId], // userInfo: ["chatId": cInfo.id, "chatItemId": cItem.id] @@ -197,7 +197,7 @@ public func createNotification( } // Spec: spec/services/notifications.md#hideSecrets -func hideSecrets(_ cItem: ChatItem) -> String { +func hideSecrets(_ cItem: ChatItem, isChannel: Bool = false) -> String { if let md = cItem.formattedText { var res = "" for ft in md { @@ -213,7 +213,7 @@ func hideSecrets(_ cItem: ChatItem) -> String { if case let .report(text, reason) = mc { return String.localizedStringWithFormat(NSLocalizedString("Report: %@", comment: "report in notification"), text.isEmpty ? reason.text : text) } else { - return cItem.text + return cItem.text(isChannel: isChannel) } } } 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 0ac7a1b973..4e406044e5 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 @@ -1748,6 +1748,9 @@ sealed class ChatInfo: SomeChat, NamedChat { is Group -> groupInfo else -> null } + + val isChannel: Boolean + get() = groupInfo_?.useRelays == true } @Serializable @@ -2891,12 +2894,14 @@ data class ChatItem ( val id: Long get() = meta.itemId val timestampText: String get() = meta.timestampText - val text: String get() { + val text: String get() = text(isChannel = false) + + fun text(isChannel: Boolean): String { val mc = content.msgContent return when { - content.text == "" && file != null && mc is MsgContent.MCVoice -> String.format(generalGetString(MR.strings.voice_message_with_duration), durationText(mc.duration)) - content.text == "" && file != null -> file.fileName - else -> content.text + content.text(isChannel) == "" && file != null && mc is MsgContent.MCVoice -> String.format(generalGetString(MR.strings.voice_message_with_duration), durationText(mc.duration)) + content.text(isChannel) == "" && file != null -> file.fileName + else -> content.text(isChannel) } } @@ -3754,7 +3759,9 @@ sealed class CIContent: ItemContent { @Serializable @SerialName("chatBanner") object ChatBanner: CIContent() { override val msgContent: MsgContent? get() = null } @Serializable @SerialName("invalidJSON") data class InvalidJSON(val json: String): CIContent() { override val msgContent: MsgContent? get() = null } - override val text: String get() = when (this) { + override val text: String get() = text(isChannel = false) + + fun text(isChannel: Boolean): String = when (this) { is SndMsgContent -> msgContent.text is RcvMsgContent -> msgContent.text is SndDeleted -> generalGetString(MR.strings.deleted_description) @@ -3766,8 +3773,8 @@ sealed class CIContent: ItemContent { is RcvGroupInvitation -> groupInvitation.text is SndGroupInvitation -> groupInvitation.text is RcvDirectEventContent -> rcvDirectEvent.text - is RcvGroupEventContent -> rcvGroupEvent.text - is SndGroupEventContent -> sndGroupEvent.text + is RcvGroupEventContent -> rcvGroupEvent.text(isChannel) + is SndGroupEventContent -> sndGroupEvent.text(isChannel) is RcvConnEventContent -> rcvConnEvent.text is SndConnEventContent -> sndConnEvent.text is RcvChatFeature -> featureText(feature, enabled.text, param) @@ -4764,7 +4771,9 @@ sealed class RcvGroupEvent() { @Serializable @SerialName("memberProfileUpdated") class MemberProfileUpdated(val fromProfile: Profile, val toProfile: Profile): RcvGroupEvent() @Serializable @SerialName("newMemberPendingReview") class NewMemberPendingReview(): RcvGroupEvent() - val text: String get() = when (this) { + val text: String get() = text(isChannel = false) + + fun text(isChannel: Boolean): String = when (this) { is MemberAdded -> String.format(generalGetString(MR.strings.rcv_group_event_member_added), profile.profileViewName) is MemberConnected -> generalGetString(MR.strings.rcv_group_event_member_connected) is MemberAccepted -> String.format(generalGetString(MR.strings.rcv_group_event_member_accepted), profile.profileViewName) @@ -4779,8 +4788,8 @@ sealed class RcvGroupEvent() { is UserRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_your_role), role.text) is MemberDeleted -> String.format(generalGetString(MR.strings.rcv_group_event_member_deleted), profile.profileViewName) is UserDeleted -> generalGetString(MR.strings.rcv_group_event_user_deleted) - is GroupDeleted -> generalGetString(MR.strings.rcv_group_event_group_deleted) - is GroupUpdated -> generalGetString(MR.strings.rcv_group_event_updated_group_profile) + is GroupDeleted -> generalGetString(if (isChannel) MR.strings.rcv_channel_event_channel_deleted else MR.strings.rcv_group_event_group_deleted) + is GroupUpdated -> generalGetString(if (isChannel) MR.strings.rcv_channel_event_updated_channel_profile else MR.strings.rcv_group_event_updated_group_profile) is InvitedViaGroupLink -> generalGetString(MR.strings.rcv_group_event_invited_via_your_group_link) is MemberCreatedContact -> generalGetString(MR.strings.rcv_group_event_member_created_contact) is MemberProfileUpdated -> profileUpdatedText(fromProfile, toProfile) @@ -4812,7 +4821,9 @@ sealed class SndGroupEvent() { @Serializable @SerialName("memberAccepted") class MemberAccepted(val groupMemberId: Long, val profile: Profile): SndGroupEvent() @Serializable @SerialName("userPendingReview") class UserPendingReview(): SndGroupEvent() - val text: String get() = when (this) { + val text: String get() = text(isChannel = false) + + fun text(isChannel: Boolean): String = when (this) { is MemberRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_member_role), profile.profileViewName, role.text) is UserRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_role_for_yourself), role.text) is MemberBlocked -> if (blocked) { @@ -4822,7 +4833,7 @@ sealed class SndGroupEvent() { } is MemberDeleted -> String.format(generalGetString(MR.strings.snd_group_event_member_deleted), profile.profileViewName) is UserLeft -> generalGetString(MR.strings.snd_group_event_user_left) - is GroupUpdated -> generalGetString(MR.strings.snd_group_event_group_profile_updated) + is GroupUpdated -> generalGetString(if (isChannel) MR.strings.snd_channel_event_channel_profile_updated else MR.strings.snd_group_event_group_profile_updated) is MemberAccepted -> generalGetString(MR.strings.snd_group_event_member_accepted) is UserPendingReview -> generalGetString(MR.strings.snd_group_event_user_pending_review) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/NtfManager.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/NtfManager.kt index 39fcea3981..385120f18b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/NtfManager.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/NtfManager.kt @@ -44,7 +44,7 @@ abstract class NtfManager { chatModel.chatId.value != cInfo.id || chatModel.remoteHostId() != rhId) ) { - displayNotification(user = user, chatId = cInfo.id, displayName = cInfo.displayName, msgText = hideSecrets(cItem)) + displayNotification(user = user, chatId = cInfo.id, displayName = cInfo.displayName, msgText = hideSecrets(cItem, cInfo.isChannel)) } } @@ -119,7 +119,7 @@ abstract class NtfManager { } } - private fun hideSecrets(cItem: ChatItem): String { + private fun hideSecrets(cItem: ChatItem, isChannel: Boolean = false): String { val md = cItem.formattedText return if (md != null) { var res = "" @@ -130,9 +130,9 @@ abstract class NtfManager { } else { val mc = cItem.content.msgContent if (mc is MsgContent.MCReport) { - generalGetString(MR.strings.notification_group_report).format(cItem.text.ifEmpty { mc.reason.text }) + generalGetString(MR.strings.notification_group_report).format(cItem.text(isChannel).ifEmpty { mc.reason.text }) } else { - cItem.text + cItem.text(isChannel) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt index 05c84db4c3..d2d0a91c9b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt @@ -48,8 +48,8 @@ private val msgTailMaxHeightDp = msgTailWidthDp * 1.732f // 60deg val chatEventStyle = SpanStyle(fontSize = 12.sp, fontWeight = FontWeight.Light, color = CurrentColors.value.colors.secondary) -fun chatEventText(ci: ChatItem): AnnotatedString = - chatEventText(ci.content.text, ci.timestampText) +fun chatEventText(ci: ChatItem, isChannel: Boolean = false): AnnotatedString = + chatEventText(ci.content.text(isChannel), ci.timestampText) fun chatEventText(eventText: String, ts: String): AnnotatedString = buildAnnotatedString { @@ -612,7 +612,7 @@ fun ChatItemView( return if (count <= 1) { null } else if (ns.isEmpty()) { - generalGetString(MR.strings.rcv_group_events_count).format(count) + generalGetString(if (cInfo.isChannel) MR.strings.rcv_channel_events_count else MR.strings.rcv_group_events_count).format(count) } else if (count > ns.size) { members + " " + generalGetString(MR.strings.rcv_group_and_other_events).format(count - ns.size) } else { @@ -629,9 +629,9 @@ fun ChatItemView( buildAnnotatedString { withStyle(chatEventStyle) { append(memberDisplayName) } append(" ") - }.plus(chatEventText(cItem)) + }.plus(chatEventText(cItem, cInfo.isChannel)) } else { - chatEventText(cItem) + chatEventText(cItem, cInfo.isChannel) } } @@ -643,7 +643,7 @@ fun ChatItemView( @Composable fun PendingReviewEventItemView() { Text( buildAnnotatedString { - withStyle(chatEventStyle.copy(fontWeight = FontWeight.Bold)) { append(cItem.content.text) } + withStyle(chatEventStyle.copy(fontWeight = FontWeight.Bold)) { append(cItem.content.text(cInfo.isChannel)) } }, Modifier.padding(horizontal = 6.dp, vertical = 6.dp) ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt index 9248ac6efe..f5e0389043 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt @@ -241,7 +241,7 @@ fun ChatPreviewView( Text(previewText.first, color = previewText.second) } else if (ci != null && showChatPreviews) { val (text: CharSequence, inlineTextContent) = when { - ci.meta.itemDeleted == null -> ci.text to null + ci.meta.itemDeleted == null -> ci.text(chat.chatInfo.isChannel) to null else -> markedDeletedText(ci, chat.chatInfo) to null } val formattedText = when { 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 f2872f3f0a..609b6c4b3e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1707,7 +1707,9 @@ removed %1$s removed you deleted group + deleted channel updated group profile + updated channel profile invited via your group link requested connection New member wants to join the group. @@ -1718,6 +1720,7 @@ you removed %1$s you left group profile updated + channel profile updated you accepted this member Please wait for group moderators to review your request to join the group. @@ -1726,6 +1729,7 @@ %s, %s and %s connected %s, %s and %d other members connected %d group events + %d channel events and %d other events %s and %s %s, %s and %d members