@@ -7,15 +7,18 @@ import Foundation
77import StreamChat
88
99/// View model for the `ChatThreadListView`.
10- open class ChatThreadListViewModel : ObservableObject , ChatThreadListControllerDelegate {
10+ open class ChatThreadListViewModel : ObservableObject , ChatThreadListControllerDelegate , EventsControllerDelegate {
1111
1212 /// Context provided dependencies.
1313 @Injected ( \. chatClient) private var chatClient : ChatClient
1414 @Injected ( \. images) private var images : Images
1515 @Injected ( \. utils) private var utils : Utils
1616
1717 /// The controller that manages the thread list data.
18- private var controller : ChatThreadListController ?
18+ private var threadListController : ChatThreadListController !
19+
20+ /// The controller that manages thread list events.
21+ private var eventsController : EventsController !
1922
2023 /// A boolean value indicating if the initial threads have been loaded.
2124 public private( set) var hasLoadedThreads = false
@@ -26,6 +29,9 @@ open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDe
2629 /// A boolean indicating if it is loading data from the server and no local cache is available.
2730 @Published public var isLoading = false
2831
32+ /// A boolean indicating if it is reloading data from the server.
33+ @Published public var isReloading = false
34+
2935 /// A boolean indicating that there is no data from server.
3036 @Published public var isEmpty = false
3137
@@ -41,18 +47,40 @@ open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDe
4147 /// A boolean value indicating if all the older threads are loaded.
4248 @Published public var hasLoadedAllThreads : Bool = false
4349
50+ /// The number of new threads available to be fetched.
51+ @Published public var newThreadsCount : Int = 0
52+
53+ /// A boolean value indicating if there are new threads available to be fetched.
54+ @Published public var hasNewThreads : Bool = false
55+
56+ /// The ids of the new threads available to be fetched.
57+ private var newAvailableThreadIds : Set < MessageId > = [ ] {
58+ didSet {
59+ newThreadsCount = newAvailableThreadIds. count
60+ hasNewThreads = newThreadsCount > 0
61+ }
62+ }
63+
4464 /// Creates a view model for the `ChatThreadListView`.
4565 ///
4666 /// - Parameters:
4767 /// - threadListController: A controller providing the list of threads. If nil, a controller with default `ThreadListQuery` is created.
68+ /// - eventsController: The controller that manages thread list events. If nil, the default events controller will be provided.
4869 public init (
49- threadListController: ChatThreadListController ? = nil
70+ threadListController: ChatThreadListController ? = nil ,
71+ eventsController: EventsController ? = nil
5072 ) {
5173 if let threadListController = threadListController {
52- self . controller = threadListController
74+ self . threadListController = threadListController
5375 } else {
5476 makeDefaultThreadListController ( )
5577 }
78+
79+ if let eventsController = eventsController {
80+ self . eventsController = eventsController
81+ } else {
82+ makeDefaultEventsController ( )
83+ }
5684 }
5785
5886 public func retryLoadThreads( ) {
@@ -64,16 +92,32 @@ open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDe
6492 loadMoreThreads ( )
6593 }
6694
95+ public func viewDidAppear( ) {
96+ if !hasLoadedThreads {
97+ startObserving ( )
98+ loadThreads ( )
99+ }
100+ }
101+
102+ public func startObserving( ) {
103+ threadListController. delegate = self
104+ eventsController? . delegate = self
105+ }
106+
67107 public func loadThreads( ) {
68- controller? . delegate = self
69- isLoading = controller? . threads. isEmpty == true
108+ isLoading = threadListController. threads. isEmpty == true
70109 failedToLoadThreads = false
71- controller? . synchronize { [ weak self] error in
110+ isReloading = !isEmpty
111+ threadListController. synchronize { [ weak self] error in
72112 self ? . isLoading = false
113+ self ? . isReloading = false
73114 self ? . hasLoadedThreads = error == nil
74115 self ? . failedToLoadThreads = error != nil
75- self ? . isEmpty = self ? . controller? . threads. isEmpty == true
76- self ? . hasLoadedAllThreads = self ? . controller? . hasLoadedAllThreads ?? false
116+ self ? . isEmpty = self ? . threadListController. threads. isEmpty == true
117+ self ? . hasLoadedAllThreads = self ? . threadListController. hasLoadedAllThreads ?? false
118+ if error == nil {
119+ self ? . newAvailableThreadIds = [ ]
120+ }
77121 }
78122 }
79123
@@ -86,14 +130,14 @@ open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDe
86130 }
87131
88132 public func loadMoreThreads( ) {
89- if isLoadingMoreThreads || controller ? . hasLoadedAllThreads == true {
133+ if isLoadingMoreThreads || threadListController . hasLoadedAllThreads == true {
90134 return
91135 }
92136
93137 isLoadingMoreThreads = true
94- controller ? . loadMoreThreads { [ weak self] result in
138+ threadListController . loadMoreThreads { [ weak self] result in
95139 self ? . isLoadingMoreThreads = false
96- self ? . hasLoadedAllThreads = self ? . controller ? . hasLoadedAllThreads ?? false
140+ self ? . hasLoadedAllThreads = self ? . threadListController . hasLoadedAllThreads ?? false
97141 let threads = try ? result. get ( )
98142 self ? . failedToLoadMoreThreads = threads == nil
99143 }
@@ -106,13 +150,26 @@ open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDe
106150 threads = controller. threads
107151 }
108152
109- private func makeDefaultThreadListController( ) {
110- guard let currentUserId = chatClient. currentUserId else {
111- // TODO: observeClientIdChange()
112- return
153+ public func eventsController( _ controller: EventsController , didReceiveEvent event: any Event ) {
154+ switch event {
155+ case let event as ThreadMessageNewEvent :
156+ guard let parentId = event. message. parentMessageId else { break }
157+ let isNewThread = threadListController. dataStore. thread ( parentMessageId: parentId) == nil
158+ if isNewThread {
159+ newAvailableThreadIds. insert ( parentId)
160+ }
161+ default :
162+ break
113163 }
114- controller = chatClient. threadListController (
164+ }
165+
166+ private func makeDefaultThreadListController( ) {
167+ threadListController = chatClient. threadListController (
115168 query: . init( watch: true )
116169 )
117170 }
171+
172+ private func makeDefaultEventsController( ) {
173+ eventsController = chatClient. eventsController ( )
174+ }
118175}
0 commit comments