diff --git a/Example/ExampleApp/Package.swift b/Example/ExampleApp/Package.swift index 9f02c271e0bba61bdf5ce95235ca7a946288950b..3b02bf979acbbd2d44d20cc04eca3ad9dc4a8ce9 100644 --- a/Example/ExampleApp/Package.swift +++ b/Example/ExampleApp/Package.swift @@ -56,6 +56,7 @@ let package = Package( .target( name: "AppFeature", dependencies: [ + .target(name: "ErrorFeature"), .target(name: "LandingFeature"), .target(name: "SessionFeature"), .product( @@ -108,10 +109,15 @@ let package = Package( .target( name: "LandingFeature", dependencies: [ + .target(name: "ErrorFeature"), .product( name: "ComposableArchitecture", package: "swift-composable-architecture" ), + .product( + name: "ComposablePresentation", + package: "swift-composable-presentation" + ), .product( name: "ElixxirDAppsSDK", package: "elixxir-dapps-sdk-swift" diff --git a/Example/ExampleApp/Sources/AppFeature/App.swift b/Example/ExampleApp/Sources/AppFeature/App.swift index b7446b7e0e0849b549d7b802e255038ec0e0f243..1353882a744740f111d93562021f892f3108d5a9 100644 --- a/Example/ExampleApp/Sources/AppFeature/App.swift +++ b/Example/ExampleApp/Sources/AppFeature/App.swift @@ -1,6 +1,7 @@ import Combine import ComposableArchitecture import ElixxirDAppsSDK +import ErrorFeature import LandingFeature import SessionFeature import SwiftUI @@ -36,7 +37,8 @@ extension AppEnvironment { ), setClient: { clientSubject.send($0) }, bgScheduler: bgScheduler, - mainScheduler: mainScheduler + mainScheduler: mainScheduler, + error: ErrorEnvironment() ), session: SessionEnvironment() ) diff --git a/Example/ExampleApp/Sources/ErrorFeature/ErrorFeature.swift b/Example/ExampleApp/Sources/ErrorFeature/ErrorFeature.swift index 756260a9d0e6da6e8c7e790f25568586c4fc795b..dc7d8b69db96f23837fd62a352dbe8d4f0f2e2f0 100644 --- a/Example/ExampleApp/Sources/ErrorFeature/ErrorFeature.swift +++ b/Example/ExampleApp/Sources/ErrorFeature/ErrorFeature.swift @@ -6,7 +6,7 @@ public struct ErrorState: Equatable { self.error = error } - var error: NSError + public var error: NSError } public enum ErrorAction: Equatable {} diff --git a/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift b/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift index a3b1c3b83b19384da34d95c44dce9151ee373bb7..dfca1d37c532b6cdbf682c3ea5465f4829e513e0 100644 --- a/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift +++ b/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift @@ -1,21 +1,25 @@ import Combine import ComposableArchitecture import ElixxirDAppsSDK +import ErrorFeature public struct LandingState: Equatable { public init( hasStoredClient: Bool = false, isMakingClient: Bool = false, - isRemovingClient: Bool = false + isRemovingClient: Bool = false, + error: ErrorState? = nil ) { self.hasStoredClient = hasStoredClient self.isMakingClient = isMakingClient self.isRemovingClient = isRemovingClient + self.error = error } var hasStoredClient: Bool var isMakingClient: Bool var isRemovingClient: Bool + var error: ErrorState? } public enum LandingAction: Equatable { @@ -26,6 +30,8 @@ public enum LandingAction: Equatable { case removeStoredClient case didRemoveStoredClient case didFailRemovingStoredClient(NSError) + case didDismissError + case error(ErrorAction) } public struct LandingEnvironment { @@ -33,18 +39,21 @@ public struct LandingEnvironment { clientStorage: ClientStorage, setClient: @escaping (Client) -> Void, bgScheduler: AnySchedulerOf<DispatchQueue>, - mainScheduler: AnySchedulerOf<DispatchQueue> + mainScheduler: AnySchedulerOf<DispatchQueue>, + error: ErrorEnvironment ) { self.clientStorage = clientStorage self.setClient = setClient self.bgScheduler = bgScheduler self.mainScheduler = mainScheduler + self.error = error } public var clientStorage: ClientStorage public var setClient: (Client) -> Void public var bgScheduler: AnySchedulerOf<DispatchQueue> public var mainScheduler: AnySchedulerOf<DispatchQueue> + public var error: ErrorEnvironment } public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironment> @@ -80,7 +89,7 @@ public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironm case .didFailMakingClient(let error): state.isMakingClient = false state.hasStoredClient = env.clientStorage.hasStoredClient() - // TODO: handle error + state.error = ErrorState(error: error) return .none case .removeStoredClient: @@ -105,10 +114,21 @@ public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironm case .didFailRemovingStoredClient(let error): state.isRemovingClient = false state.hasStoredClient = env.clientStorage.hasStoredClient() - // TODO: handle error + state.error = ErrorState(error: error) + return .none + + case .didDismissError: + state.error = nil return .none } } +.presenting( + errorReducer, + state: .keyPath(\.error), + id: .keyPath(\.?.error), + action: /LandingAction.error, + environment: \.error +) #if DEBUG extension LandingEnvironment { @@ -116,7 +136,8 @@ extension LandingEnvironment { clientStorage: .failing, setClient: { _ in fatalError() }, bgScheduler: .failing, - mainScheduler: .failing + mainScheduler: .failing, + error: .failing ) } #endif diff --git a/Example/ExampleApp/Sources/LandingFeature/LandingView.swift b/Example/ExampleApp/Sources/LandingFeature/LandingView.swift index 325cbe635645c7ed4d98784f3dfb380a2ebcdb61..a4dd2b73face637d99e3615922a512d84d9994e5 100644 --- a/Example/ExampleApp/Sources/LandingFeature/LandingView.swift +++ b/Example/ExampleApp/Sources/LandingFeature/LandingView.swift @@ -1,4 +1,6 @@ import ComposableArchitecture +import ComposablePresentation +import ErrorFeature import SwiftUI public struct LandingView: View { @@ -59,6 +61,16 @@ public struct LandingView: View { .task { viewStore.send(.viewDidLoad) } + .sheet( + store.scope( + state: \.error, + action: LandingAction.error + ), + onDismiss: { + viewStore.send(.didDismissError) + }, + content: ErrorView.init(store:) + ) } } } diff --git a/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift b/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift index 3083d97ab257c31f4d1d2450ec50cd75ff1cc772..df9791e7de8c81a4a43f21a11e16f188afa044f7 100644 --- a/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift +++ b/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift @@ -1,4 +1,5 @@ import ComposableArchitecture +import ErrorFeature import XCTest @testable import LandingFeature @@ -115,6 +116,7 @@ final class LandingFeatureTests: XCTestCase { store.receive(.didFailMakingClient(error)) { $0.isMakingClient = false $0.hasStoredClient = false + $0.error = ErrorState(error: error) } } @@ -180,6 +182,7 @@ final class LandingFeatureTests: XCTestCase { store.receive(.didFailRemovingStoredClient(error)) { $0.isRemovingClient = false $0.hasStoredClient = true + $0.error = ErrorState(error: error) } } }