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

Update AppFeature

parent a82b0222
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!19Update example app
......@@ -70,13 +70,7 @@ let package = Package(
dependencies: [
.target(name: "ErrorFeature"),
.target(name: "LandingFeature"),
.target(name: "MyContactFeature"),
.target(name: "MyIdentityFeature"),
.target(name: "SessionFeature"),
.product(
name: "ElixxirDAppsSDK",
package: "elixxir-dapps-sdk-swift"
),
.product(
name: "ComposableArchitecture",
package: "swift-composable-architecture"
......@@ -85,10 +79,18 @@ let package = Package(
name: "ComposablePresentation",
package: "swift-composable-presentation"
),
.product(
name: "ElixxirDAppsSDK",
package: "elixxir-dapps-sdk-swift"
),
.product(
name: "KeychainAccess",
package: "KeychainAccess"
),
.product(
name: "XCTestDynamicOverlay",
package: "xctest-dynamic-overlay"
),
],
swiftSettings: swiftSettings
),
......
......@@ -3,8 +3,6 @@ import ComposableArchitecture
import ElixxirDAppsSDK
import ErrorFeature
import LandingFeature
import MyContactFeature
import MyIdentityFeature
import SessionFeature
import SwiftUI
......@@ -23,9 +21,7 @@ struct App: SwiftUI.App {
extension AppEnvironment {
static func live() -> AppEnvironment {
let clientSubject = CurrentValueSubject<Client?, Never>(nil)
let identitySubject = CurrentValueSubject<Identity?, Never>(nil)
let contactSubject = CurrentValueSubject<Data?, Never>(nil)
let cmixSubject = CurrentValueSubject<Cmix?, Never>(nil)
let mainScheduler = DispatchQueue.main.eraseToAnyScheduler()
let bgScheduler = DispatchQueue(
label: "xx.network.dApps.ExampleApp.bg",
......@@ -34,41 +30,23 @@ extension AppEnvironment {
return AppEnvironment(
makeId: UUID.init,
hasClient: clientSubject.map { $0 != nil }.eraseToAnyPublisher(),
hasCmix: { cmixSubject.map { $0 != nil }.eraseToAnyPublisher() },
mainScheduler: mainScheduler,
landing: LandingEnvironment(
clientStorage: .live(
cmixManager: .live(
passwordStorage: .keychain
),
setClient: { clientSubject.send($0) },
setCmix: { cmixSubject.value = $0 },
bgScheduler: bgScheduler,
mainScheduler: mainScheduler,
error: ErrorEnvironment()
),
session: SessionEnvironment(
getClient: { clientSubject.value },
bgScheduler: bgScheduler,
mainScheduler: mainScheduler,
makeId: UUID.init,
error: ErrorEnvironment(),
myIdentity: MyIdentityEnvironment(
getClient: { clientSubject.value },
observeIdentity: { identitySubject.eraseToAnyPublisher() },
updateIdentity: { identitySubject.value = $0 },
bgScheduler: bgScheduler,
mainScheduler: mainScheduler,
error: ErrorEnvironment()
),
myContact: MyContactEnvironment(
getClient: { clientSubject.value },
getIdentity: { identitySubject.value },
observeContact: { contactSubject.eraseToAnyPublisher() },
updateContact: { contactSubject.value = $0 },
getCmix: { cmixSubject.value },
bgScheduler: bgScheduler,
mainScheduler: mainScheduler,
error: ErrorEnvironment()
)
)
)
}
}
......@@ -3,6 +3,7 @@ import ComposableArchitecture
import ComposablePresentation
import LandingFeature
import SessionFeature
import XCTestDynamicOverlay
struct AppState: Equatable {
enum Scene: Equatable {
......@@ -40,14 +41,14 @@ extension AppState.Scene {
enum AppAction: Equatable {
case viewDidLoad
case clientDidChange(hasClient: Bool)
case cmixDidChange(hasCmix: Bool)
case landing(LandingAction)
case session(SessionAction)
}
struct AppEnvironment {
var makeId: () -> UUID
var hasClient: AnyPublisher<Bool, Never>
var hasCmix: () -> AnyPublisher<Bool, Never>
var mainScheduler: AnySchedulerOf<DispatchQueue>
var landing: LandingEnvironment
var session: SessionEnvironment
......@@ -55,19 +56,18 @@ struct AppEnvironment {
let appReducer = Reducer<AppState, AppAction, AppEnvironment>
{ state, action, env in
enum HasCmixEffectId {}
switch action {
case .viewDidLoad:
struct HasClientEffectId: Hashable {
var id: UUID
}
return env.hasClient
return env.hasCmix()
.removeDuplicates()
.map(AppAction.clientDidChange(hasClient:))
.map(AppAction.cmixDidChange(hasCmix:))
.receive(on: env.mainScheduler)
.eraseToEffect()
.cancellable(id: HasClientEffectId(id: state.id), cancelInFlight: true)
.cancellable(id: HasCmixEffectId.self, cancelInFlight: true)
case .clientDidChange(let hasClient):
case .cmixDidChange(let hasClient):
if hasClient {
let sessionState = state.scene.asSession ?? SessionState(id: env.makeId())
state.scene = .session(sessionState)
......@@ -96,14 +96,12 @@ let appReducer = Reducer<AppState, AppAction, AppEnvironment>
environment: \.session
)
#if DEBUG
extension AppEnvironment {
static let failing = AppEnvironment(
makeId: { fatalError() },
hasClient: Empty().eraseToAnyPublisher(),
mainScheduler: .failing,
landing: .failing,
session: .failing
static let unimplemented = AppEnvironment(
makeId: XCTUnimplemented("\(Self.self).makeId"),
hasCmix: XCTUnimplemented("\(Self.self).hasCmix"),
mainScheduler: .unimplemented,
landing: .unimplemented,
session: .unimplemented
)
}
#endif
......@@ -8,45 +8,44 @@ import XCTest
final class AppFeatureTests: XCTestCase {
func testViewDidLoad() throws {
let newId = UUID()
let hasClient = PassthroughSubject<Bool, Never>()
let hasCmix = PassthroughSubject<Bool, Never>()
let mainScheduler = DispatchQueue.test
var env = AppEnvironment.failing
env.makeId = { newId }
env.hasClient = hasClient.eraseToAnyPublisher()
env.mainScheduler = mainScheduler.eraseToAnyScheduler()
let store = TestStore(
initialState: AppState(),
reducer: appReducer,
environment: env
environment: .unimplemented
)
store.environment.makeId = { newId }
store.environment.hasCmix = { hasCmix.eraseToAnyPublisher() }
store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
store.send(.viewDidLoad)
hasClient.send(false)
hasCmix.send(false)
mainScheduler.advance()
store.receive(.clientDidChange(hasClient: false))
store.receive(.cmixDidChange(hasCmix: false))
hasClient.send(true)
hasCmix.send(true)
mainScheduler.advance()
store.receive(.clientDidChange(hasClient: true)) {
store.receive(.cmixDidChange(hasCmix: true)) {
$0.scene = .session(SessionState(id: newId))
}
hasClient.send(true)
hasCmix.send(true)
mainScheduler.advance()
hasClient.send(false)
hasCmix.send(false)
mainScheduler.advance()
store.receive(.clientDidChange(hasClient: false)) {
store.receive(.cmixDidChange(hasCmix: false)) {
$0.scene = .landing(LandingState(id: newId))
}
hasClient.send(completion: .finished)
hasCmix.send(completion: .finished)
mainScheduler.advance()
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment