@@ -18,8 +18,6 @@ final class HomeViewModel: Store {
1818 var showSearchView : Bool = false
1919 var webPageURLInput : String = " https:// "
2020 var selectedTodoKind : TodoKind ?
21- var searchText : String = " "
22- var isSearching : Bool = false
2321 var reorderTodo : Bool = false
2422 var isRecentTodosLoading : Bool = false
2523 var isWebPageLoading : Bool = false
@@ -34,28 +32,21 @@ final class HomeViewModel: Store {
3432 }
3533
3634 enum Action {
35+ case onAppear
36+ case setPresentation( Presentation , Bool )
37+ case setAlert( isPresented: Bool , type: AlertType ? = nil )
38+ case setToast( isPresented: Bool , type: ToastType ? = nil )
39+ case setLoading( LoadingTarget , Bool )
3740 case tapTodoKind( TodoKind )
3841 case orderTodoKindPreferences( [ TodoKindPreference ] )
39- case setReorderTodo( Bool )
40- case setShowTodoEditor( Bool )
41- case setShowContentPicker( Bool )
42- case setShowSearchView( Bool )
43- case setAlert( isPresented: Bool , type: AlertType ? = nil )
44- case onAppear
45- case updateWebPageURLInput( String )
46- case updateSearching( Bool )
47- case updateSearchText( String )
4842 case addTodo( Todo )
43+ case updateRecentTodos( [ RecentTodoItem ] )
44+ case updateWebPageURLInput( String )
4945 case addWebPage
5046 case deleteWebPage( WebPageItem )
5147 case undoDeleteWebPage
52- case setToast( isPresented: Bool , type: ToastType ? = nil )
53- case fetchRecentTodos( [ RecentTodoItem ] )
54- case fetchWebPages( [ WebPageItem ] )
48+ case updateWebPages( [ WebPageItem ] )
5549 case restoreWebPage( WebPageItem , Int )
56- case setRecentTodosLoading( Bool )
57- case setWebPageLoading( Bool )
58- case setAppending( Bool )
5950 }
6051
6152 enum SideEffect {
@@ -83,6 +74,19 @@ final class HomeViewModel: Store {
8374 case urlInputAlert
8475 }
8576
77+ enum Presentation {
78+ case reorderTodo
79+ case todoEditor
80+ case contentPicker
81+ case searchView
82+ }
83+
84+ enum LoadingTarget {
85+ case recentTodos
86+ case webPage
87+ case overlay
88+ }
89+
8690 private( set) var state = State ( )
8791 private let upsertTodoUseCase : UpsertTodoUseCase
8892 private let addWebPageUseCase : AddWebPageUseCase
@@ -113,17 +117,12 @@ final class HomeViewModel: Store {
113117 var effects : [ SideEffect ] = [ ]
114118
115119 switch action {
116- case . tapTodoKind, . orderTodoKindPreferences, . setReorderTodo,
117- . setShowTodoEditor, . setShowContentPicker, . setShowSearchView,
118- . updateWebPageURLInput, . setAlert, . deleteWebPage,
119- . undoDeleteWebPage, . setToast:
120- effects = reduceByUser ( action, state: & state)
121-
122- case . onAppear, . updateSearching, . updateSearchText, . addTodo, . addWebPage:
120+ case . onAppear, . setPresentation, . setAlert, . setToast, . tapTodoKind,
121+ . orderTodoKindPreferences, . addTodo, . updateWebPageURLInput,
122+ . addWebPage, . deleteWebPage, . undoDeleteWebPage:
123123 effects = reduceByView ( action, state: & state)
124124
125- case . fetchRecentTodos, . fetchWebPages, . restoreWebPage, . setRecentTodosLoading,
126- . setWebPageLoading, . setAppending:
125+ case . setLoading, . updateRecentTodos, . updateWebPages, . restoreWebPage:
127126 effects = reduceByRun ( action, state: & state)
128127 }
129128
@@ -136,50 +135,51 @@ final class HomeViewModel: Store {
136135 case . addTodo( let todo) :
137136 Task {
138137 do {
139- send ( . setAppending( true ) )
138+ defer { send ( . setLoading( . overlay, false ) ) }
139+ send ( . setLoading( . overlay, true ) )
140140 try await upsertTodoUseCase. execute ( todo)
141141 let page = try await fetchRecentTodos ( )
142142 let items = page. items
143143 . filter { $0. createdAt != $0. updatedAt }
144144 . prefix ( 5 )
145145 . map { RecentTodoItem ( from: $0) }
146- send ( . fetchRecentTodos ( items) )
146+ send ( . updateRecentTodos ( items) )
147147 } catch {
148148 send ( . setAlert( isPresented: true , type: . error) )
149149 }
150150 }
151151 case . fetchRecentTodos:
152152 Task {
153153 do {
154- defer { send ( . setRecentTodosLoading ( false ) ) }
155- send ( . setRecentTodosLoading ( true ) )
154+ defer { send ( . setLoading ( . recentTodos , false ) ) }
155+ send ( . setLoading ( . recentTodos , true ) )
156156 let page = try await fetchRecentTodos ( )
157157 let items = page. items
158158 . filter { $0. createdAt != $0. updatedAt }
159159 . prefix ( 5 )
160160 . map { RecentTodoItem ( from: $0) }
161- send ( . fetchRecentTodos ( items) )
161+ send ( . updateRecentTodos ( items) )
162162 } catch {
163163 send ( . setAlert( isPresented: true , type: . error) )
164164 }
165165 }
166166 case . addWebPage( let urlString) :
167167 Task {
168168 do {
169- defer { send ( . setAppending ( false ) ) }
170- send ( . setAppending ( true ) )
169+ defer { send ( . setLoading ( . overlay , false ) ) }
170+ send ( . setLoading ( . overlay , true ) )
171171 try await addWebPageUseCase. execute ( urlString)
172172 let pages = try await fetchWebPagesUseCase. execute ( " " )
173- send ( . fetchWebPages ( pages. map { WebPageItem ( from: $0) } ) )
173+ send ( . updateWebPages ( pages. map { WebPageItem ( from: $0) } ) )
174174 } catch {
175175 send ( . setAlert( isPresented: true , type: . error) )
176176 }
177177 }
178178 case . deleteWebPage( let page, let index) :
179179 Task {
180180 do {
181- defer { send ( . setWebPageLoading ( false ) ) }
182- send ( . setWebPageLoading ( true ) )
181+ defer { send ( . setLoading ( . webPage , false ) ) }
182+ send ( . setLoading ( . webPage , true ) )
183183 try await deleteWebPageUseCase. execute ( page. url. absoluteString)
184184 } catch {
185185 send ( . restoreWebPage( page, index) )
@@ -188,8 +188,8 @@ final class HomeViewModel: Store {
188188 }
189189 case . undoDeleteWebPage( let urlString) :
190190 Task {
191- defer { send ( . setWebPageLoading ( false ) ) }
192- send ( . setWebPageLoading ( true ) )
191+ defer { send ( . setLoading ( . webPage , false ) ) }
192+ send ( . setLoading ( . webPage , true ) )
193193
194194 var shouldPresentError = false
195195
@@ -201,7 +201,7 @@ final class HomeViewModel: Store {
201201
202202 do {
203203 let pages = try await fetchWebPagesUseCase. execute ( " " )
204- send ( . fetchWebPages ( pages. map { WebPageItem ( from: $0) } ) )
204+ send ( . updateWebPages ( pages. map { WebPageItem ( from: $0) } ) )
205205 } catch {
206206 shouldPresentError = true
207207 }
@@ -213,10 +213,10 @@ final class HomeViewModel: Store {
213213 case . fetchWebPages:
214214 Task {
215215 do {
216- defer { send ( . setWebPageLoading ( false ) ) }
217- send ( . setWebPageLoading ( true ) )
216+ defer { send ( . setLoading ( . webPage , false ) ) }
217+ send ( . setLoading ( . webPage , true ) )
218218 let pages = try await fetchWebPagesUseCase. execute ( " " )
219- send ( . fetchWebPages ( pages. map { WebPageItem ( from: $0) } ) )
219+ send ( . updateWebPages ( pages. map { WebPageItem ( from: $0) } ) )
220220 } catch {
221221 send ( . setAlert( isPresented: true , type: . error) )
222222 }
@@ -226,7 +226,7 @@ final class HomeViewModel: Store {
226226 try await Task . sleep ( for: . seconds( 0.1 ) )
227227 switch type {
228228 case . todoEditor:
229- send ( . setShowTodoEditor ( true ) )
229+ send ( . setPresentation ( . todoEditor , true ) )
230230 case . urlInputAlert:
231231 send ( . setAlert( isPresented: true , type: . webPageInput) )
232232 }
@@ -237,81 +237,66 @@ final class HomeViewModel: Store {
237237
238238// MARK: - Reduce Methods
239239private extension HomeViewModel {
240- func reduceByUser( _ action: Action , state: inout State ) -> [ SideEffect ] {
240+ // swiftlint:disable cyclomatic_complexity
241+ func reduceByView( _ action: Action , state: inout State ) -> [ SideEffect ] {
241242 switch action {
242- case . tapTodoKind( let kind) :
243- state. selectedTodoKind = kind
244- state. showContentPicker = false
245- return [ . showModalAfterDelay( . todoEditor) ]
246- case . orderTodoKindPreferences( let preferences) :
247- state. todoKindPreferences = preferences
248- case . setReorderTodo( let presented) :
249- state. reorderTodo = presented
250- case . setShowTodoEditor( let presented) :
251- state. showTodoEditor = presented
252- if !presented { state. selectedTodoKind = nil }
253- case . setShowContentPicker( let presented) :
254- state. showContentPicker = presented
255- case . setShowSearchView( let presented) :
256- state. showSearchView = presented
257- case . updateWebPageURLInput( let text) :
258- state. webPageURLInput = text
243+ case . onAppear:
244+ return [ . fetchRecentTodos, . fetchWebPages]
245+ case . setPresentation( let presentation, let isPresented) :
246+ setPresentation ( & state, presentation: presentation, isPresented: isPresented)
259247 case . setAlert( let presented, let type) :
260248 if presented && type == . webPageInput && state. showContentPicker {
261249 state. showContentPicker = false
262250 return [ . showModalAfterDelay( . urlInputAlert) ]
263251 }
264252 setAlert ( & state, isPresented: presented, type: type)
265- case . deleteWebPage( let page) :
266- if let index = state. webPages. firstIndex ( where: { $0. id == page. id } ) {
267- deletedWebPageURLString = page. url. absoluteString
268- state. webPages. remove ( at: index)
269- setToast ( & state, isPresented: true , for: . deleteWebPage)
270- return [ . deleteWebPage( page, index) ]
271- }
272- case . undoDeleteWebPage:
273- guard let deletedWebPageURLString else { return [ ] }
274- self . deletedWebPageURLString = nil
275- return [ . undoDeleteWebPage( deletedWebPageURLString) ]
276253 case . setToast( let isPresented, let type) :
277254 setToast ( & state, isPresented: isPresented, for: type)
278255 if !isPresented {
279256 deletedWebPageURLString = nil
280257 }
281- default :
282- break
283- }
284- return [ ]
285- }
286-
287- func reduceByView( _ action: Action , state: inout State ) -> [ SideEffect ] {
288- switch action {
289- case . onAppear:
290- return [ . fetchRecentTodos, . fetchWebPages]
291- case . updateSearching( let isSearching) :
292- state. isSearching = isSearching
293- case . updateSearchText( let text) :
294- state. searchText = text
258+ case . tapTodoKind( let kind) :
259+ state. selectedTodoKind = kind
260+ state. showContentPicker = false
261+ return [ . showModalAfterDelay( . todoEditor) ]
262+ case . orderTodoKindPreferences( let preferences) :
263+ state. todoKindPreferences = preferences
295264 case . addTodo( let todo) :
296265 return [ . addTodo( todo) ]
266+ case . updateWebPageURLInput( let text) :
267+ state. webPageURLInput = text
297268 case . addWebPage:
298269 guard let normalizedURL = normalizedWebPageURL ( state. webPageURLInput) else {
299270 setAlert ( & state, isPresented: true , type: . invalidURL)
300271 return [ ]
301272 }
302273 setAlert ( & state, isPresented: false , type: nil )
303274 return [ . addWebPage( normalizedURL) ]
275+ case . deleteWebPage( let page) :
276+ if let index = state. webPages. firstIndex ( where: { $0. id == page. id } ) {
277+ deletedWebPageURLString = page. url. absoluteString
278+ state. webPages. remove ( at: index)
279+ setToast ( & state, isPresented: true , for: . deleteWebPage)
280+ return [ . deleteWebPage( page, index) ]
281+ }
282+ case . undoDeleteWebPage:
283+ guard let deletedWebPageURLString else { return [ ] }
284+ self . deletedWebPageURLString = nil
285+ return [ . undoDeleteWebPage( deletedWebPageURLString) ]
304286 default :
305287 break
306288 }
307289 return [ ]
308290 }
291+ // swiftlint:enable cyclomatic_complexity
309292
310293 func reduceByRun( _ action: Action , state: inout State ) -> [ SideEffect ] {
311294 switch action {
312- case . fetchRecentTodos( let todos) :
295+ case . setLoading( let loadingTarget, let isLoading) :
296+ setLoading ( & state, loadingTarget: loadingTarget, isLoading: isLoading)
297+ case . updateRecentTodos( let todos) :
313298 state. recentTodos = todos
314- case . fetchWebPages ( let pages) :
299+ case . updateWebPages ( let pages) :
315300 state. webPages = pages
316301 case . restoreWebPage( let page, let index) :
317302 if state. webPages. contains ( where: { $0. id == page. id } ) { break }
@@ -323,12 +308,6 @@ private extension HomeViewModel {
323308 if deletedWebPageURLString == page. url. absoluteString {
324309 deletedWebPageURLString = nil
325310 }
326- case . setRecentTodosLoading( let isLoading) :
327- state. isRecentTodosLoading = isLoading
328- case . setWebPageLoading( let isLoading) :
329- state. isWebPageLoading = isLoading
330- case . setAppending( let isLoading) :
331- state. isAppending = isLoading
332311 default :
333312 break
334313 }
@@ -338,6 +317,24 @@ private extension HomeViewModel {
338317
339318// MARK: - Helper Methods
340319private extension HomeViewModel {
320+ func setPresentation(
321+ _ state: inout State ,
322+ presentation: Presentation ,
323+ isPresented: Bool
324+ ) {
325+ switch presentation {
326+ case . reorderTodo:
327+ state. reorderTodo = isPresented
328+ case . todoEditor:
329+ state. showTodoEditor = isPresented
330+ if !isPresented { state. selectedTodoKind = nil }
331+ case . contentPicker:
332+ state. showContentPicker = isPresented
333+ case . searchView:
334+ state. showSearchView = isPresented
335+ }
336+ }
337+
341338 func setAlert(
342339 _ state: inout State ,
343340 isPresented: Bool ,
@@ -377,6 +374,21 @@ private extension HomeViewModel {
377374 state. toastType = type
378375 }
379376
377+ func setLoading(
378+ _ state: inout State ,
379+ loadingTarget: LoadingTarget ,
380+ isLoading: Bool
381+ ) {
382+ switch loadingTarget {
383+ case . recentTodos:
384+ state. isRecentTodosLoading = isLoading
385+ case . webPage:
386+ state. isWebPageLoading = isLoading
387+ case . overlay:
388+ state. isAppending = isLoading
389+ }
390+ }
391+
380392 func normalizedWebPageURL( _ input: String ) -> String ? {
381393 let trimmed = input. trimmingCharacters ( in: . whitespacesAndNewlines)
382394 guard !trimmed. isEmpty else { return nil }
0 commit comments