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

Implement SendRequest UI

parent 4f378901
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!68Messenger example - send auth request
...@@ -164,7 +164,11 @@ let package = Package( ...@@ -164,7 +164,11 @@ let package = Package(
.target( .target(
name: "SendRequestFeature", name: "SendRequestFeature",
dependencies: [ dependencies: [
.target(name: "AppCore"),
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
.product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
.product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
.product(name: "XXModels", package: "client-ios-db"),
], ],
swiftSettings: swiftSettings swiftSettings: swiftSettings
), ),
......
...@@ -4,6 +4,7 @@ import Foundation ...@@ -4,6 +4,7 @@ import Foundation
import HomeFeature import HomeFeature
import RegisterFeature import RegisterFeature
import RestoreFeature import RestoreFeature
import SendRequestFeature
import UserSearchFeature import UserSearchFeature
import WelcomeFeature import WelcomeFeature
import XXMessengerClient import XXMessengerClient
......
...@@ -104,7 +104,11 @@ public let contactReducer = Reducer<ContactState, ContactAction, ContactEnvironm ...@@ -104,7 +104,11 @@ public let contactReducer = Reducer<ContactState, ContactAction, ContactEnvironm
.eraseToEffect() .eraseToEffect()
case .sendRequestTapped: case .sendRequestTapped:
state.sendRequest = SendRequestState() if let xxContact = state.xxContact {
state.sendRequest = SendRequestState(contact: xxContact)
} else if let marshaled = state.dbContact?.marshaled {
state.sendRequest = SendRequestState(contact: .live(marshaled))
}
return .none return .none
case .sendRequestDismissed: case .sendRequestDismissed:
......
import ComposableArchitecture import ComposableArchitecture
import XCTestDynamicOverlay import XCTestDynamicOverlay
import XXClient
import XXModels
public struct SendRequestState: Equatable { public struct SendRequestState: Equatable {
public init() {} 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 SendRequestAction: Equatable { public enum SendRequestAction: Equatable, BindableAction {
case start case start
case sendTapped
case binding(BindingAction<SendRequestState>)
} }
public struct SendRequestEnvironment { public struct SendRequestEnvironment {
...@@ -24,5 +52,11 @@ public let sendRequestReducer = Reducer<SendRequestState, SendRequestAction, Sen ...@@ -24,5 +52,11 @@ public let sendRequestReducer = Reducer<SendRequestState, SendRequestAction, Sen
switch action { switch action {
case .start: case .start:
return .none return .none
case .sendTapped:
return .none
case .binding(_):
return .none
} }
} }
import AppCore
import ComposableArchitecture import ComposableArchitecture
import SwiftUI import SwiftUI
import XXClient
public struct SendRequestView: View { public struct SendRequestView: View {
public init(store: Store<SendRequestState, SendRequestAction>) { public init(store: Store<SendRequestState, SendRequestAction>) {
...@@ -9,13 +11,101 @@ public struct SendRequestView: View { ...@@ -9,13 +11,101 @@ public struct SendRequestView: View {
let store: Store<SendRequestState, SendRequestAction> let store: Store<SendRequestState, SendRequestAction>
struct ViewState: Equatable { struct ViewState: Equatable {
init(state: SendRequestState) {} var contact: XXClient.Contact
var myContact: XXClient.Contact?
var sendUsername: Bool
var sendEmail: Bool
var sendPhone: Bool
var isSending: Bool
var failure: String?
init(state: SendRequestState) {
contact = state.contact
myContact = state.myContact
sendUsername = state.sendUsername
sendEmail = state.sendEmail
sendPhone = state.sendPhone
isSending = state.isSending
failure = state.failure
}
} }
public var body: some View { public var body: some View {
WithViewStore(store.scope(state: ViewState.init)) { viewStore in WithViewStore(store.scope(state: ViewState.init)) { viewStore in
Form { Form {
Section {
HStack {
Label(viewStore.myContact?.username ?? "", systemImage: "person")
Spacer()
Toggle(
isOn: viewStore.binding(
get: \.sendUsername,
send: { SendRequestAction.set(\.$sendUsername, $0) }
),
label: EmptyView.init
)
}
HStack {
Label(viewStore.myContact?.email ?? "", systemImage: "envelope")
Spacer()
Toggle(
isOn: viewStore.binding(
get: \.sendEmail,
send: { SendRequestAction.set(\.$sendEmail, $0) }
),
label: EmptyView.init
)
}
HStack {
Label(viewStore.myContact?.phone ?? "", systemImage: "phone")
Spacer()
Toggle(
isOn: viewStore.binding(
get: \.sendPhone,
send: { SendRequestAction.set(\.$sendPhone, $0) }
),
label: EmptyView.init
)
}
} header: {
Text("My facts")
}
.disabled(viewStore.isSending)
Section {
Label(viewStore.contact.username ?? "", systemImage: "person")
Label(viewStore.contact.email ?? "", systemImage: "envelope")
Label(viewStore.contact.phone ?? "", systemImage: "phone")
} header: {
Text("Contact")
}
Section {
Button {
viewStore.send(.sendTapped)
} label: {
HStack {
Text("Send request")
Spacer()
if viewStore.isSending {
ProgressView()
} else {
Image(systemName: "paperplane")
}
}
}
}
.disabled(viewStore.isSending)
if let failure = viewStore.failure {
Section {
Text(failure)
} header: {
Text("Error")
}
}
} }
.navigationTitle("Send Request") .navigationTitle("Send Request")
.task { viewStore.send(.start) } .task { viewStore.send(.start) }
...@@ -26,11 +116,38 @@ public struct SendRequestView: View { ...@@ -26,11 +116,38 @@ public struct SendRequestView: View {
#if DEBUG #if DEBUG
public struct SendRequestView_Previews: PreviewProvider { public struct SendRequestView_Previews: PreviewProvider {
public static var previews: some View { public static var previews: some View {
SendRequestView(store: Store( NavigationView {
initialState: SendRequestState(), SendRequestView(store: Store(
reducer: .empty, initialState: SendRequestState(
environment: () contact: {
)) var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!)
contact.getFactsFromContact.run = { _ in
[
Fact(fact: "contact-username", type: 0),
Fact(fact: "contact-email", type: 1),
Fact(fact: "contact-phone", type: 2),
]
}
return contact
}(),
myContact: {
var contact = XXClient.Contact.unimplemented("my-data".data(using: .utf8)!)
contact.getFactsFromContact.run = { _ in
[
Fact(fact: "my-username", type: 0),
Fact(fact: "my-email", type: 1),
Fact(fact: "my-phone", type: 2),
]
}
return contact
}(),
isSending: true,
failure: "Something went wrong"
),
reducer: .empty,
environment: ()
))
}
} }
} }
#endif #endif
...@@ -95,18 +95,52 @@ final class ContactFeatureTests: XCTestCase { ...@@ -95,18 +95,52 @@ final class ContactFeatureTests: XCTestCase {
XCTAssertNoDifference(dbDidSaveContact, [expectedSavedContact]) XCTAssertNoDifference(dbDidSaveContact, [expectedSavedContact])
} }
func testSendRequest() { func testSendRequestWithDBContact() {
var dbContact = XXModels.Contact(id: "contact-id".data(using: .utf8)!)
dbContact.marshaled = "contact-data".data(using: .utf8)!
let store = TestStore( let store = TestStore(
initialState: ContactState( initialState: ContactState(
id: "contact-id".data(using: .utf8)! id: dbContact.id,
dbContact: dbContact
), ),
reducer: contactReducer, reducer: contactReducer,
environment: .unimplemented environment: .unimplemented
) )
store.send(.sendRequestTapped) { store.send(.sendRequestTapped) {
$0.sendRequest = SendRequestState() $0.sendRequest = SendRequestState(contact: .live(dbContact.marshaled!))
} }
}
func testSendRequestWithXXContact() {
let xxContact = XXClient.Contact.unimplemented("contact-id".data(using: .utf8)!)
let store = TestStore(
initialState: ContactState(
id: "contact-id".data(using: .utf8)!,
xxContact: xxContact
),
reducer: contactReducer,
environment: .unimplemented
)
store.send(.sendRequestTapped) {
$0.sendRequest = SendRequestState(contact: xxContact)
}
}
func testSendRequestDismissed() {
let store = TestStore(
initialState: ContactState(
id: "contact-id".data(using: .utf8)!,
sendRequest: SendRequestState(
contact: .unimplemented("contact-id".data(using: .utf8)!)
)
),
reducer: contactReducer,
environment: .unimplemented
)
store.send(.sendRequestDismissed) { store.send(.sendRequestDismissed) {
$0.sendRequest = nil $0.sendRequest = nil
......
...@@ -5,7 +5,9 @@ import XCTest ...@@ -5,7 +5,9 @@ import XCTest
final class SendRequestFeatureTests: XCTestCase { final class SendRequestFeatureTests: XCTestCase {
func testStart() { func testStart() {
let store = TestStore( let store = TestStore(
initialState: SendRequestState(), initialState: SendRequestState(
contact: .unimplemented("contact-data".data(using: .utf8)!)
),
reducer: sendRequestReducer, reducer: sendRequestReducer,
environment: .unimplemented environment: .unimplemented
) )
......
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