Skip to content

Instantly share code, notes, and snippets.

@bocato
Last active September 26, 2022 08:07
Show Gist options
  • Save bocato/474c8285c0543a8d142e02a1356de17c to your computer and use it in GitHub Desktop.
Save bocato/474c8285c0543a8d142e02a1356de17c to your computer and use it in GitHub Desktop.
Features / Interface Modules SwiftUI
// 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