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(
.target(
name: "SendRequestFeature",
dependencies: [
.target(name: "AppCore"),
.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
),
......
......@@ -4,6 +4,7 @@ import Foundation
import HomeFeature
import RegisterFeature
import RestoreFeature
import SendRequestFeature
import UserSearchFeature
import WelcomeFeature
import XXMessengerClient
......
......@@ -104,7 +104,11 @@ public let contactReducer = Reducer<ContactState, ContactAction, ContactEnvironm
.eraseToEffect()
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
case .sendRequestDismissed:
......
import ComposableArchitecture
import XCTestDynamicOverlay
import XXClient
import XXModels
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 sendTapped
case binding(BindingAction<SendRequestState>)
}
public struct SendRequestEnvironment {
......@@ -24,5 +52,11 @@ public let sendRequestReducer = Reducer<SendRequestState, SendRequestAction, Sen
switch action {
case .start:
return .none
case .sendTapped:
return .none
case .binding(_):
return .none
}
}
import AppCore
import ComposableArchitecture
import SwiftUI
import XXClient
public struct SendRequestView: View {
public init(store: Store<SendRequestState, SendRequestAction>) {
......@@ -9,13 +11,101 @@ public struct SendRequestView: View {
let store: Store<SendRequestState, SendRequestAction>
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 {
WithViewStore(store.scope(state: ViewState.init)) { viewStore in
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")
.task { viewStore.send(.start) }
......@@ -26,11 +116,38 @@ public struct SendRequestView: View {
#if DEBUG
public struct SendRequestView_Previews: PreviewProvider {
public static var previews: some View {
SendRequestView(store: Store(
initialState: SendRequestState(),
reducer: .empty,
environment: ()
))
NavigationView {
SendRequestView(store: Store(
initialState: SendRequestState(
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
......@@ -95,18 +95,52 @@ final class ContactFeatureTests: XCTestCase {
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(
initialState: ContactState(
id: "contact-id".data(using: .utf8)!
id: dbContact.id,
dbContact: dbContact
),
reducer: contactReducer,
environment: .unimplemented
)
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) {
$0.sendRequest = nil
......
......@@ -5,7 +5,9 @@ import XCTest
final class SendRequestFeatureTests: XCTestCase {
func testStart() {
let store = TestStore(
initialState: SendRequestState(),
initialState: SendRequestState(
contact: .unimplemented("contact-data".data(using: .utf8)!)
),
reducer: sendRequestReducer,
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