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

Fetch groups

parent a3e67c1f
No related branches found
No related tags found
2 merge requests!153Release 1.1.0,!149[Messenger example] create new group
import AppCore
import ComposableArchitecture
import Foundation
import XXModels
public struct GroupsComponent: ReducerProtocol {
public struct State: Equatable {
public init() {}
public init(
groups: IdentifiedArrayOf<Group> = []
) {
self.groups = groups
}
public var groups: IdentifiedArrayOf<XXModels.Group> = []
}
public enum Action: Equatable {
case start
case didFetchGroups([XXModels.Group])
case didSelectGroup(XXModels.Group)
}
public init() {}
@Dependency(\.app.dbManager.getDB) var db: DBManagerGetDB
@Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
@Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
public var body: some ReducerProtocol<State, Action> {
Reduce { state, action in
switch action {
case .start:
return Effect
.catching { try db() }
.flatMap { $0.fetchGroupsPublisher.callAsFunction(.init()) }
.assertNoFailure()
.map(Action.didFetchGroups)
.subscribe(on: bgQueue)
.receive(on: mainQueue)
.eraseToEffect()
case .didFetchGroups(let groups):
state.groups = IdentifiedArray(uniqueElements: groups)
return .none
case .didSelectGroup(_):
return .none
}
}
......
import AppCore
import ComposableArchitecture
import SwiftUI
import XXModels
public struct GroupsView: View {
public typealias Component = GroupsComponent
......@@ -12,17 +14,43 @@ public struct GroupsView: View {
struct ViewState: Equatable {
init(state: Component.State) {}
var groups: IdentifiedArrayOf<XXModels.Group> = []
}
public var body: some View {
WithViewStore(store, observe: ViewState.init) { viewStore in
Form {
ForEach(viewStore.groups) { group in
groupView(group) {
viewStore.send(.didSelectGroup(group))
}
}
}
.navigationTitle("Groups")
.task { viewStore.send(.start) }
}
}
func groupView(
_ group: XXModels.Group,
onSelect: @escaping () -> Void
) -> some View {
Section {
Button {
onSelect()
} label: {
HStack {
Label(group.name, systemImage: "person.3")
.font(.callout)
.tint(Color.primary)
Spacer()
Image(systemName: "chevron.forward")
}
GroupAuthStatusView(group.authStatus)
}
}
}
}
#if DEBUG
......
import Combine
import ComposableArchitecture
import CustomDump
import XCTest
import XXModels
@testable import GroupsFeature
final class GroupsComponentTests: XCTestCase {
enum Action: Equatable {
case didFetchGroups(XXModels.Group.Query)
}
var actions: [Action]!
override func setUp() {
actions = []
}
override func tearDown() {
actions = nil
}
func testStart() {
let groupsSubject = PassthroughSubject<[XXModels.Group], Error>()
let store = TestStore(
initialState: GroupsComponent.State(),
reducer: GroupsComponent()
)
store.dependencies.app.mainQueue = .immediate
store.dependencies.app.bgQueue = .immediate
store.dependencies.app.dbManager.getDB.run = {
var db: Database = .unimplemented
db.fetchGroupsPublisher.run = { query in
self.actions.append(.didFetchGroups(query))
return groupsSubject.eraseToAnyPublisher()
}
return db
}
store.send(.start)
XCTAssertNoDifference(actions, [
.didFetchGroups(.init())
])
let groups: [XXModels.Group] = [
.stub(1),
.stub(2),
.stub(3),
]
groupsSubject.send(groups)
store.receive(.didFetchGroups(groups)) {
$0.groups = IdentifiedArray(uniqueElements: groups)
}
groupsSubject.send(completion: .finished)
}
func testSelectGroup() {
let store = TestStore(
initialState: GroupsComponent.State(
groups: IdentifiedArray(uniqueElements: [
.stub(1),
.stub(2),
.stub(3),
])
),
reducer: GroupsComponent()
)
store.send(.didSelectGroup(.stub(2)))
}
}
private extension XXModels.Group {
static func stub(_ id: Int) -> XXModels.Group {
XXModels.Group(
id: "group-\(id)-id".data(using: .utf8)!,
name: "Group \(id)",
leaderId: "group-\(id)-leader-id".data(using: .utf8)!,
createdAt: Date(timeIntervalSince1970: TimeInterval(id * 86_400)),
authStatus: .participating,
serialized: "group-\(id)-serialized".data(using: .utf8)!
)
}
}
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