Skip to content
Snippets Groups Projects
Commit 0c2d1aca authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Embed UserSearchResultFeature in UserSearchFeature

parent 2e50e9c8
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!68Messenger example - send auth request
This commit is part of merge request !68. Comments created here will be created in the context of that merge request.
......@@ -141,6 +141,7 @@ let package = Package(
name: "UserSearchFeature",
dependencies: [
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
.product(name: "ComposablePresentation", package: "swift-composable-presentation"),
.product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
.product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
],
......
......@@ -50,7 +50,10 @@ extension AppEnvironment {
UserSearchEnvironment(
messenger: messenger,
mainQueue: mainQueue,
bgQueue: bgQueue
bgQueue: bgQueue,
result: {
UserSearchResultEnvironment()
}
)
}
)
......
import ComposableArchitecture
import ComposablePresentation
import Foundation
import XCTestDynamicOverlay
import XXClient
......@@ -11,34 +12,12 @@ public struct UserSearchState: Equatable {
case phone
}
public struct Result: Equatable, Identifiable {
public init(
id: Data,
contact: Contact,
username: String? = nil,
email: String? = nil,
phone: String? = nil
) {
self.id = id
self.contact = contact
self.username = username
self.email = email
self.phone = phone
}
public var id: Data
public var contact: XXClient.Contact
public var username: String?
public var email: String?
public var phone: String?
}
public init(
focusedField: Field? = nil,
query: MessengerSearchUsers.Query = .init(),
isSearching: Bool = false,
failure: String? = nil,
results: IdentifiedArrayOf<Result> = []
results: IdentifiedArrayOf<UserSearchResultState> = []
) {
self.focusedField = focusedField
self.query = query
......@@ -51,7 +30,7 @@ public struct UserSearchState: Equatable {
@BindableState public var query: MessengerSearchUsers.Query
public var isSearching: Bool
public var failure: String?
public var results: IdentifiedArrayOf<Result>
public var results: IdentifiedArrayOf<UserSearchResultState>
}
public enum UserSearchAction: Equatable, BindableAction {
......@@ -59,22 +38,26 @@ public enum UserSearchAction: Equatable, BindableAction {
case didFail(String)
case didSucceed([Contact])
case binding(BindingAction<UserSearchState>)
case result(id: UserSearchResultState.ID, action: UserSearchResultAction)
}
public struct UserSearchEnvironment {
public init(
messenger: Messenger,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
bgQueue: AnySchedulerOf<DispatchQueue>,
result: @escaping () -> UserSearchResultEnvironment
) {
self.messenger = messenger
self.mainQueue = mainQueue
self.bgQueue = bgQueue
self.result = result
}
public var messenger: Messenger
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
public var result: () -> UserSearchResultEnvironment
}
#if DEBUG
......@@ -82,7 +65,8 @@ extension UserSearchEnvironment {
public static let unimplemented = UserSearchEnvironment(
messenger: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
bgQueue: .unimplemented,
result: { .unimplemented }
)
}
#endif
......@@ -111,14 +95,7 @@ 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 }
let facts = (try? contact.getFacts()) ?? []
return UserSearchState.Result(
id: id,
contact: contact,
username: facts.first(where: { $0.type == 0 })?.fact,
email: facts.first(where: { $0.type == 1 })?.fact,
phone: facts.first(where: { $0.type == 2 })?.fact
)
return UserSearchResultState(id: id, contact: contact)
})
return .none
......@@ -128,8 +105,14 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe
state.results = []
return .none
case .binding(_):
case .binding(_), .result(_, _):
return .none
}
}
.binding()
.presenting(
forEach: userSearchResultReducer,
state: \.results,
action: /UserSearchAction.result(id:action:),
environment: { $0.result() }
)
......@@ -15,14 +15,12 @@ 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,23 +85,13 @@ public struct UserSearchView: View {
}
}
ForEach(viewStore.results) { result in
Section {
if let username = result.username {
Text(username)
}
if let email = result.email {
Text(email)
}
if let phone = result.phone {
Text(phone)
}
if result.username == nil, result.email == nil, result.phone == nil {
Image(systemName: "questionmark")
.frame(maxWidth: .infinity)
}
}
}
ForEachStore(
store.scope(
state: \.results,
action: UserSearchAction.result(id:action:)
),
content: UserSearchResultView.init(store:)
)
}
.onChange(of: viewStore.focusedField) { focusedField = $0 }
.onChange(of: focusedField) { viewStore.send(.set(\.$focusedField, $0)) }
......
......@@ -19,23 +19,12 @@ final class UserSearchFeatureTests: XCTestCase {
var contact1 = Contact.unimplemented("contact-1".data(using: .utf8)!)
contact1.getIdFromContact.run = { _ in "contact-1-id".data(using: .utf8)! }
contact1.getFactsFromContact.run = { _ in
[Fact(fact: "contact-1-username", type: 0),
Fact(fact: "contact-1-email", type: 1),
Fact(fact: "contact-1-phone", type: 2)]
}
var contact2 = Contact.unimplemented("contact-1".data(using: .utf8)!)
contact2.getIdFromContact.run = { _ in "contact-2-id".data(using: .utf8)! }
contact2.getFactsFromContact.run = { _ in
[Fact(fact: "contact-2-username", type: 0),
Fact(fact: "contact-2-email", type: 1),
Fact(fact: "contact-2-phone", type: 2)]
}
var contact3 = Contact.unimplemented("contact-3".data(using: .utf8)!)
contact3.getIdFromContact.run = { _ in throw GetIdFromContactError() }
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
......@@ -64,27 +53,9 @@ final class UserSearchFeatureTests: XCTestCase {
$0.isSearching = false
$0.failure = nil
$0.results = [
.init(
id: "contact-1-id".data(using: .utf8)!,
contact: contact1,
username: "contact-1-username",
email: "contact-1-email",
phone: "contact-1-phone"
),
.init(
id: "contact-2-id".data(using: .utf8)!,
contact: contact2,
username: "contact-2-username",
email: "contact-2-email",
phone: "contact-2-phone"
),
.init(
id: "contact-4-id".data(using: .utf8)!,
contact: contact4,
username: nil,
email: nil,
phone: nil
)
.init(id: "contact-1-id".data(using: .utf8)!, contact: contact1),
.init(id: "contact-2-id".data(using: .utf8)!, contact: contact2),
.init(id: "contact-4-id".data(using: .utf8)!, contact: contact4)
]
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment