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

Present Contact from Contacts

parent 300a762a
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!75Messenger example - contacts list
......@@ -117,6 +117,7 @@ let package = Package(
name: "ContactsFeature",
dependencies: [
.target(name: "AppCore"),
.target(name: "ContactFeature"),
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
.product(name: "ComposablePresentation", package: "swift-composable-presentation"),
.product(name: "XXModels", package: "client-ios-db"),
......
......@@ -19,6 +19,21 @@ extension AppEnvironment {
let mainQueue = DispatchQueue.main.eraseToAnyScheduler()
let bgQueue = DispatchQueue.global(qos: .background).eraseToAnyScheduler()
let contactEnvironment = ContactEnvironment(
messenger: messenger,
db: dbManager.getDB,
mainQueue: mainQueue,
bgQueue: bgQueue,
sendRequest: {
SendRequestEnvironment(
messenger: messenger,
db: dbManager.getDB,
mainQueue: mainQueue,
bgQueue: bgQueue
)
}
)
return AppEnvironment(
dbManager: dbManager,
messenger: messenger,
......@@ -53,7 +68,8 @@ extension AppEnvironment {
ContactsEnvironment(
db: dbManager.getDB,
mainQueue: mainQueue,
bgQueue: bgQueue
bgQueue: bgQueue,
contact: { contactEnvironment }
)
},
userSearch: {
......@@ -61,22 +77,7 @@ extension AppEnvironment {
messenger: messenger,
mainQueue: mainQueue,
bgQueue: bgQueue,
contact: {
ContactEnvironment(
messenger: messenger,
db: dbManager.getDB,
mainQueue: mainQueue,
bgQueue: bgQueue,
sendRequest: {
SendRequestEnvironment(
messenger: messenger,
db: dbManager.getDB,
mainQueue: mainQueue,
bgQueue: bgQueue
)
}
)
}
contact: { contactEnvironment }
)
}
)
......
import AppCore
import ComposableArchitecture
import ComposablePresentation
import ContactFeature
import Foundation
import XCTestDynamicOverlay
import XXModels
public struct ContactsState: Equatable {
public init(
contacts: IdentifiedArrayOf<Contact> = []
contacts: IdentifiedArrayOf<Contact> = [],
contact: ContactState? = nil
) {
self.contacts = contacts
self.contact = contact
}
public var contacts: IdentifiedArrayOf<XXModels.Contact>
public var contact: ContactState?
}
public enum ContactsAction: Equatable {
case start
case didFetchContacts([XXModels.Contact])
case contactSelected(XXModels.Contact)
case contactDismissed
case contact(ContactAction)
}
public struct ContactsEnvironment {
public init(
db: DBManagerGetDB,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
bgQueue: AnySchedulerOf<DispatchQueue>,
contact: @escaping () -> ContactEnvironment
) {
self.db = db
self.mainQueue = mainQueue
self.bgQueue = bgQueue
self.contact = contact
}
public var db: DBManagerGetDB
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
public var contact: () -> ContactEnvironment
}
#if DEBUG
......@@ -40,7 +51,8 @@ extension ContactsEnvironment {
public static let unimplemented = ContactsEnvironment(
db: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
bgQueue: .unimplemented,
contact: { .unimplemented }
)
}
#endif
......@@ -61,5 +73,23 @@ public let contactsReducer = Reducer<ContactsState, ContactsAction, ContactsEnvi
case .didFetchContacts(let contacts):
state.contacts = IdentifiedArray(uniqueElements: contacts)
return .none
case .contactSelected(let contact):
state.contact = ContactState(id: contact.id, dbContact: contact)
return .none
case .contactDismissed:
state.contact = nil
return .none
case .contact(_):
return .none
}
}
.presenting(
contactReducer,
state: .keyPath(\.contact),
id: .keyPath(\.?.id),
action: /ContactsAction.contact,
environment: { $0.contact() }
)
import AppCore
import ComposableArchitecture
import ComposablePresentation
import ContactFeature
import SwiftUI
import XXModels
......@@ -24,7 +26,7 @@ public struct ContactsView: View {
ForEach(viewStore.contacts) { contact in
Section {
Button {
// TODO:
viewStore.send(.contactSelected(contact))
} label: {
HStack {
VStack(alignment: .leading, spacing: 8) {
......@@ -44,6 +46,14 @@ public struct ContactsView: View {
}
.navigationTitle("Contacts")
.task { viewStore.send(.start) }
.background(NavigationLinkWithStore(
store.scope(
state: \.contact,
action: ContactsAction.contact
),
onDeactivate: { viewStore.send(.contactDismissed) },
destination: ContactView.init(store:)
))
}
}
}
......
import Combine
import ComposableArchitecture
import ContactFeature
import CustomDump
import XCTest
import XXModels
......@@ -44,4 +45,35 @@ final class ContactsFeatureTests: XCTestCase {
contactsPublisher.send(completion: .finished)
}
func testSelectContact() {
let store = TestStore(
initialState: ContactsState(),
reducer: contactsReducer,
environment: .unimplemented
)
let contact = XXModels.Contact(id: "id".data(using: .utf8)!)
store.send(.contactSelected(contact)) {
$0.contact = ContactState(id: contact.id, dbContact: contact)
}
}
func testDismissContact() {
let store = TestStore(
initialState: ContactsState(
contact: ContactState(
id: "id".data(using: .utf8)!,
dbContact: Contact(id: "id".data(using: .utf8)!)
)
),
reducer: contactsReducer,
environment: .unimplemented
)
store.send(.contactDismissed) {
$0.contact = nil
}
}
}
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