diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift index 46e8044d..a65ebf07 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift @@ -209,7 +209,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { private func applicationWillEnterForeground() { guard let first = messages.first else { return } if canMarkRead { - maybeSendReadEvent(for: first) + sendReadEventIfNeeded(for: first) } } @@ -224,7 +224,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { } public func jumpToMessage(messageId: String) -> Bool { - if messageId == "unknown" { + if messageId == .unknownMessageId { if firstUnreadMessageId == nil, let lastReadMessageId { channelDataSource.loadPageAroundMessageId(lastReadMessageId) { [weak self] error in if error != nil { @@ -313,7 +313,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { if index == 0 { let isActive = UIApplication.shared.applicationState == .active if isActive && canMarkRead { - maybeSendReadEvent(for: message) + sendReadEventIfNeeded(for: message) } } } @@ -390,14 +390,14 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { } } - maybeRefreshMessageList() + refreshMessageListIfNeeded() if !showScrollToLatestButton && scrolledId == nil && !loadingNextMessages { updateScrolledIdToNewestMessage() } if lastMessageRead != nil && firstUnreadMessageId == nil { - self.firstUnreadMessageId = channelDataSource.firstUnreadMessageId + firstUnreadMessageId = channelDataSource.firstUnreadMessageId } } @@ -497,7 +497,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { ) } - private func maybeSendReadEvent(for message: ChatMessage) { + private func sendReadEventIfNeeded(for message: ChatMessage) { if message.id != lastMessageRead { lastMessageRead = message.id throttler.throttle { [weak self] in @@ -509,7 +509,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { } } - private func maybeRefreshMessageList() { + private func refreshMessageListIfNeeded() { let count = messages.count if count > lastRefreshThreshold { lastRefreshThreshold = lastRefreshThreshold + refreshThreshold diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/JumpToUnreadButton.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/JumpToUnreadButton.swift index c3a070c8..294a03a6 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/JumpToUnreadButton.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/JumpToUnreadButton.swift @@ -10,8 +10,8 @@ struct JumpToUnreadButton: View { @Injected(\.colors) var colors var unreadCount: Int - var onTap: () -> () - var onClose: () -> () + var onTap: () -> Void + var onClose: () -> Void var body: some View { HStack { diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift index 846ca2a1..3d8daa83 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift @@ -131,7 +131,9 @@ public struct MessageListView: View, KeyboardReadable { ForEach(messages, id: \.messageId) { message in var index: Int? = messageListDateUtils.indexForMessageDate(message: message, in: messages) let messageDate: Date? = messageListDateUtils.showMessageDate(for: index, in: messages) - let showUnreadSeparator = messageListConfig.showNewMessagesSeparator && (message.messageId == firstUnreadMessageId || message.id == firstUnreadMessageId) + let messageIsFirstUnread = message.messageId == firstUnreadMessageId || + message.id == firstUnreadMessageId + let showUnreadSeparator = messageListConfig.showNewMessagesSeparator && messageIsFirstUnread let showsLastInGroupInfo = showsLastInGroupInfo(for: message, channel: channel) factory.makeMessageContainerView( channel: channel, @@ -289,16 +291,16 @@ public struct MessageListView: View, KeyboardReadable { } }) .overlay( - (channel.unreadCount.messages > 0 && !unreadMessagesBannerShown) ? - factory.makeJumpToUnreadButton( - channel: channel, - onJumpToMessage: { - _ = onJumpToMessage?(firstUnreadMessageId ?? "unknown") - }, - onClose: { - firstUnreadMessageId = nil - } - ) : nil + (channel.unreadCount.messages > 0 && !unreadMessagesBannerShown) ? + factory.makeJumpToUnreadButton( + channel: channel, + onJumpToMessage: { + _ = onJumpToMessage?(firstUnreadMessageId ?? .unknownMessageId) + }, + onClose: { + firstUnreadMessageId = nil + } + ) : nil ) .modifier(factory.makeMessageListContainerModifier()) .modifier(HideKeyboardOnTapGesture(shouldAdd: keyboardShown)) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/DefaultMessageActions.swift b/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/DefaultMessageActions.swift index f3617e35..277265c7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/DefaultMessageActions.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/DefaultMessageActions.swift @@ -456,22 +456,21 @@ extension MessageAction { let channelController = chatClient.channelController(for: channel.cid) let action = { channelController.markUnread(from: message.id) { result in - switch result { - case .success(_): + if case let .failure(error) = result { + onError(error) + } else { onFinish( MessageActionInfo( message: message, - identifier: "markUnread" + identifier: MessageActionId.markUnread ) ) - case .failure(let error): - onError(error) } } } let unreadAction = MessageAction( - id: "markUnread", - title: "Mark Unread", + id: MessageActionId.markUnread, + title: L10n.Message.Actions.markUnread, iconName: "message.badge", action: action, confirmationPopup: nil, @@ -665,4 +664,5 @@ public enum MessageActionId { public static let pin = "pin_message_action" public static let unpin = "unpin_message_action" public static let resend = "resend_message_action" + public static let markUnread = "mark_unread_action" } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/MessageActionsResolver.swift b/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/MessageActionsResolver.swift index b8b08352..2bc1aba3 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/MessageActionsResolver.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Reactions/MessageActions/MessageActionsResolver.swift @@ -39,7 +39,7 @@ public class MessageActionsResolver: MessageActionsResolving { viewModel.editedMessage = info.message viewModel.quotedMessage = nil } - } else if info.identifier == "markUnread" { + } else if info.identifier == MessageActionId.markUnread { viewModel.firstUnreadMessageId = info.message.messageId } diff --git a/Sources/StreamChatSwiftUI/DefaultViewFactory.swift b/Sources/StreamChatSwiftUI/DefaultViewFactory.swift index a9cbebdd..c250e9d6 100644 --- a/Sources/StreamChatSwiftUI/DefaultViewFactory.swift +++ b/Sources/StreamChatSwiftUI/DefaultViewFactory.swift @@ -879,8 +879,8 @@ extension ViewFactory { public func makeJumpToUnreadButton( channel: ChatChannel, - onJumpToMessage: @escaping () -> (), - onClose: @escaping () -> () + onJumpToMessage: @escaping () -> Void, + onClose: @escaping () -> Void ) -> some View { VStack { JumpToUnreadButton( diff --git a/Sources/StreamChatSwiftUI/Generated/L10n.swift b/Sources/StreamChatSwiftUI/Generated/L10n.swift index 5d57494d..c9a8a28b 100644 --- a/Sources/StreamChatSwiftUI/Generated/L10n.swift +++ b/Sources/StreamChatSwiftUI/Generated/L10n.swift @@ -271,6 +271,8 @@ internal enum L10n { internal static var flag: String { L10n.tr("Localizable", "message.actions.flag") } /// Reply internal static var inlineReply: String { L10n.tr("Localizable", "message.actions.inline-reply") } + /// Mark Unread + internal static var markUnread: String { L10n.tr("Localizable", "message.actions.mark-unread") } /// Pin to conversation internal static var pin: String { L10n.tr("Localizable", "message.actions.pin") } /// Resend diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings index 82d67739..c88cfa15 100644 --- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings +++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings @@ -33,6 +33,7 @@ "message.actions.user-mute" = "Mute User"; "message.actions.resend" = "Resend"; "message.actions.flag" = "Flag Message"; +"message.actions.mark-unread" = "Mark Unread"; "message.actions.flag.confirmation-title" = "Flag Message"; "message.actions.flag.confirmation-message" = "Do you want to send a copy of this message to a moderator for further investigation?"; diff --git a/Sources/StreamChatSwiftUI/Utils/StringExtensions.swift b/Sources/StreamChatSwiftUI/Utils/StringExtensions.swift index e18d80b3..f8cfc17b 100644 --- a/Sources/StreamChatSwiftUI/Utils/StringExtensions.swift +++ b/Sources/StreamChatSwiftUI/Utils/StringExtensions.swift @@ -109,4 +109,6 @@ extension String { return false } + + static let unknownMessageId = "unknown" } diff --git a/Sources/StreamChatSwiftUI/ViewFactory.swift b/Sources/StreamChatSwiftUI/ViewFactory.swift index a2b57c7b..9b82308c 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory.swift @@ -880,7 +880,7 @@ public protocol ViewFactory: AnyObject { /// - Returns: view shown in the jump to unread slot. func makeJumpToUnreadButton( channel: ChatChannel, - onJumpToMessage: @escaping () -> (), - onClose: @escaping () -> () + onJumpToMessage: @escaping () -> Void, + onClose: @escaping () -> Void ) -> JumpToUnreadButtonType }