diff --git a/Example/example-app/Package.swift b/Example/example-app/Package.swift index cb8aead735a4ccc7be2327faf8215acbc126c23a..0c0ef22230153b65f531bbdb29f044158041a35f 100644 --- a/Example/example-app/Package.swift +++ b/Example/example-app/Package.swift @@ -62,6 +62,7 @@ let package = Package( dependencies: [ .target(name: "ErrorFeature"), .target(name: "LandingFeature"), + .target(name: "MyIdentityFeature"), .target(name: "SessionFeature"), .product( name: "ElixxirDAppsSDK", @@ -157,6 +158,7 @@ let package = Package( name: "SessionFeature", dependencies: [ .target(name: "ErrorFeature"), + .target(name: "MyIdentityFeature"), .product( name: "ComposableArchitecture", package: "swift-composable-architecture" diff --git a/Example/example-app/Sources/AppFeature/App.swift b/Example/example-app/Sources/AppFeature/App.swift index 341cb46c6bbc7515e222c9e4157fab6f42c82160..06477b12909ed045647364b6d209c1256307d154 100644 --- a/Example/example-app/Sources/AppFeature/App.swift +++ b/Example/example-app/Sources/AppFeature/App.swift @@ -3,6 +3,7 @@ import ComposableArchitecture import ElixxirDAppsSDK import ErrorFeature import LandingFeature +import MyIdentityFeature import SessionFeature import SwiftUI @@ -44,7 +45,9 @@ extension AppEnvironment { session: SessionEnvironment( getClient: { clientSubject.value }, bgScheduler: bgScheduler, - mainScheduler: mainScheduler + mainScheduler: mainScheduler, + makeId: UUID.init, + myIdentity: MyIdentityEnvironment() ) ) } diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift index a9b973610534b5c0cb4f1ebe8c7bf219209045c2..fb4c7200466290ea5f950eaaa65605f1948042ca 100644 --- a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift +++ b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift @@ -1,7 +1,13 @@ import ComposableArchitecture public struct MyIdentityState: Equatable { - public init() {} + public init( + id: UUID + ) { + self.id = id + } + + public var id: UUID } public enum MyIdentityAction: Equatable {} diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift index 4061024b1b26ae4a758dc8f9cacdbd422f5c747d..c50941b6a987a909aa2440541c69f6ad133ce82a 100644 --- a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift +++ b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift @@ -24,7 +24,7 @@ public struct MyIdentityView_Previews: PreviewProvider { public static var previews: some View { NavigationView { MyIdentityView(store: .init( - initialState: .init(), + initialState: .init(id: UUID()), reducer: .empty, environment: () )) diff --git a/Example/example-app/Sources/SessionFeature/SessionFeature.swift b/Example/example-app/Sources/SessionFeature/SessionFeature.swift index 0756f738008e1ea1870ffd1a11a600fccab5e0ca..f3ba93262307cc067732c18068fcc4dddc25989f 100644 --- a/Example/example-app/Sources/SessionFeature/SessionFeature.swift +++ b/Example/example-app/Sources/SessionFeature/SessionFeature.swift @@ -2,24 +2,28 @@ import Combine import ComposableArchitecture import ElixxirDAppsSDK import ErrorFeature +import MyIdentityFeature public struct SessionState: Equatable { public init( id: UUID, networkFollowerStatus: NetworkFollowerStatus? = nil, isNetworkHealthy: Bool? = nil, - error: ErrorState? = nil + error: ErrorState? = nil, + myIdentity: MyIdentityState? = nil ) { self.id = id self.networkFollowerStatus = networkFollowerStatus self.isNetworkHealthy = isNetworkHealthy self.error = error + self.myIdentity = myIdentity } public var id: UUID public var networkFollowerStatus: NetworkFollowerStatus? public var isNetworkHealthy: Bool? public var error: ErrorState? + public var myIdentity: MyIdentityState? } public enum SessionAction: Equatable { @@ -31,23 +35,32 @@ public enum SessionAction: Equatable { case monitorNetworkHealth(Bool) case didUpdateNetworkHealth(Bool?) case didDismissError + case presentMyIdentity + case didDismissMyIdentity case error(ErrorAction) + case myIdentity(MyIdentityAction) } public struct SessionEnvironment { public init( getClient: @escaping () -> Client?, bgScheduler: AnySchedulerOf<DispatchQueue>, - mainScheduler: AnySchedulerOf<DispatchQueue> + mainScheduler: AnySchedulerOf<DispatchQueue>, + makeId: @escaping () -> UUID, + myIdentity: MyIdentityEnvironment ) { self.getClient = getClient self.bgScheduler = bgScheduler self.mainScheduler = mainScheduler + self.makeId = makeId + self.myIdentity = myIdentity } public var getClient: () -> Client? public var bgScheduler: AnySchedulerOf<DispatchQueue> public var mainScheduler: AnySchedulerOf<DispatchQueue> + public var makeId: () -> UUID + public var myIdentity: MyIdentityEnvironment } public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironment> @@ -129,17 +142,36 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm state.error = nil return .none - case .error(_): + case .presentMyIdentity: + if state.myIdentity == nil { + state.myIdentity = MyIdentityState(id: env.makeId()) + } + return .none + + case .didDismissMyIdentity: + state.myIdentity = nil + return .none + + case .error(_), .myIdentity(_): return .none } } +.presenting( + myIdentityReducer, + state: .keyPath(\.myIdentity), + id: .keyPath(\.?.id), + action: /SessionAction.myIdentity, + environment: \.myIdentity +) #if DEBUG extension SessionEnvironment { public static let failing = SessionEnvironment( getClient: { .failing }, bgScheduler: .failing, - mainScheduler: .failing + mainScheduler: .failing, + makeId: { fatalError() }, + myIdentity: .failing ) } #endif diff --git a/Example/example-app/Sources/SessionFeature/SessionView.swift b/Example/example-app/Sources/SessionFeature/SessionView.swift index 395cfcb160067fedc31ec3ddd5200aa6960864e2..9f3c419b8034a475a7fa6ad272ba15a796c76166 100644 --- a/Example/example-app/Sources/SessionFeature/SessionView.swift +++ b/Example/example-app/Sources/SessionFeature/SessionView.swift @@ -2,6 +2,7 @@ import ComposableArchitecture import ComposablePresentation import ElixxirDAppsSDK import ErrorFeature +import MyIdentityFeature import SwiftUI public struct SessionView: View { @@ -49,6 +50,18 @@ public struct SessionView: View { } header: { Text("Network health") } + + Section { + Button { + viewStore.send(.presentMyIdentity) + } label: { + HStack { + Text("My identity") + Spacer() + Image(systemName: "chevron.forward") + } + } + } } .navigationTitle("Session") .task { @@ -64,6 +77,18 @@ public struct SessionView: View { }, content: ErrorView.init(store:) ) + .background( + NavigationLinkWithStore( + store.scope( + state: \.myIdentity, + action: SessionAction.myIdentity + ), + onDeactivate: { + viewStore.send(.didDismissMyIdentity) + }, + destination: MyIdentityView.init(store:) + ) + ) } } } diff --git a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift index 2ada840d7d9d02bdb1c8732836502ad15d15be33..02039168ccf5b97fa064aecaf582908a588a6417 100644 --- a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift +++ b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift @@ -1,6 +1,7 @@ import ComposableArchitecture import ElixxirDAppsSDK import ErrorFeature +import MyIdentityFeature import XCTest @testable import SessionFeature @@ -155,4 +156,25 @@ final class SessionFeatureTests: XCTestCase { $0.error = nil } } + + func testPresentingMyIdentity() { + let newId = UUID() + + var env = SessionEnvironment.failing + env.makeId = { newId } + + let store = TestStore( + initialState: SessionState(id: UUID()), + reducer: sessionReducer, + environment: env + ) + + store.send(.presentMyIdentity) { + $0.myIdentity = MyIdentityState(id: newId) + } + + store.send(.didDismissMyIdentity) { + $0.myIdentity = nil + } + } }