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

Present contact from search results

parent b5bbc0ca
Branches
Tags
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.
...@@ -69,6 +69,7 @@ let package = Package( ...@@ -69,6 +69,7 @@ let package = Package(
name: "AppFeature", name: "AppFeature",
dependencies: [ dependencies: [
.target(name: "AppCore"), .target(name: "AppCore"),
.target(name: "ContactFeature"),
.target(name: "HomeFeature"), .target(name: "HomeFeature"),
.target(name: "RegisterFeature"), .target(name: "RegisterFeature"),
.target(name: "RestoreFeature"), .target(name: "RestoreFeature"),
...@@ -158,6 +159,7 @@ let package = Package( ...@@ -158,6 +159,7 @@ let package = Package(
.target( .target(
name: "UserSearchFeature", name: "UserSearchFeature",
dependencies: [ dependencies: [
.target(name: "ContactFeature"),
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
.product(name: "ComposablePresentation", package: "swift-composable-presentation"), .product(name: "ComposablePresentation", package: "swift-composable-presentation"),
.product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
......
...@@ -52,11 +52,10 @@ extension AppEnvironment { ...@@ -52,11 +52,10 @@ extension AppEnvironment {
mainQueue: mainQueue, mainQueue: mainQueue,
bgQueue: bgQueue, bgQueue: bgQueue,
result: { result: {
UserSearchResultEnvironment( UserSearchResultEnvironment()
db: dbManager.getDB, },
mainQueue: mainQueue, contact: {
bgQueue: bgQueue ContactEnvironment()
)
} }
) )
} }
......
import ComposableArchitecture import ComposableArchitecture
import ComposablePresentation import ComposablePresentation
import ContactFeature
import Foundation import Foundation
import XCTestDynamicOverlay import XCTestDynamicOverlay
import XXClient import XXClient
...@@ -17,13 +18,15 @@ public struct UserSearchState: Equatable { ...@@ -17,13 +18,15 @@ public struct UserSearchState: Equatable {
query: MessengerSearchUsers.Query = .init(), query: MessengerSearchUsers.Query = .init(),
isSearching: Bool = false, isSearching: Bool = false,
failure: String? = nil, failure: String? = nil,
results: IdentifiedArrayOf<UserSearchResultState> = [] results: IdentifiedArrayOf<UserSearchResultState> = [],
contact: ContactState? = nil
) { ) {
self.focusedField = focusedField self.focusedField = focusedField
self.query = query self.query = query
self.isSearching = isSearching self.isSearching = isSearching
self.failure = failure self.failure = failure
self.results = results self.results = results
self.contact = contact
} }
@BindableState public var focusedField: Field? @BindableState public var focusedField: Field?
...@@ -31,14 +34,17 @@ public struct UserSearchState: Equatable { ...@@ -31,14 +34,17 @@ public struct UserSearchState: Equatable {
public var isSearching: Bool public var isSearching: Bool
public var failure: String? public var failure: String?
public var results: IdentifiedArrayOf<UserSearchResultState> public var results: IdentifiedArrayOf<UserSearchResultState>
public var contact: ContactState?
} }
public enum UserSearchAction: Equatable, BindableAction { public enum UserSearchAction: Equatable, BindableAction {
case searchTapped case searchTapped
case didFail(String) case didFail(String)
case didSucceed([Contact]) case didSucceed([Contact])
case didDismissContact
case binding(BindingAction<UserSearchState>) case binding(BindingAction<UserSearchState>)
case result(id: UserSearchResultState.ID, action: UserSearchResultAction) case result(id: UserSearchResultState.ID, action: UserSearchResultAction)
case contact(ContactAction)
} }
public struct UserSearchEnvironment { public struct UserSearchEnvironment {
...@@ -46,18 +52,21 @@ public struct UserSearchEnvironment { ...@@ -46,18 +52,21 @@ public struct UserSearchEnvironment {
messenger: Messenger, messenger: Messenger,
mainQueue: AnySchedulerOf<DispatchQueue>, mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>, bgQueue: AnySchedulerOf<DispatchQueue>,
result: @escaping () -> UserSearchResultEnvironment result: @escaping () -> UserSearchResultEnvironment,
contact: @escaping () -> ContactEnvironment
) { ) {
self.messenger = messenger self.messenger = messenger
self.mainQueue = mainQueue self.mainQueue = mainQueue
self.bgQueue = bgQueue self.bgQueue = bgQueue
self.result = result self.result = result
self.contact = contact
} }
public var messenger: Messenger public var messenger: Messenger
public var mainQueue: AnySchedulerOf<DispatchQueue> public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue> public var bgQueue: AnySchedulerOf<DispatchQueue>
public var result: () -> UserSearchResultEnvironment public var result: () -> UserSearchResultEnvironment
public var contact: () -> ContactEnvironment
} }
#if DEBUG #if DEBUG
...@@ -66,7 +75,8 @@ extension UserSearchEnvironment { ...@@ -66,7 +75,8 @@ extension UserSearchEnvironment {
messenger: .unimplemented, messenger: .unimplemented,
mainQueue: .unimplemented, mainQueue: .unimplemented,
bgQueue: .unimplemented, bgQueue: .unimplemented,
result: { .unimplemented } result: { .unimplemented },
contact: { .unimplemented }
) )
} }
#endif #endif
...@@ -105,7 +115,15 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe ...@@ -105,7 +115,15 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe
state.results = [] state.results = []
return .none return .none
case .binding(_), .result(_, _): case .didDismissContact:
state.contact = nil
return .none
case .result(let id, action: .tapped):
state.contact = ContactState()
return .none
case .binding(_), .result(_, _), .contact(_):
return .none return .none
} }
} }
...@@ -116,3 +134,10 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe ...@@ -116,3 +134,10 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe
action: /UserSearchAction.result(id:action:), action: /UserSearchAction.result(id:action:),
environment: { $0.result() } environment: { $0.result() }
) )
.presenting(
contactReducer,
state: .keyPath(\.contact),
id: .notNil(), // TODO: use Contact.ID
action: /UserSearchAction.contact,
environment: { $0.contact() }
)
import ComposableArchitecture import ComposableArchitecture
import ComposablePresentation
import ContactFeature
import SwiftUI import SwiftUI
import XXMessengerClient import XXMessengerClient
...@@ -96,6 +98,14 @@ public struct UserSearchView: View { ...@@ -96,6 +98,14 @@ public struct UserSearchView: View {
.onChange(of: viewStore.focusedField) { focusedField = $0 } .onChange(of: viewStore.focusedField) { focusedField = $0 }
.onChange(of: focusedField) { viewStore.send(.set(\.$focusedField, $0)) } .onChange(of: focusedField) { viewStore.send(.set(\.$focusedField, $0)) }
.navigationTitle("User Search") .navigationTitle("User Search")
.background(NavigationLinkWithStore(
store.scope(
state: \.contact,
action: UserSearchAction.contact
),
onDeactivate: { viewStore.send(.didDismissContact) },
destination: ContactView.init(store:)
))
} }
} }
} }
......
import ComposableArchitecture import ComposableArchitecture
import ContactFeature
import XCTest import XCTest
import XXClient import XXClient
import XXMessengerClient import XXMessengerClient
...@@ -87,4 +88,37 @@ final class UserSearchFeatureTests: XCTestCase { ...@@ -87,4 +88,37 @@ final class UserSearchFeatureTests: XCTestCase {
$0.results = [] $0.results = []
} }
} }
func testResultTapped() {
let store = TestStore(
initialState: UserSearchState(
results: [
.init(
id: "contact-id".data(using: .utf8)!,
xxContact: .unimplemented("contact-data".data(using: .utf8)!)
)
]
),
reducer: userSearchReducer,
environment: .unimplemented
)
store.send(.result(id: "contact-id".data(using: .utf8)!, action: .tapped)) {
$0.contact = ContactState()
}
}
func testDismissingContact() {
let store = TestStore(
initialState: UserSearchState(
contact: ContactState()
),
reducer: userSearchReducer,
environment: .unimplemented
)
store.send(.didDismissContact) {
$0.contact = nil
}
}
} }
import Combine
import ComposableArchitecture import ComposableArchitecture
import XCTest import XCTest
import XCTestDynamicOverlay import XCTestDynamicOverlay
import XXClient import XXClient
import XXModels
@testable import UserSearchFeature @testable import UserSearchFeature
final class UserSearchResultFeatureTests: XCTestCase { final class UserSearchResultFeatureTests: XCTestCase {
...@@ -26,41 +24,14 @@ final class UserSearchResultFeatureTests: XCTestCase { ...@@ -26,41 +24,14 @@ final class UserSearchResultFeatureTests: XCTestCase {
environment: .unimplemented environment: .unimplemented
) )
var dbDidFetchContacts: [XXModels.Contact.Query] = []
let dbContactsPublisher = PassthroughSubject<[XXModels.Contact], Error>()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.db.run = {
var db: Database = .failing
db.fetchContactsPublisher.run = { query in
dbDidFetchContacts.append(query)
return dbContactsPublisher.eraseToAnyPublisher()
}
return db
}
store.send(.start) { store.send(.start) {
$0.username = "contact-username" $0.username = "contact-username"
$0.email = "contact-email" $0.email = "contact-email"
$0.phone = "contact-phone" $0.phone = "contact-phone"
} }
XCTAssertNoDifference(dbDidFetchContacts, [
.init(id: ["contact-id".data(using: .utf8)!])
])
let dbContact = XXModels.Contact(id: "contact-id".data(using: .utf8)!)
dbContactsPublisher.send([dbContact])
store.receive(.didUpdateContact(dbContact)) {
$0.dbContact = dbContact
}
dbContactsPublisher.send(completion: .finished)
} }
func testSendRequest() { func testTapped() {
let store = TestStore( let store = TestStore(
initialState: UserSearchResultState( initialState: UserSearchResultState(
id: "contact-id".data(using: .utf8)!, id: "contact-id".data(using: .utf8)!,
...@@ -70,6 +41,6 @@ final class UserSearchResultFeatureTests: XCTestCase { ...@@ -70,6 +41,6 @@ final class UserSearchResultFeatureTests: XCTestCase {
environment: .unimplemented environment: .unimplemented
) )
store.send(.sendRequestButtonTapped) store.send(.tapped)
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment