Last active
September 26, 2022 08:07
-
-
Save bocato/474c8285c0543a8d142e02a1356de17c to your computer and use it in GitHub Desktop.
Features / Interface Modules SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. Feature definition (Module entry point / Root) | |
public struct ActivitiesFeatureRoutesHandler: RoutesHandler { | |
public var routes: [SceneRoute.Type] { | |
[ | |
WODListRoute.self, | |
WODRouletteRoute.self, | |
WODDetailsRoute.self | |
] | |
} | |
public init() {} | |
public func destination<Context>( | |
forRoute route: SceneRoute, | |
withContext context: Context | |
) -> Feature.Type { ActivitiesFeature.self } | |
} | |
struct ActivitiesFeature: Feature { | |
// MARK: - Dependencies | |
@Dependency var wodsRepository: WODSRepository | |
@Dependency var wodWellRepository: WODWellRepositoryProtocol | |
@Dependency var crossfitWebsiteRepository: CrossfitWebsiteRepository | |
@Dependency var routingSystem: RoutingSystemProtocol | |
var mainQueue: AnySchedulerOf<DispatchQueue> = DispatchQueue.main.eraseToAnyScheduler() | |
// MARK: - Build Logic | |
func build<Context>( | |
from route: SceneRoute, | |
context: Context | |
) -> SceneAssembler { | |
switch route { | |
case is WODListRoute: | |
return .init( | |
buildLogicController: { | |
Store<WODListState, WODListAction>( | |
initialState: .init(), | |
reducer: wodListReducer, | |
environment: WODListEnvironment( | |
wodsRepository: wodsRepository, | |
mainQueue: mainQueue | |
) | |
) | |
}, | |
buildView: { WODListView(store: $0, routingSystem: routingSystem) } | |
) | |
case is WODRouletteRoute: | |
return .init( | |
buildLogicController: { | |
Store<WODRouletteState, WODRouletteAction>( | |
initialState: .init(), | |
reducer: wodRouletteReducer, | |
environment: WODRouletteEnvironment( | |
wodWellRepository: wodWellRepository, | |
crossfitWebsiteRepository: crossfitWebsiteRepository, | |
mainQueue: mainQueue | |
) | |
) | |
}, | |
buildView: { WODRouletteView(store: $0) } | |
) | |
case let route as WODDetailsRoute: | |
return .init( | |
buildState: { WODDetailsState(wodData: .init(wodData: route.wodData)) }, | |
buildLogicController: { (state: WODDetailsState) -> Store<WODDetailsState, WODDetailsAction> in | |
.init( | |
initialState: state, | |
reducer: wodDetailsReducer, | |
environment: WODDetailsEnvironment() | |
) | |
}, | |
buildView: { WODDetailsView(store: $0) } | |
) | |
default: | |
preconditionFailure("Unexpected route!") | |
} | |
} | |
} | |
import ComposableArchitecture | |
import Core_IntegrationKit | |
import Feature_Home_Interface | |
import SwiftUI | |
import LightInjection | |
public struct HomeFeatureRoutesHandler: RoutesHandler { | |
public var routes: [SceneRoute.Type] { | |
[ | |
HomeRoute.self | |
] | |
} | |
public init() {} | |
public func destination<Context>( | |
forRoute route: SceneRoute, | |
withContext context: Context | |
) -> Feature.Type { HomeFeature.self } | |
} | |
struct HomeFeature: Feature { | |
// MARK: - Dependencies | |
@Dependency var routingSystem: RoutingSystemProtocol | |
var mainQueue: AnySchedulerOf<DispatchQueue> = DispatchQueue.main.eraseToAnyScheduler() | |
// MARK: - Build Logic | |
func build<Context>( | |
from route: SceneRoute, | |
context: Context | |
) -> SceneAssembler { | |
switch route { | |
case is HomeRoute: | |
return .init( | |
buildLogicController: { (actions: HomeActions) in | |
Store<HomeState, HomeAction>( | |
initialState: .init(), // set selected tab, can start from deeplink, for example | |
reducer: homeReducer, | |
environment: HomeEnvironment( | |
onLogout: actions.onLogout, | |
mainQueue: mainQueue | |
) | |
) | |
}, | |
buildView: { HomeView(store: $0, routingSystem: routingSystem) } | |
) | |
default: | |
preconditionFailure("Unexpected route!") | |
} | |
} | |
} | |
// 2. Setup (on app delegate, or integration layer) | |
routingSystem.register( | |
routesHandler: ActivitiesFeatureRoutesHandler() | |
) | |
// 3. Defining Route / Actions | |
import Core_IntegrationKit | |
import Foundation | |
struct SignUpRoute: SceneRoute, Equatable, Identifiable { | |
var id: String { identifier } | |
static var identifier: Identifier { "feature:authentication:sign_up" } | |
} | |
struct SignUpActions { | |
let onSigninSuccess: () -> Void | |
} | |
// 4. Using to route | |
struct MyView: View { | |
// ... | |
var body: some View { | |
WithViewStore(store) { viewStore in | |
VStack { | |
Text(L10n.SignIn.title) | |
.font(.largeTitle) | |
.bold() | |
Form { | |
emailSection(with: viewStore) | |
passwordSection(with: viewStore) | |
loginActionsSection(with: viewStore) | |
footerSection(with: viewStore) | |
} | |
} | |
.onAppear { viewStore.send(.onAppear) } | |
.enableUserInteraction(viewStore.isAPIRequestInFlight == false) | |
.sheet( | |
item: viewStore.binding( | |
get: { $0.signUpRoute }, | |
send: .presentSignUpScene(false) | |
), | |
content: { route in | |
routingSystem.getView( | |
for: route, | |
actions: SignUpActions( | |
onSigninSuccess: { | |
viewStore.send(.presentSignUpScene(false)) | |
viewStore.send(.routeToHomeFeature) | |
} | |
), | |
keepAliveIn: viewStore.signUpSceneStore, | |
enableStateRestoration: true | |
) | |
} | |
) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment