diff --git a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactComponent.swift b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactComponent.swift new file mode 100644 index 0000000000000000000000000000000000000000..eaa2753626b1df72f6af6d89312670e281bae151 --- /dev/null +++ b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactComponent.swift @@ -0,0 +1,75 @@ +import AppCore +import ComposableArchitecture +import Foundation +import XCTestDynamicOverlay +import XXClient +import XXMessengerClient +import XXModels + +public struct VerifyContactComponent: ReducerProtocol { + public struct State: Equatable { + public enum Result: Equatable { + case success(Bool) + case failure(String) + } + + public init( + contact: XXClient.Contact, + isVerifying: Bool = false, + result: Result? = nil + ) { + self.contact = contact + self.isVerifying = isVerifying + self.result = result + } + + public var contact: XXClient.Contact + public var isVerifying: Bool + public var result: Result? + } + + public enum Action: Equatable { + case verifyTapped + case didVerify(State.Result) + } + + public init() {} + + @Dependency(\.appDependencies.messenger) var messenger: Messenger + @Dependency(\.appDependencies.dbManager.getDB) var db: DBManagerGetDB + @Dependency(\.appDependencies.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue> + @Dependency(\.appDependencies.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue> + + public func reduce(into state: inout State, action: Action) -> EffectTask<Action> { + switch action { + case .verifyTapped: + state.isVerifying = true + state.result = nil + return Effect.result { [state] in + func updateStatus(_ status: XXModels.Contact.AuthStatus) throws { + try db().bulkUpdateContacts.callAsFunction( + .init(id: [try state.contact.getId()]), + .init(authStatus: status) + ) + } + do { + try updateStatus(.verificationInProgress) + let result = try messenger.verifyContact(state.contact) + try updateStatus(result ? .verified : .verificationFailed) + return .success(.didVerify(.success(result))) + } catch { + try? updateStatus(.verificationFailed) + return .success(.didVerify(.failure(error.localizedDescription))) + } + } + .subscribe(on: bgQueue) + .receive(on: mainQueue) + .eraseToEffect() + + case .didVerify(let result): + state.isVerifying = false + state.result = result + return .none + } + } +} diff --git a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift deleted file mode 100644 index 1663d155f59e9c8d7eb4b542de4255021620be4c..0000000000000000000000000000000000000000 --- a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactFeature.swift +++ /dev/null @@ -1,97 +0,0 @@ -import AppCore -import ComposableArchitecture -import Foundation -import XCTestDynamicOverlay -import XXClient -import XXMessengerClient -import XXModels - -public struct VerifyContactState: Equatable { - public enum Result: Equatable { - case success(Bool) - case failure(String) - } - - public init( - contact: XXClient.Contact, - isVerifying: Bool = false, - result: Result? = nil - ) { - self.contact = contact - self.isVerifying = isVerifying - self.result = result - } - - public var contact: XXClient.Contact - public var isVerifying: Bool - public var result: Result? -} - -public enum VerifyContactAction: Equatable { - case verifyTapped - case didVerify(VerifyContactState.Result) -} - -public struct VerifyContactEnvironment { - public init( - messenger: Messenger, - db: DBManagerGetDB, - mainQueue: AnySchedulerOf<DispatchQueue>, - bgQueue: AnySchedulerOf<DispatchQueue> - ) { - self.messenger = messenger - self.db = db - self.mainQueue = mainQueue - self.bgQueue = bgQueue - } - - public var messenger: Messenger - public var db: DBManagerGetDB - public var mainQueue: AnySchedulerOf<DispatchQueue> - public var bgQueue: AnySchedulerOf<DispatchQueue> -} - -#if DEBUG -extension VerifyContactEnvironment { - public static let unimplemented = VerifyContactEnvironment( - messenger: .unimplemented, - db: .unimplemented, - mainQueue: .unimplemented, - bgQueue: .unimplemented - ) -} -#endif - -public let verifyContactReducer = Reducer<VerifyContactState, VerifyContactAction, VerifyContactEnvironment> -{ state, action, env in - switch action { - case .verifyTapped: - state.isVerifying = true - state.result = nil - return Effect.result { [state] in - func updateStatus(_ status: XXModels.Contact.AuthStatus) throws { - try env.db().bulkUpdateContacts.callAsFunction( - .init(id: [try state.contact.getId()]), - .init(authStatus: status) - ) - } - do { - try updateStatus(.verificationInProgress) - let result = try env.messenger.verifyContact(state.contact) - try updateStatus(result ? .verified : .verificationFailed) - return .success(.didVerify(.success(result))) - } catch { - try? updateStatus(.verificationFailed) - return .success(.didVerify(.failure(error.localizedDescription))) - } - } - .subscribe(on: env.bgQueue) - .receive(on: env.mainQueue) - .eraseToEffect() - - case .didVerify(let result): - state.isVerifying = false - state.result = result - return .none - } -} diff --git a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift index 32b81ab789a5408cb46f34574cca6bf7e12144c0..d2cb428c3a8189d4ddbcd6f7948573ad68f9963e 100644 --- a/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift +++ b/Examples/xx-messenger/Sources/VerifyContactFeature/VerifyContactView.swift @@ -2,20 +2,20 @@ import ComposableArchitecture import SwiftUI public struct VerifyContactView: View { - public init(store: Store<VerifyContactState, VerifyContactAction>) { + public init(store: StoreOf<VerifyContactComponent>) { self.store = store } - let store: Store<VerifyContactState, VerifyContactAction> + let store: StoreOf<VerifyContactComponent> struct ViewState: Equatable { var username: String? var email: String? var phone: String? var isVerifying: Bool - var result: VerifyContactState.Result? + var result: VerifyContactComponent.State.Result? - init(state: VerifyContactState) { + init(state: VerifyContactComponent.State) { username = try? state.contact.getFact(.username)?.value email = try? state.contact.getFact(.email)?.value phone = try? state.contact.getFact(.phone)?.value @@ -89,11 +89,10 @@ public struct VerifyContactView: View { public struct VerifyContactView_Previews: PreviewProvider { public static var previews: some View { VerifyContactView(store: Store( - initialState: VerifyContactState( + initialState: VerifyContactComponent.State( contact: .unimplemented("contact-data".data(using: .utf8)!) ), - reducer: .empty, - environment: () + reducer: EmptyReducer() )) } } diff --git a/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift b/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactComponentTests.swift similarity index 78% rename from Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift rename to Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactComponentTests.swift index ceaa61cc3f215234aea66381b4c7dc17965bb1a4..5548c66cb642b244301f022129c11fe30d9bec6d 100644 --- a/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactFeatureTests.swift +++ b/Examples/xx-messenger/Tests/VerifyContactFeatureTests/VerifyContactComponentTests.swift @@ -5,31 +5,30 @@ import XXClient import XXModels @testable import VerifyContactFeature -final class VerifyContactFeatureTests: XCTestCase { +final class VerifyContactComponentTests: XCTestCase { func testVerify() { var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!) let contactId = "contact-id".data(using: .utf8)! contact.getIdFromContact.run = { _ in contactId } let store = TestStore( - initialState: VerifyContactState( + initialState: VerifyContactComponent.State( contact: contact ), - reducer: verifyContactReducer, - environment: .unimplemented + reducer: VerifyContactComponent() ) var didVerifyContact: [XXClient.Contact] = [] var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = [] var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = [] - store.environment.mainQueue = .immediate - store.environment.bgQueue = .immediate - store.environment.messenger.verifyContact.run = { contact in + store.dependencies.appDependencies.mainQueue = .immediate + store.dependencies.appDependencies.bgQueue = .immediate + store.dependencies.appDependencies.messenger.verifyContact.run = { contact in didVerifyContact.append(contact) return true } - store.environment.db.run = { + store.dependencies.appDependencies.dbManager.getDB.run = { var db: Database = .unimplemented db.bulkUpdateContacts.run = { query, assignments in didBulkUpdateContactsWithQuery.append(query) @@ -66,24 +65,23 @@ final class VerifyContactFeatureTests: XCTestCase { contact.getIdFromContact.run = { _ in contactId } let store = TestStore( - initialState: VerifyContactState( + initialState: VerifyContactComponent.State( contact: contact ), - reducer: verifyContactReducer, - environment: .unimplemented + reducer: VerifyContactComponent() ) var didVerifyContact: [XXClient.Contact] = [] var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = [] var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = [] - store.environment.mainQueue = .immediate - store.environment.bgQueue = .immediate - store.environment.messenger.verifyContact.run = { contact in + store.dependencies.appDependencies.mainQueue = .immediate + store.dependencies.appDependencies.bgQueue = .immediate + store.dependencies.appDependencies.messenger.verifyContact.run = { contact in didVerifyContact.append(contact) return false } - store.environment.db.run = { + store.dependencies.appDependencies.dbManager.getDB.run = { var db: Database = .unimplemented db.bulkUpdateContacts.run = { query, assignments in didBulkUpdateContactsWithQuery.append(query) @@ -120,11 +118,10 @@ final class VerifyContactFeatureTests: XCTestCase { contact.getIdFromContact.run = { _ in contactId } let store = TestStore( - initialState: VerifyContactState( + initialState: VerifyContactComponent.State( contact: contact ), - reducer: verifyContactReducer, - environment: .unimplemented + reducer: VerifyContactComponent() ) struct Failure: Error {} @@ -133,10 +130,10 @@ final class VerifyContactFeatureTests: XCTestCase { var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = [] var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = [] - store.environment.mainQueue = .immediate - store.environment.bgQueue = .immediate - store.environment.messenger.verifyContact.run = { _ in throw error } - store.environment.db.run = { + store.dependencies.appDependencies.mainQueue = .immediate + store.dependencies.appDependencies.bgQueue = .immediate + store.dependencies.appDependencies.messenger.verifyContact.run = { _ in throw error } + store.dependencies.appDependencies.dbManager.getDB.run = { var db: Database = .unimplemented db.bulkUpdateContacts.run = { query, assignments in didBulkUpdateContactsWithQuery.append(query)