@@ -9,6 +9,7 @@ import SwiftUI
99import ComposableArchitecture
1010import ArticlesListFeature
1111import ArticleFeature
12+ import ForumFeature
1213import MenuFeature
1314import AuthFeature
1415import ProfileFeature
@@ -24,9 +25,18 @@ public struct AppFeature: Sendable {
2425 // MARK: - Path
2526
2627 @Reducer ( state: . equatable)
27- public enum Path {
28+ public enum ArticlesPath {
2829 case article( ArticleFeature )
29- case menu( MenuFeature )
30+ case profile( ProfileFeature )
31+ }
32+
33+ @Reducer ( state: . equatable)
34+ public enum ForumPath {
35+
36+ }
37+
38+ @Reducer ( state: . equatable)
39+ public enum MenuPath {
3040 case auth( AuthFeature )
3141 case profile( ProfileFeature )
3242 case settings( SettingsFeature )
@@ -36,9 +46,15 @@ public struct AppFeature: Sendable {
3646
3747 @ObservableState
3848 public struct State : Equatable {
39- public var path : StackState < Path . State >
4049 public var appDelegate : AppDelegateFeature . State
50+
51+ public var articlesPath : StackState < ArticlesPath . State >
52+ public var forumPath : StackState < ForumPath . State >
53+ public var menuPath : StackState < MenuPath . State >
54+
4155 public var articlesList : ArticlesListFeature . State
56+ public var forum : ForumFeature . State
57+ public var menu : MenuFeature . State
4258
4359 public var showToast : Bool
4460 public var toast : ToastInfo
@@ -50,15 +66,26 @@ public struct AppFeature: Sendable {
5066 }
5167
5268 public init (
53- path: StackState < Path . State > = StackState ( ) ,
5469 appDelegate: AppDelegateFeature . State = AppDelegateFeature . State ( ) ,
70+ articlesPath: StackState < ArticlesPath . State > = StackState ( ) ,
71+ forumPath: StackState < ForumPath . State > = StackState ( ) ,
72+ menuPath: StackState < MenuPath . State > = StackState ( ) ,
5573 articlesList: ArticlesListFeature . State = ArticlesListFeature . State ( ) ,
74+ forum: ForumFeature . State = ForumFeature . State ( ) ,
75+ menu: MenuFeature . State = MenuFeature . State ( ) ,
5676 showToast: Bool = false ,
5777 toast: ToastInfo = ToastInfo ( screen: . articlesList, message: " " )
5878 ) {
59- self . path = path
6079 self . appDelegate = appDelegate
80+
81+ self . articlesPath = articlesPath
82+ self . forumPath = forumPath
83+ self . menuPath = menuPath
84+
6185 self . articlesList = articlesList
86+ self . forum = forum
87+ self . menu = menu
88+
6289 self . showToast = showToast
6390 self . toast = toast
6491 }
@@ -68,9 +95,16 @@ public struct AppFeature: Sendable {
6895
6996 public enum Action : BindableAction {
7097 case appDelegate( AppDelegateFeature . Action )
71- case path( StackActionOf < Path > )
98+
99+ case articlesPath( StackActionOf < ArticlesPath > )
100+ case forumPath( StackActionOf < ForumPath > )
101+ case menuPath( StackActionOf < MenuPath > )
102+
72103 case articlesList( ArticlesListFeature . Action )
73- case binding( BindingAction < State > ) // TODO: Do I need it?
104+ case forum( ForumFeature . Action )
105+ case menu( MenuFeature . Action )
106+
107+ case binding( BindingAction < State > ) // For Toast
74108 case deeplink( URL )
75109 case scenePhaseDidChange( from: ScenePhase , to: ScenePhase )
76110 }
@@ -92,6 +126,14 @@ public struct AppFeature: Sendable {
92126 ArticlesListFeature ( )
93127 }
94128
129+ Scope ( state: \. forum, action: \. forum) {
130+ ForumFeature ( )
131+ }
132+
133+ Scope ( state: \. menu, action: \. menu) {
134+ MenuFeature ( )
135+ }
136+
95137 Reduce { state, action in
96138 switch action {
97139
@@ -123,7 +165,7 @@ public struct AppFeature: Sendable {
123165 let id = Int ( match!. output. 1 ) !
124166
125167 let articlePreview = ArticlePreview . outerDeeplink ( id: id, imageUrl: imageUrl, title: title)
126- state. path . append ( . article( ArticleFeature . State ( articlePreview: articlePreview) ) )
168+ state. articlesPath . append ( . article( ArticleFeature . State ( articlePreview: articlePreview) ) )
127169
128170 default : // For new deeplink usage cases
129171 break
@@ -141,14 +183,25 @@ public struct AppFeature: Sendable {
141183 return . none
142184 }
143185
144- // MARK: - ArticlesList
186+ // MARK: - Default
187+
188+ case . articlesList, . forum, . menu:
189+ return . none
145190
146- case . articlesList( . menuTapped) :
147- state. path. append ( . menu( MenuFeature . State ( ) ) )
191+ case . articlesPath, . forumPath, . menuPath:
148192 return . none
193+ }
194+ }
195+
196+ // MARK: - Article Path
197+
198+ Reduce { state, action in
199+ switch action {
200+
201+ // MARK: - Articles List
149202
150203 case let . articlesList( . articleTapped( articlePreview) ) :
151- state. path . append ( . article( ArticleFeature . State ( articlePreview: articlePreview) ) )
204+ state. articlesPath . append ( . article( ArticleFeature . State ( articlePreview: articlePreview) ) )
152205 return . none
153206
154207 case let . articlesList( . cellMenuOpened( _, action) ) :
@@ -164,9 +217,9 @@ public struct AppFeature: Sendable {
164217 case . articlesList:
165218 return . none
166219
167- // MARK: - Article
220+ // MARK: Article
168221
169- case let . path ( . element( id: _, action: . article( . menuActionTapped( action) ) ) ) :
222+ case let . articlesPath ( . element( id: _, action: . article( . menuActionTapped( action) ) ) ) :
170223 switch action {
171224 case . copyLink, . report:
172225 state. toast = ToastInfo ( screen: . article, message: action. rawValue)
@@ -176,44 +229,62 @@ public struct AppFeature: Sendable {
176229 state. showToast = true
177230 return . none
178231
179- case let . path ( . element( id: _, action: . article( . delegate( . handleDeeplink( id) ) ) ) ) :
232+ case let . articlesPath ( . element( id: _, action: . article( . delegate( . handleDeeplink( id) ) ) ) ) :
180233 let articlePreview = ArticlePreview . innerDeeplink ( id: id)
181- state. path . append ( . article( ArticleFeature . State ( articlePreview: articlePreview) ) )
234+ state. articlesPath . append ( . article( ArticleFeature . State ( articlePreview: articlePreview) ) )
182235 return . none
183236
184- case let . path( . element( id: _, action: . article( . delegate( . commentHeaderTapped( id) ) ) ) ) :
185- state. path. append ( . profile( ProfileFeature . State ( userId: id) ) )
237+ case let . articlesPath( . element( id: _, action: . article( . delegate( . commentHeaderTapped( id) ) ) ) ) :
238+ state. articlesPath. append ( . profile( ProfileFeature . State ( userId: id) ) )
239+ return . none
240+
241+ default :
242+ return . none
243+ }
244+ }
245+ . forEach ( \. articlesPath, action: \. articlesPath)
246+
247+ // MARK: - Forum Path
248+
249+ Reduce { state, action in
250+ switch action {
251+ default :
186252 return . none
253+ }
254+ }
255+ . forEach ( \. forumPath, action: \. forumPath)
256+
257+ // MARK: - Menu Path
258+
259+ Reduce { state, action in
260+ switch action {
187261
188- // MARK: - Menu
262+ // MARK: Menu
189263
190- case . path ( . element ( id : _ , action : . menu( . delegate( . openAuth) ) ) ) :
191- state. path . append ( . auth( AuthFeature . State ( ) ) )
264+ case . menu( . delegate( . openAuth) ) :
265+ state. menuPath . append ( . auth( AuthFeature . State ( ) ) )
192266 return . none
193267
194- case let . path ( . element ( id : _ , action : . menu( . delegate( . openProfile( id: id) ) ) ) ) :
195- state. path . append ( . profile( ProfileFeature . State ( userId: id) ) )
268+ case let . menu( . delegate( . openProfile( id: id) ) ) :
269+ state. menuPath . append ( . profile( ProfileFeature . State ( userId: id) ) )
196270 return . none
197271
198- case . path ( . element ( id : _ , action : . menu( . settingsTapped) ) ) :
199- state. path . append ( . settings( SettingsFeature . State ( ) ) )
272+ case . menu( . settingsTapped) :
273+ state. menuPath . append ( . settings( SettingsFeature . State ( ) ) )
200274 return . none
201275
202- // MARK: - Auth
276+ // MARK: Auth
203277
204- case let . path ( . element( id: id, action: . auth( . delegate( . loginSuccess( userId: userId) ) ) ) ) :
278+ case let . menuPath ( . element( id: id, action: . auth( . delegate( . loginSuccess( userId: userId) ) ) ) ) :
205279 // TODO: How to make seamless animation?
206- state. path . pop ( from: id)
207- state. path . append ( . profile( ProfileFeature . State ( userId: userId) ) )
280+ state. menuPath . pop ( from: id)
281+ state. menuPath . append ( . profile( ProfileFeature . State ( userId: userId) ) )
208282 return . none
209283
210- // MARK: - Default
211-
212- case . path:
284+ default :
213285 return . none
214286 }
215-
216287 }
217- . forEach ( \. path , action: \. path )
288+ . forEach ( \. menuPath , action: \. menuPath )
218289 }
219290}
0 commit comments