From d107bb5820e4524b366091945b222db090180ea2 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Thu, 8 Sep 2022 12:18:18 +0200 Subject: [PATCH] Remove UserSearchResultFeature --- .../AppFeature/AppEnvironment+Live.swift | 3 - .../UserSearchFeature/UserSearchFeature.swift | 54 ++++++++++---- .../UserSearchResultFeature.swift | 55 -------------- .../UserSearchResultView.swift | 74 ------------------- .../UserSearchFeature/UserSearchView.swift | 37 ++++++++-- .../UserSearchFeatureTests.swift | 37 ++++++++-- .../UserSearchResultFeatureTests.swift | 46 ------------ 7 files changed, 100 insertions(+), 206 deletions(-) delete mode 100644 Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultFeature.swift delete mode 100644 Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultView.swift delete mode 100644 Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift index 298cb9f6..01e31519 100644 --- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift +++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift @@ -53,9 +53,6 @@ extension AppEnvironment { messenger: messenger, mainQueue: mainQueue, bgQueue: bgQueue, - result: { - UserSearchResultEnvironment() - }, contact: { ContactEnvironment( messenger: messenger, diff --git a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift index 1b10c1b3..d49b4440 100644 --- a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift +++ b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift @@ -13,12 +13,38 @@ public struct UserSearchState: Equatable { case phone } + public struct Result: Equatable, Identifiable { + public init( + id: Data, + xxContact: XXClient.Contact, + username: String? = nil, + email: String? = nil, + phone: String? = nil + ) { + self.id = id + self.xxContact = xxContact + self.username = username + self.email = email + self.phone = phone + } + + public var id: Data + public var xxContact: XXClient.Contact + public var username: String? + public var email: String? + public var phone: String? + + public var hasFacts: Bool { + username != nil || email != nil || phone != nil + } + } + public init( focusedField: Field? = nil, query: MessengerSearchUsers.Query = .init(), isSearching: Bool = false, failure: String? = nil, - results: IdentifiedArrayOf<UserSearchResultState> = [], + results: IdentifiedArrayOf<Result> = [], contact: ContactState? = nil ) { self.focusedField = focusedField @@ -33,7 +59,7 @@ public struct UserSearchState: Equatable { @BindableState public var query: MessengerSearchUsers.Query public var isSearching: Bool public var failure: String? - public var results: IdentifiedArrayOf<UserSearchResultState> + public var results: IdentifiedArrayOf<Result> public var contact: ContactState? } @@ -42,8 +68,8 @@ public enum UserSearchAction: Equatable, BindableAction { case didFail(String) case didSucceed([Contact]) case didDismissContact + case resultTapped(id: Data) case binding(BindingAction<UserSearchState>) - case result(id: UserSearchResultState.ID, action: UserSearchResultAction) case contact(ContactAction) } @@ -52,20 +78,17 @@ public struct UserSearchEnvironment { messenger: Messenger, mainQueue: AnySchedulerOf<DispatchQueue>, bgQueue: AnySchedulerOf<DispatchQueue>, - result: @escaping () -> UserSearchResultEnvironment, contact: @escaping () -> ContactEnvironment ) { self.messenger = messenger self.mainQueue = mainQueue self.bgQueue = bgQueue - self.result = result self.contact = contact } public var messenger: Messenger public var mainQueue: AnySchedulerOf<DispatchQueue> public var bgQueue: AnySchedulerOf<DispatchQueue> - public var result: () -> UserSearchResultEnvironment public var contact: () -> ContactEnvironment } @@ -75,7 +98,6 @@ extension UserSearchEnvironment { messenger: .unimplemented, mainQueue: .unimplemented, bgQueue: .unimplemented, - result: { .unimplemented }, contact: { .unimplemented } ) } @@ -105,7 +127,13 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe state.failure = nil state.results = IdentifiedArray(uniqueElements: contacts.compactMap { contact in guard let id = try? contact.getId() else { return nil } - return UserSearchResultState(id: id, xxContact: contact) + return UserSearchState.Result( + id: id, + xxContact: contact, + username: try? contact.getFact(.username)?.fact, + email: try? contact.getFact(.email)?.fact, + phone: try? contact.getFact(.phone)?.fact + ) }) return .none @@ -119,24 +147,18 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe state.contact = nil return .none - case .result(let id, action: .tapped): + case .resultTapped(let id): state.contact = ContactState( id: id, xxContact: state.results[id: id]?.xxContact ) return .none - case .binding(_), .result(_, _), .contact(_): + case .binding(_), .contact(_): return .none } } .binding() -.presenting( - forEach: userSearchResultReducer, - state: \.results, - action: /UserSearchAction.result(id:action:), - environment: { $0.result() } -) .presenting( contactReducer, state: .keyPath(\.contact), diff --git a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultFeature.swift b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultFeature.swift deleted file mode 100644 index 839e6886..00000000 --- a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultFeature.swift +++ /dev/null @@ -1,55 +0,0 @@ -import ComposableArchitecture -import Foundation -import XCTestDynamicOverlay -import XXClient - -public struct UserSearchResultState: Equatable, Identifiable { - public init( - id: Data, - xxContact: XXClient.Contact, - username: String? = nil, - email: String? = nil, - phone: String? = nil - ) { - self.id = id - self.xxContact = xxContact - self.username = username - self.email = email - self.phone = phone - } - - public var id: Data - public var xxContact: XXClient.Contact - public var username: String? - public var email: String? - public var phone: String? -} - -public enum UserSearchResultAction: Equatable { - case start - case tapped -} - -public struct UserSearchResultEnvironment { - public init() {} -} - -#if DEBUG -extension UserSearchResultEnvironment { - public static let unimplemented = UserSearchResultEnvironment() -} -#endif - -public let userSearchResultReducer = Reducer<UserSearchResultState, UserSearchResultAction, UserSearchResultEnvironment> -{ state, action, env in - switch action { - case .start: - state.username = try? state.xxContact.getFact(.username)?.fact - state.email = try? state.xxContact.getFact(.email)?.fact - state.phone = try? state.xxContact.getFact(.phone)?.fact - return .none - - case .tapped: - return .none - } -} diff --git a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultView.swift b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultView.swift deleted file mode 100644 index fd29a84f..00000000 --- a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchResultView.swift +++ /dev/null @@ -1,74 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import XXModels - -public struct UserSearchResultView: View { - public init(store: Store<UserSearchResultState, UserSearchResultAction>) { - self.store = store - } - - let store: Store<UserSearchResultState, UserSearchResultAction> - - struct ViewState: Equatable { - var username: String? - var email: String? - var phone: String? - - init(state: UserSearchResultState) { - username = state.username - email = state.email - phone = state.phone - } - - var isEmpty: Bool { - username == nil && email == nil && phone == nil - } - } - - public var body: some View { - WithViewStore(store.scope(state: ViewState.init)) { viewStore in - Section { - Button { - viewStore.send(.tapped) - } label: { - HStack { - VStack { - if viewStore.isEmpty { - Image(systemName: "questionmark") - .frame(maxWidth: .infinity) - } else { - if let username = viewStore.username { - Text(username) - } - if let email = viewStore.email { - Text(email) - } - if let phone = viewStore.phone { - Text(phone) - } - } - } - Spacer() - Image(systemName: "chevron.forward") - } - } - } - .task { viewStore.send(.start) } - } - } -} - -#if DEBUG -public struct UserSearchResultView_Previews: PreviewProvider { - public static var previews: some View { - UserSearchResultView(store: Store( - initialState: UserSearchResultState( - id: "contact-id".data(using: .utf8)!, - xxContact: .unimplemented("contact-data".data(using: .utf8)!) - ), - reducer: .empty, - environment: () - )) - } -} -#endif diff --git a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift index f0416b3a..9f76ed0a 100644 --- a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift +++ b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift @@ -17,12 +17,14 @@ public struct UserSearchView: View { var query: MessengerSearchUsers.Query var isSearching: Bool var failure: String? + var results: IdentifiedArrayOf<UserSearchState.Result> init(state: UserSearchState) { focusedField = state.focusedField query = state.query isSearching = state.isSearching failure = state.failure + results = state.results } } @@ -87,13 +89,34 @@ public struct UserSearchView: View { } } - ForEachStore( - store.scope( - state: \.results, - action: UserSearchAction.result(id:action:) - ), - content: UserSearchResultView.init(store:) - ) + ForEach(viewStore.results) { result in + Section { + Button { + viewStore.send(.resultTapped(id: result.id)) + } label: { + HStack { + VStack { + if result.hasFacts { + if let username = result.username { + Text(username) + } + if let email = result.email { + Text(email) + } + if let phone = result.phone { + Text(phone) + } + } else { + Image(systemName: "questionmark") + .frame(maxWidth: .infinity) + } + } + Spacer() + Image(systemName: "chevron.forward") + } + } + } + } } .onChange(of: viewStore.focusedField) { focusedField = $0 } .onChange(of: focusedField) { viewStore.send(.set(\.$focusedField, $0)) } diff --git a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift index c457327c..f8f482f6 100644 --- a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift +++ b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift @@ -20,12 +20,26 @@ final class UserSearchFeatureTests: XCTestCase { var contact1 = Contact.unimplemented("contact-1".data(using: .utf8)!) contact1.getIdFromContact.run = { _ in "contact-1-id".data(using: .utf8)! } - var contact2 = Contact.unimplemented("contact-1".data(using: .utf8)!) + contact1.getFactsFromContact.run = { _ in + [ + Fact(type: .username, value: "contact-1-username"), + Fact(type: .email, value: "contact-1-email"), + Fact(type: .phone, value: "contact-1-phone"), + ] + } + var contact2 = Contact.unimplemented("contact-2".data(using: .utf8)!) contact2.getIdFromContact.run = { _ in "contact-2-id".data(using: .utf8)! } + contact2.getFactsFromContact.run = { _ in + [ + Fact(type: .username, value: "contact-2-username"), + ] + } var contact3 = Contact.unimplemented("contact-3".data(using: .utf8)!) contact3.getIdFromContact.run = { _ in throw GetIdFromContactError() } + contact3.getFactsFromContact.run = { _ in [] } var contact4 = Contact.unimplemented("contact-4".data(using: .utf8)!) contact4.getIdFromContact.run = { _ in "contact-4-id".data(using: .utf8)! } + contact4.getFactsFromContact.run = { _ in throw GetFactsFromContactError() } let contacts = [contact1, contact2, contact3, contact4] store.environment.bgQueue = .immediate @@ -54,9 +68,22 @@ final class UserSearchFeatureTests: XCTestCase { $0.isSearching = false $0.failure = nil $0.results = [ - .init(id: "contact-1-id".data(using: .utf8)!, xxContact: contact1), - .init(id: "contact-2-id".data(using: .utf8)!, xxContact: contact2), - .init(id: "contact-4-id".data(using: .utf8)!, xxContact: contact4) + .init( + id: "contact-1-id".data(using: .utf8)!, + xxContact: contact1, + username: "contact-1-username", + email: "contact-1-email", + phone: "contact-1-phone" + ), + .init( + id: "contact-2-id".data(using: .utf8)!, + xxContact: contact2, + username: "contact-2-username" + ), + .init( + id: "contact-4-id".data(using: .utf8)!, + xxContact: contact4 + ) ] } } @@ -103,7 +130,7 @@ final class UserSearchFeatureTests: XCTestCase { environment: .unimplemented ) - store.send(.result(id: "contact-id".data(using: .utf8)!, action: .tapped)) { + store.send(.resultTapped(id: "contact-id".data(using: .utf8)!)) { $0.contact = ContactState( id: "contact-id".data(using: .utf8)!, xxContact: .unimplemented("contact-data".data(using: .utf8)!) diff --git a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift deleted file mode 100644 index c8f2a99b..00000000 --- a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift +++ /dev/null @@ -1,46 +0,0 @@ -import ComposableArchitecture -import XCTest -import XCTestDynamicOverlay -import XXClient -@testable import UserSearchFeature - -final class UserSearchResultFeatureTests: XCTestCase { - func testStart() { - var contact = Contact.unimplemented("contact-data".data(using: .utf8)!) - contact.getFactsFromContact.run = { _ in - [ - Fact(fact: "contact-username", type: 0), - Fact(fact: "contact-email", type: 1), - Fact(fact: "contact-phone", type: 2), - ] - } - - let store = TestStore( - initialState: UserSearchResultState( - id: "contact-id".data(using: .utf8)!, - xxContact: contact - ), - reducer: userSearchResultReducer, - environment: .unimplemented - ) - - store.send(.start) { - $0.username = "contact-username" - $0.email = "contact-email" - $0.phone = "contact-phone" - } - } - - func testTapped() { - let store = TestStore( - initialState: UserSearchResultState( - id: "contact-id".data(using: .utf8)!, - xxContact: .unimplemented("contact-data".data(using: .utf8)!) - ), - reducer: userSearchResultReducer, - environment: .unimplemented - ) - - store.send(.tapped) - } -} -- GitLab