Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import AppCore
import Combine
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct SendRequestComponent: ReducerProtocol {
public struct State: Equatable {
public init(
contact: XXClient.Contact,
myContact: XXClient.Contact? = nil,
sendUsername: Bool = true,
sendEmail: Bool = true,
sendPhone: Bool = true,
isSending: Bool = false,
failure: String? = nil
) {
self.contact = contact
self.myContact = myContact
self.sendUsername = sendUsername
self.sendEmail = sendEmail
self.sendPhone = sendPhone
self.isSending = isSending
self.failure = failure
}
public var contact: XXClient.Contact
public var myContact: XXClient.Contact?
@BindableState public var sendUsername: Bool
@BindableState public var sendEmail: Bool
@BindableState public var sendPhone: Bool
public var isSending: Bool
public var failure: String?
}
public enum Action: Equatable, BindableAction {
case start
case sendTapped
case sendSucceeded
case sendFailed(String)
case binding(BindingAction<State>)
case myContactFetched(XXClient.Contact)
case myContactFetchFailed(NSError)
}
public init() {}
@Dependency(\.app.messenger) var messenger: Messenger
@Dependency(\.app.dbManager.getDB) var db: DBManagerGetDB
@Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
@Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
public var body: some ReducerProtocol<State, Action> {
BindingReducer()
Reduce { state, action in
switch action {
case .start:
return Effect.run { subscriber in
do {
let contact = try messenger.myContact()
subscriber.send(.myContactFetched(contact))
} catch {
subscriber.send(.myContactFetchFailed(error as NSError))
}
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.receive(on: mainQueue)
.subscribe(on: bgQueue)
.eraseToEffect()
case .myContactFetched(let contact):
state.myContact = contact
state.failure = nil
return .none
case .myContactFetchFailed(let failure):
state.myContact = nil
state.failure = failure.localizedDescription
return .none
case .sendTapped:
state.isSending = true
state.failure = nil
return .result { [state] in
func updateAuthStatus(_ authStatus: XXModels.Contact.AuthStatus) throws {
try db().bulkUpdateContacts(
.init(id: [try state.contact.getId()]),
.init(authStatus: authStatus)
)
}
do {
try updateAuthStatus(.requesting)
let myFacts = try state.myContact?.getFacts() ?? []
var includedFacts: [Fact] = []
if state.sendUsername, let fact = myFacts.get(.username) {
includedFacts.append(fact)
}
if state.sendEmail, let fact = myFacts.get(.email) {
includedFacts.append(fact)
}
if state.sendPhone, let fact = myFacts.get(.phone) {
includedFacts.append(fact)
}
_ = try messenger.e2e.tryGet().requestAuthenticatedChannel(
partner: state.contact,
myFacts: includedFacts
)
try updateAuthStatus(.requested)
return .success(.sendSucceeded)
} catch {
try? updateAuthStatus(.requestFailed)
return .success(.sendFailed(error.localizedDescription))
}
}
.subscribe(on: bgQueue)
.receive(on: mainQueue)
.eraseToEffect()
case .sendSucceeded:
state.isSending = false
state.failure = nil
return .none
case .sendFailed(let failure):
state.isSending = false
state.failure = failure
return .none
case .binding(_):
return .none
}
}
}
}