@@ -63,20 +63,24 @@ struct TodoListFeature {
6363 case alert( PresentationAction < Never > )
6464 case fullScreenCover( PresentationAction < Never > )
6565 case binding( BindingAction < State > )
66- case refresh
67- case setFullScreenCover( FullScreenCoverState ? )
68- case swipeTodo( TodoListItem )
69- case resetFilters
70- case finishDeleteToast( String )
71- case tapToggleCompleted( TodoListItem )
72- case tapTogglePinned( TodoListItem )
73- case undoDelete
74- case onAppear
75- case loadNextPage
66+ case view( ViewAction )
7667 case store( StoreAction )
7768 case loading( LoadingFeature . Action )
7869
70+ enum ViewAction : Equatable {
71+ case refresh
72+ case swipeTodo( TodoListItem )
73+ case resetFilters
74+ case finishDeleteToast( String )
75+ case tapToggleCompleted( TodoListItem )
76+ case tapTogglePinned( TodoListItem )
77+ case undoDelete
78+ case onAppear
79+ case loadNextPage
80+ }
81+
7982 enum StoreAction : Equatable {
83+ case setFullScreenCover( FullScreenCoverState ? )
8084 case setAlert( Bool )
8185 case applySearchQuery( String )
8286 case fetchSearchResults( [ TodoListItem ] )
@@ -111,7 +115,36 @@ struct TodoListFeature {
111115 }
112116 BindingReducer ( )
113117 Reduce { state, action in
114- reduce ( action, state: & state)
118+ switch action {
119+ case . alert:
120+ break
121+ case . fullScreenCover( . dismiss) :
122+ state. fullScreenCover = nil
123+ case . fullScreenCover:
124+ break
125+ case . binding( \. searchText) :
126+ return setSearchTextEffect ( state: & state)
127+ case . binding( \. isSearching) :
128+ guard !state. isSearching else { break }
129+ state. searchText = " "
130+ state. searchResults = [ ]
131+ state. showAllSearchResults = false
132+ return cancelSearchEffect ( )
133+ case . binding( \. query. sortTarget) , . binding( \. query. sortOrder) , . binding( \. query. isPinned) ,
134+ . binding( \. query. completionFilter) :
135+ state. nextCursor = nil
136+ return fetchEffect ( query: state. query, cursor: nil )
137+ case . binding:
138+ break
139+ case . view( let action) :
140+ return reduce ( action, state: & state)
141+ case . store( let action) :
142+ return reduce ( action, state: & state)
143+ case . loading:
144+ break
145+ }
146+
147+ return . none
115148 }
116149 . ifLet ( \. $alert, action: \. alert)
117150 }
@@ -165,84 +198,6 @@ private enum TodoListUndoDeleteTodoUseCaseKey: DependencyKey {
165198}
166199
167200private extension TodoListFeature {
168- func reduce( _ action: Action , state: inout State ) -> Effect < Action > {
169- switch action {
170- case . alert:
171- break
172- case . fullScreenCover( . dismiss) :
173- state. fullScreenCover = nil
174- case . fullScreenCover:
175- break
176- case . binding( \. searchText) :
177- return setSearchTextEffect ( state: & state)
178- case . binding( \. isSearching) :
179- guard !state. isSearching else { break }
180- state. searchText = " "
181- state. searchResults = [ ]
182- state. showAllSearchResults = false
183- return cancelSearchEffect ( )
184- case . binding( \. query. sortTarget) , . binding( \. query. sortOrder) , . binding( \. query. isPinned) ,
185- . binding( \. query. completionFilter) :
186- state. nextCursor = nil
187- return fetchEffect ( query: state. query, cursor: nil )
188- case . binding:
189- break
190- case . refresh, . onAppear:
191- return fetchEffect ( query: state. query, cursor: nil )
192- case . store( . setAlert( let value) ) :
193- Self . setAlert ( & state, isPresented: value)
194- case . setFullScreenCover( let cover) :
195- state. fullScreenCover = cover
196- case . swipeTodo( let todo) :
197- return swipeTodoEffect ( todo, state: & state)
198- case . resetFilters:
199- state. query = TodoQuery ( categoryId: state. category. storageValue)
200- state. nextCursor = nil
201- return fetchEffect ( query: state. query, cursor: nil )
202- case . finishDeleteToast( let todoId) :
203- state. todos. removeAll { $0. id == todoId && $0. isHidden }
204- state. searchResults. removeAll { $0. id == todoId && $0. isHidden }
205- if state. undoTodoId == todoId {
206- state. undoTodoId = nil
207- }
208- case . tapToggleCompleted( let todo) :
209- return toggleCompletedEffect ( todo)
210- case . tapTogglePinned( let todo) :
211- return togglePinnedEffect ( todo)
212- case . undoDelete:
213- guard let undoTodoId = state. undoTodoId else { return . none }
214- Self . setTodoHidden ( & state, todoId: undoTodoId, isHidden: false )
215- state. undoTodoId = nil
216- return undoDeleteEffect ( undoTodoId)
217- case . loadNextPage:
218- guard state. hasMore, !state. isLoading else { return . none }
219- return fetchEffect ( query: state. query, cursor: state. nextCursor, resetsPagination: false )
220- case . store( . applySearchQuery( let query) ) :
221- return applySearchQueryEffect ( query, state: & state)
222- case . store( . fetchSearchResults( let items) ) :
223- state. searchResults = items
224- case . store( . didToggleCompleted( let todo) ) , . store( . didTogglePinned( let todo) ) :
225- if let index = state. todos. firstIndex ( where: { $0. id == todo. id } ) {
226- state. todos [ index] = todo
227- }
228- case . store( . setTodoHidden( let todoId, let isHidden) ) :
229- Self . setTodoHidden ( & state, todoId: todoId, isHidden: isHidden)
230- case . store( . appendTodos( let todos, let nextCursor) ) :
231- state. todos. append ( contentsOf: todos)
232- state. nextCursor = nextCursor
233- case . store( . resetPagination) :
234- state. todos = [ ]
235- state. nextCursor = nil
236- state. hasMore = false
237- case . store( . setHasMore( let value) ) :
238- state. hasMore = value
239- case . loading:
240- break
241- }
242-
243- return . none
244- }
245-
246201 func fetchEffect(
247202 query: TodoQuery ,
248203 cursor: TodoCursor ? ,
@@ -316,4 +271,73 @@ private extension TodoListFeature {
316271 . cancellable ( id: CancelID . debounce, cancelInFlight: true )
317272 )
318273 }
274+
275+ func reduce(
276+ _ action: Action . ViewAction ,
277+ state: inout State
278+ ) -> Effect < Action > {
279+ switch action {
280+ case . refresh, . onAppear:
281+ return fetchEffect ( query: state. query, cursor: nil )
282+ case . swipeTodo( let todo) :
283+ return swipeTodoEffect ( todo, state: & state)
284+ case . resetFilters:
285+ state. query = TodoQuery ( categoryId: state. category. storageValue)
286+ state. nextCursor = nil
287+ return fetchEffect ( query: state. query, cursor: nil )
288+ case . finishDeleteToast( let todoId) :
289+ state. todos. removeAll { $0. id == todoId && $0. isHidden }
290+ state. searchResults. removeAll { $0. id == todoId && $0. isHidden }
291+ if state. undoTodoId == todoId {
292+ state. undoTodoId = nil
293+ }
294+ case . tapToggleCompleted( let todo) :
295+ return toggleCompletedEffect ( todo)
296+ case . tapTogglePinned( let todo) :
297+ return togglePinnedEffect ( todo)
298+ case . undoDelete:
299+ guard let undoTodoId = state. undoTodoId else { return . none }
300+ Self . setTodoHidden ( & state, todoId: undoTodoId, isHidden: false )
301+ state. undoTodoId = nil
302+ return undoDeleteEffect ( undoTodoId)
303+ case . loadNextPage:
304+ guard state. hasMore, !state. isLoading else { return . none }
305+ return fetchEffect ( query: state. query, cursor: state. nextCursor, resetsPagination: false )
306+ }
307+
308+ return . none
309+ }
310+
311+ func reduce(
312+ _ action: Action . StoreAction ,
313+ state: inout State
314+ ) -> Effect < Action > {
315+ switch action {
316+ case . setFullScreenCover( let cover) :
317+ state. fullScreenCover = cover
318+ case . setAlert( let value) :
319+ Self . setAlert ( & state, isPresented: value)
320+ case . applySearchQuery( let query) :
321+ return applySearchQueryEffect ( query, state: & state)
322+ case . fetchSearchResults( let items) :
323+ state. searchResults = items
324+ case . didToggleCompleted( let todo) , . didTogglePinned( let todo) :
325+ if let index = state. todos. firstIndex ( where: { $0. id == todo. id } ) {
326+ state. todos [ index] = todo
327+ }
328+ case . setTodoHidden( let todoId, let isHidden) :
329+ Self . setTodoHidden ( & state, todoId: todoId, isHidden: isHidden)
330+ case . appendTodos( let todos, let nextCursor) :
331+ state. todos. append ( contentsOf: todos)
332+ state. nextCursor = nextCursor
333+ case . resetPagination:
334+ state. todos = [ ]
335+ state. nextCursor = nil
336+ state. hasMore = false
337+ case . setHasMore( let value) :
338+ state. hasMore = value
339+ }
340+
341+ return . none
342+ }
319343}
0 commit comments