secant-ios-wallet/modules/Sources/Features/RequestZec/RequestZecStore.swift

135 lines
4.3 KiB
Swift

//
// RequestZecStore.swift
// Zashi
//
// Created by Lukáš Korba on 09-20-2024.
//
import Foundation
import SwiftUI
import ComposableArchitecture
import ZcashLightClientKit
import Pasteboard
import Generated
import Utils
import UIComponents
import ZcashSDKEnvironment
import ZcashPaymentURI
import Models
@Reducer
public struct RequestZec {
@ObservableState
public struct State: Equatable {
public var cancelId = UUID()
public var address: RedactableString = .empty
public var encryptedOutput: String?
public var encryptedOutputToBeShared: String?
public var isQRCodeAppreanceFlipped = false
public var maxPrivacy = false
public var memoState: MessageEditor.State = .initial
public var requestedZec: Zatoshi = .zero
@Shared(.inMemory(.selectedWalletAccount)) public var selectedWalletAccount: WalletAccount? = nil
public var storedQR: CGImage?
public init() {}
}
public enum Action: Equatable {
case cancelRequestTapped
case generateQRCode(Bool)
case memo(MessageEditor.Action)
case onAppear
case onDisappear
case qrCodeTapped
case rememberQR(CGImage?)
case requestTapped
case shareFinished
case shareQR
}
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
public init() { }
public var body: some Reducer<State, Action> {
Scope(state: \.memoState, action: \.memo) {
MessageEditor()
}
Reduce { state, action in
switch action {
case .onAppear:
state.memoState.charLimit = zcashSDKEnvironment.memoCharLimit
state.isQRCodeAppreanceFlipped = false
state.encryptedOutput = nil
return .none
case .onDisappear:
return .cancel(id: state.cancelId)
case .cancelRequestTapped:
return .none
case .memo:
return .none
case .requestTapped:
return .none
case .qrCodeTapped:
guard state.storedQR != nil else {
return .none
}
state.isQRCodeAppreanceFlipped.toggle()
return .send(.generateQRCode(true))
case let .rememberQR(image):
state.storedQR = image
return .none
case .generateQRCode:
if let recipient = RecipientAddress(value: state.address.data) {
do {
let payment = Payment(
recipientAddress: recipient,
amount: try Amount(value: state.requestedZec.decimalValue.doubleValue),
memo: state.memoState.text.isEmpty ? nil : try MemoBytes(utf8String: state.memoState.text),
label: nil,
message: nil,
otherParams: nil
)
let encryptedOutput = ZIP321.request(payment, formattingOptions: .useEmptyParamIndex(omitAddressLabel: true))
state.encryptedOutput = encryptedOutput
return .publisher {
QRCodeGenerator.generate(
from: encryptedOutput,
maxPrivacy: state.maxPrivacy,
vendor: state.selectedWalletAccount?.vendor == .keystone ? .keystone : .zashi,
color: state.isQRCodeAppreanceFlipped
? .black
: Asset.Colors.primary.systemColor
)
.map(Action.rememberQR)
}
.cancellable(id: state.cancelId)
} catch {
return .none
}
}
return .none
case .shareFinished:
state.encryptedOutputToBeShared = nil
return .none
case .shareQR:
state.encryptedOutputToBeShared = state.encryptedOutput
return .none
}
}
}
}