From be414f3c144593279e1e9f76a9ed69c7dab9709c Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Thu, 29 Aug 2024 10:20:58 +0200 Subject: [PATCH] Change of UIList coordinator to a singleton --- .../Fragments/ConversationFragment.swift | 7 +- .../Main/Conversations/Fragments/UIList.swift | 142 ++++++++++-------- .../ViewModel/ConversationViewModel.swift | 5 +- 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift index 9cd784708..529fce11e 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift @@ -38,9 +38,6 @@ struct ConversationFragment: View { private let ids: [String] = [] - @State private var isScrolledToBottom: Bool = true - var showMessageMenuOnLongPress: Bool = true - @StateObject private var viewModel = ChatViewModel() @StateObject private var paginationState = PaginationState() @@ -171,13 +168,11 @@ struct ConversationFragment: View { paginationState: paginationState, conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, - isScrolledToBottom: $isScrolledToBottom, - showMessageMenuOnLongPress: showMessageMenuOnLongPress, geometryProxy: geometry, sections: conversationViewModel.conversationMessagesSection ) - if !isScrolledToBottom { + if !conversationViewModel.isScrolledToBottom { Button { NotificationCenter.default.post(name: .onScrollToBottom, object: nil) } label: { diff --git a/Linphone/UI/Main/Conversations/Fragments/UIList.swift b/Linphone/UI/Main/Conversations/Fragments/UIList.swift index ee8d2f376..e0b94ad70 100644 --- a/Linphone/UI/Main/Conversations/Fragments/UIList.swift +++ b/Linphone/UI/Main/Conversations/Fragments/UIList.swift @@ -28,18 +28,18 @@ public extension Notification.Name { struct UIList: UIViewRepresentable { + private static var sharedCoordinator: Coordinator? + @ObservedObject var viewModel: ChatViewModel @ObservedObject var paginationState: PaginationState @ObservedObject var conversationViewModel: ConversationViewModel @ObservedObject var conversationsListViewModel: ConversationsListViewModel - @Binding var isScrolledToBottom: Bool - - let showMessageMenuOnLongPress: Bool let geometryProxy: GeometryProxy let sections: [MessagesSection] @State private var isScrolledToTop = false + @State private var isScrolledToBottom = true func makeUIView(context: Context) -> UITableView { let tableView = UITableView(frame: .zero, style: .grouped) @@ -57,42 +57,11 @@ struct UIList: UIViewRepresentable { tableView.backgroundColor = UIColor(.white) tableView.scrollsToTop = true - NotificationCenter.default.addObserver(forName: .onScrollToBottom, object: nil, queue: nil) { _ in - DispatchQueue.main.async { - if !context.coordinator.sections.isEmpty { - if context.coordinator.sections.first != nil - && conversationViewModel.conversationMessagesSection.first != nil - && conversationViewModel.displayedConversation != nil - && context.coordinator.sections.first!.chatRoomID == conversationViewModel.displayedConversation!.id - && context.coordinator.sections.first!.rows.count == conversationViewModel.conversationMessagesSection.first!.rows.count { - tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true) - } else { - NotificationCenter.default.removeObserver(self, name: .onScrollToBottom, object: nil) - } - } - } - } + context.coordinator.tableView = tableView + context.coordinator.geometryProxy = geometryProxy - NotificationCenter.default.addObserver(forName: .onScrollToIndex, object: nil, queue: nil) { notification in - DispatchQueue.main.async { - if !context.coordinator.sections.isEmpty { - if context.coordinator.sections.first != nil - && conversationViewModel.conversationMessagesSection.first != nil - && conversationViewModel.displayedConversation != nil - && context.coordinator.sections.first!.chatRoomID == conversationViewModel.displayedConversation!.id - && context.coordinator.sections.first!.rows.count == conversationViewModel.conversationMessagesSection.first!.rows.count { - if let dict = notification.userInfo as NSDictionary? { - if let index = dict["index"] as? Int { - if let animated = dict["animated"] as? Bool { - tableView.scrollToRow(at: IndexPath(row: index, section: 0), at: .bottom, animated: animated) - } - } - } - } else { - NotificationCenter.default.removeObserver(self, name: .onScrollToIndex, object: nil) - } - } - } + DispatchQueue.main.async { + conversationViewModel.isScrolledToBottom = true } return tableView @@ -140,7 +109,7 @@ struct UIList: UIViewRepresentable { tableView.endUpdates() } - if isScrolledToBottom { + if conversationViewModel.isScrolledToBottom && conversationViewModel.displayedConversationUnreadMessagesCount > 0 { conversationViewModel.markAsRead() conversationsListViewModel.computeChatRoomsList(filter: "") } @@ -268,43 +237,85 @@ struct UIList: UIViewRepresentable { // MARK: - Coordinator func makeCoordinator() -> Coordinator { - Coordinator( - conversationViewModel: conversationViewModel, - conversationsListViewModel: conversationsListViewModel, - viewModel: viewModel, - paginationState: paginationState, - isScrolledToBottom: $isScrolledToBottom, - isScrolledToTop: $isScrolledToTop, - showMessageMenuOnLongPress: showMessageMenuOnLongPress, - geometryProxy: geometryProxy, - sections: sections - ) + if UIList.sharedCoordinator == nil { + UIList.sharedCoordinator = Coordinator( + conversationViewModel: conversationViewModel, + conversationsListViewModel: conversationsListViewModel, + viewModel: viewModel, + paginationState: paginationState, + isScrolledToTop: $isScrolledToTop, + isScrolledToBottom: $isScrolledToBottom, + geometryProxy: geometryProxy, + sections: sections + ) + } + return UIList.sharedCoordinator! } class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate { + var tableView: UITableView? + @ObservedObject var viewModel: ChatViewModel @ObservedObject var paginationState: PaginationState @ObservedObject var conversationViewModel: ConversationViewModel @ObservedObject var conversationsListViewModel: ConversationsListViewModel - @Binding var isScrolledToBottom: Bool @Binding var isScrolledToTop: Bool + @Binding var isScrolledToBottom: Bool - let showMessageMenuOnLongPress: Bool - let geometryProxy: GeometryProxy + var geometryProxy: GeometryProxy var sections: [MessagesSection] - init(conversationViewModel: ConversationViewModel, conversationsListViewModel: ConversationsListViewModel, viewModel: ChatViewModel, paginationState: PaginationState, isScrolledToBottom: Binding, isScrolledToTop: Binding, showMessageMenuOnLongPress: Bool, geometryProxy: GeometryProxy, sections: [MessagesSection]) { + init(conversationViewModel: ConversationViewModel, conversationsListViewModel: ConversationsListViewModel, viewModel: ChatViewModel, paginationState: PaginationState, isScrolledToTop: Binding, isScrolledToBottom: Binding, geometryProxy: GeometryProxy, sections: [MessagesSection]) { self.conversationViewModel = conversationViewModel self.conversationsListViewModel = conversationsListViewModel self.viewModel = viewModel self.paginationState = paginationState - self._isScrolledToBottom = isScrolledToBottom self._isScrolledToTop = isScrolledToTop - self.showMessageMenuOnLongPress = showMessageMenuOnLongPress + self._isScrolledToBottom = isScrolledToBottom self.geometryProxy = geometryProxy self.sections = sections + + super.init() + + NotificationCenter.default.addObserver(forName: .onScrollToBottom, object: nil, queue: nil) { _ in + DispatchQueue.main.async { + if !self.sections.isEmpty { + if self.sections.first != nil + && self.conversationViewModel.conversationMessagesSection.first != nil + && self.conversationViewModel.displayedConversation != nil + && self.sections.first!.chatRoomID == self.conversationViewModel.displayedConversation!.id + && self.sections.first!.rows.count == self.conversationViewModel.conversationMessagesSection.first!.rows.count { + self.tableView!.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true) + } + } + } + } + + NotificationCenter.default.addObserver(forName: .onScrollToIndex, object: nil, queue: nil) { notification in + DispatchQueue.main.async { + if !self.sections.isEmpty { + if self.sections.first != nil + && self.conversationViewModel.conversationMessagesSection.first != nil + && self.conversationViewModel.displayedConversation != nil + && self.sections.first!.chatRoomID == self.conversationViewModel.displayedConversation!.id + && self.sections.first!.rows.count == self.conversationViewModel.conversationMessagesSection.first!.rows.count { + if let dict = notification.userInfo as NSDictionary? { + if let index = dict["index"] as? Int { + if let animated = dict["animated"] as? Bool { + self.tableView!.scrollToRow(at: IndexPath(row: index, section: 0), at: .bottom, animated: animated) + } + } + } + } + } + } + } + } + + deinit { + NotificationCenter.default.removeObserver(self) } func numberOfSections(in tableView: UITableView) -> Int { @@ -361,19 +372,22 @@ struct UIList: UIViewRepresentable { } func scrollViewDidScroll(_ scrollView: UIScrollView) { - isScrolledToBottom = scrollView.contentOffset.y <= 10 - if isScrolledToBottom && conversationViewModel.displayedConversationUnreadMessagesCount > 0 { - conversationViewModel.markAsRead() - conversationsListViewModel.computeChatRoomsList(filter: "") + self.isScrolledToBottom = scrollView.contentOffset.y <= 10 + + if self.isScrolledToBottom != self.conversationViewModel.isScrolledToBottom { + self.conversationViewModel.isScrolledToBottom = self.isScrolledToBottom } - if !isScrolledToTop && scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 200 { + if self.conversationViewModel.isScrolledToBottom && self.conversationViewModel.displayedConversationUnreadMessagesCount > 0 { + self.conversationViewModel.markAsRead() + self.conversationsListViewModel.computeChatRoomsList(filter: "") + } + + if !self.isScrolledToTop && scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 500 { self.conversationViewModel.getOldMessages() } - DispatchQueue.main.async { - self.isScrolledToTop = scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 200 - } + self.isScrolledToTop = scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 500 } func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { diff --git a/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift b/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift index cc9aba79d..f8202cb9e 100644 --- a/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift +++ b/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift @@ -48,6 +48,8 @@ class ConversationViewModel: ObservableObject { @Published var selectedMessage: EventLogMessage? @Published var messageToReply: EventLogMessage? + @Published var isScrolledToBottom: Bool = true + init() {} func addConversationDelegate() { @@ -417,7 +419,8 @@ class ConversationViewModel: ObservableObject { func getOldMessages() { coreContext.doOnCoreQueue { _ in - if self.displayedConversation != nil && self.displayedConversationHistorySize > self.conversationMessagesSection[0].rows.count && !self.oldMessageReceived { + if self.displayedConversation != nil && !self.conversationMessagesSection.isEmpty + && self.displayedConversationHistorySize > self.conversationMessagesSection[0].rows.count && !self.oldMessageReceived { self.oldMessageReceived = true let historyEvents = self.displayedConversation!.chatRoom.getHistoryRangeEvents(begin: self.conversationMessagesSection[0].rows.count, end: self.conversationMessagesSection[0].rows.count + 30) var conversationMessagesTmp: [EventLogMessage] = []