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

Add ConfirmRequestFeature library

parent a13e6f06
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!81Messenger example - contact authorization improvements
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ConfirmRequestFeature"
BuildableName = "ConfirmRequestFeature"
BlueprintName = "ConfirmRequestFeature"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ConfirmRequestFeatureTests"
BuildableName = "ConfirmRequestFeatureTests"
BlueprintName = "ConfirmRequestFeatureTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ConfirmRequestFeature"
BuildableName = "ConfirmRequestFeature"
BlueprintName = "ConfirmRequestFeature"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
......@@ -21,6 +21,7 @@ let package = Package(
.library(name: "AppCore", targets: ["AppCore"]),
.library(name: "AppFeature", targets: ["AppFeature"]),
.library(name: "CheckContactAuthFeature", targets: ["CheckContactAuthFeature"]),
.library(name: "ConfirmRequestFeature", targets: ["ConfirmRequestFeature"]),
.library(name: "ContactFeature", targets: ["ContactFeature"]),
.library(name: "ContactsFeature", targets: ["ContactsFeature"]),
.library(name: "HomeFeature", targets: ["HomeFeature"]),
......@@ -115,6 +116,22 @@ let package = Package(
.target(name: "CheckContactAuthFeature"),
]
),
.target(
name: "ConfirmRequestFeature",
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"),
]
),
.testTarget(
name: "ConfirmRequestFeatureTests",
dependencies: [
.target(name: "ConfirmRequestFeature"),
]
),
.target(
name: "ContactFeature",
dependencies: [
......
......@@ -59,6 +59,16 @@
ReferencedContainer = "container:..">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ConfirmRequestFeatureTests"
BuildableName = "ConfirmRequestFeatureTests"
BlueprintName = "ConfirmRequestFeatureTests"
ReferencedContainer = "container:..">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
......
import AppCore
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct ConfirmRequestState: Equatable {
public enum Result: Equatable {
case success
case failure(String)
}
public init(
contact: XXClient.Contact,
isConfirming: Bool = false,
result: Result? = nil
) {
self.contact = contact
self.isConfirming = isConfirming
self.result = result
}
public var contact: XXClient.Contact
public var isConfirming: Bool
public var result: Result?
}
public enum ConfirmRequestAction: Equatable {
case confirmTapped
case didConfirm(ConfirmRequestState.Result)
}
public struct ConfirmRequestEnvironment {
public init(
messenger: Messenger,
db: DBManagerGetDB,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
) {
self.messenger = messenger
self.db = db
self.mainQueue = mainQueue
self.bgQueue = bgQueue
}
public var messenger: Messenger
public var db: DBManagerGetDB
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
}
#if DEBUG
extension ConfirmRequestEnvironment {
public static let unimplemented = ConfirmRequestEnvironment(
messenger: .unimplemented,
db: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
)
}
#endif
public let confirmRequestReducer = Reducer<ConfirmRequestState, ConfirmRequestAction, ConfirmRequestEnvironment>
{ state, action, env in
switch action {
case .confirmTapped:
state.isConfirming = true
state.result = nil
return Effect.result { [state] in
do {
let e2e = try env.messenger.e2e.tryGet()
_ = try e2e.confirmReceivedRequest(partner: state.contact)
let contactId = try state.contact.getId()
try env.db().bulkUpdateContacts.callAsFunction(
.init(id: [contactId]),
.init(authStatus: .friend)
)
return .success(.didConfirm(.success))
} catch {
return .success(.didConfirm(.failure(error.localizedDescription)))
}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .didConfirm(let result):
state.isConfirming = false
state.result = result
return .none
}
}
import ComposableArchitecture
import SwiftUI
public struct ConfirmRequestView: View {
public init(store: Store<ConfirmRequestState, ConfirmRequestAction>) {
self.store = store
}
let store: Store<ConfirmRequestState, ConfirmRequestAction>
struct ViewState: Equatable {
var username: String?
var email: String?
var phone: String?
var isConfirming: Bool
var result: ConfirmRequestState.Result?
init(state: ConfirmRequestState) {
username = try? state.contact.getFact(.username)?.value
email = try? state.contact.getFact(.email)?.value
phone = try? state.contact.getFact(.phone)?.value
isConfirming = state.isConfirming
result = state.result
}
}
public var body: some View {
WithViewStore(store, observe: ViewState.init) { viewStore in
Form {
Section {
Label(viewStore.username ?? "", systemImage: "person")
Label(viewStore.email ?? "", systemImage: "envelope")
Label(viewStore.phone ?? "", systemImage: "phone")
} header: {
Text("Facts")
}
Section {
Button {
viewStore.send(.confirmTapped)
} label: {
HStack {
Text("Confirm")
Spacer()
if viewStore.isConfirming {
ProgressView()
} else {
Image(systemName: "checkmark")
}
}
}
.disabled(viewStore.isConfirming)
}
if let result = viewStore.result {
Section {
HStack {
switch result {
case .success:
Text("Request confirmed")
Spacer()
Image(systemName: "person.fill.checkmark")
case .failure(_):
Text("Confirming request failed")
Spacer()
Image(systemName: "xmark")
}
}
if case .failure(let failure) = result {
Text(failure)
}
} header: {
Text("Result")
}
}
}
.navigationTitle("Confirm request")
}
}
}
#if DEBUG
public struct ConfirmRequestView_Previews: PreviewProvider {
public static var previews: some View {
ConfirmRequestView(store: Store(
initialState: ConfirmRequestState(
contact: .unimplemented("contact-data".data(using: .utf8)!)
),
reducer: .empty,
environment: ()
))
}
}
#endif
import ComposableArchitecture
import CustomDump
import XCTest
import XXClient
import XXModels
@testable import ConfirmRequestFeature
final class ConfirmRequestFeatureTests: XCTestCase {
func testConfirm() {
var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: ConfirmRequestState(
contact: contact
),
reducer: confirmRequestReducer,
environment: .unimplemented
)
var didConfirmRequestFromContact: [XXClient.Contact] = []
var didBulkUpdateContactsWithQuery: [XXModels.Contact.Query] = []
var didBulkUpdateContactsWithAssignments: [XXModels.Contact.Assignments] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.confirmReceivedRequest.run = { contact in
didConfirmRequestFromContact.append(contact)
return 0
}
return e2e
}
store.environment.db.run = {
var db: Database = .failing
db.bulkUpdateContacts.run = { query, assignments in
didBulkUpdateContactsWithQuery.append(query)
didBulkUpdateContactsWithAssignments.append(assignments)
return 0
}
return db
}
store.send(.confirmTapped) {
$0.isConfirming = true
$0.result = nil
}
XCTAssertNoDifference(didConfirmRequestFromContact, [contact])
XCTAssertNoDifference(didBulkUpdateContactsWithQuery, [.init(id: [contactId])])
XCTAssertNoDifference(didBulkUpdateContactsWithAssignments, [.init(authStatus: .friend)])
store.receive(.didConfirm(.success)) {
$0.isConfirming = false
$0.result = .success
}
}
func testConfirmFailure() {
var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: ConfirmRequestState(
contact: contact
),
reducer: confirmRequestReducer,
environment: .unimplemented
)
struct Failure: Error {}
let error = Failure()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.confirmReceivedRequest.run = { _ in throw error }
return e2e
}
store.send(.confirmTapped) {
$0.isConfirming = true
$0.result = nil
}
store.receive(.didConfirm(.failure(error.localizedDescription))) {
$0.isConfirming = false
$0.result = .failure(error.localizedDescription)
}
}
}
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