Fixes for the feedback

This commit is contained in:
Lukas Korba 2025-04-22 16:22:12 +02:00
parent c5b8f4cf1f
commit 8081ab7478
18 changed files with 121 additions and 58 deletions

View File

@ -99,7 +99,7 @@ let package = Package(
.package(url: "https://github.com/pointfreeco/swift-url-routing", from: "0.6.2"),
.package(url: "https://github.com/zcash-hackworks/MnemonicSwift", from: "2.2.5"),
// .package(url: "https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk", from: "2.2.10"),
.package(url: "https://github.com/LukasKorba/ZcashLightClientKit", revision: "16a80d2efb2fbb4921a8c6be528e6a8644d4a6d8"),
.package(url: "https://github.com/LukasKorba/ZcashLightClientKit", revision: "1a2db6b167614fca4161f94ac1cb41cae976222f"),
.package(url: "https://github.com/flexa/flexa-ios.git", exact: "1.0.9"),
.package(url: "https://github.com/pacu/zcash-swift-payment-uri", from: "0.1.0-beta.10"),
.package(url: "https://github.com/airbnb/lottie-spm.git", from: "4.5.1"),

View File

@ -16,7 +16,7 @@ extension NetworkMonitorClient: DependencyKey {
public static func live() -> Self {
let monitor = NWPathMonitor()
let queue = DispatchQueue.global(qos: .background)
let subject = PassthroughSubject<Bool, Never>()
let subject = CurrentValueSubject<Bool, Never>(true)
return NetworkMonitorClient(
networkMonitorStream: {

View File

@ -21,7 +21,7 @@ extension SDKSynchronizerClient: DependencyKey {
databaseFiles: DatabaseFilesClient = .liveValue
) -> Self {
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
let network = zcashSDKEnvironment.network
#if DEBUG
@ -51,12 +51,7 @@ extension SDKSynchronizerClient: DependencyKey {
eventStream: { synchronizer.eventStream },
exchangeRateUSDStream: { synchronizer.exchangeRateUSDStream },
latestState: { synchronizer.latestState },
prepareWith: {
seedBytes,
walletBirtday,
walletMode,
name,
keySource in
prepareWith: { seedBytes, walletBirtday, walletMode, name, keySource in
let result = try await synchronizer.prepare(
with: seedBytes,
walletBirthday: walletBirtday,
@ -309,10 +304,10 @@ extension SDKSynchronizerClient {
let clearedTransactions = zcashTransactions.compactMap { rawTransaction in
rawTransaction.accountUUID == accountUUID ? rawTransaction : nil
}
var clearedTxs: [TransactionState] = []
let latestBlockHeight = try await SDKSynchronizerClient.latestBlockHeight(synchronizer: synchronizer)
let latestBlockHeight = try? await SDKSynchronizerClient.latestBlockHeight(synchronizer: synchronizer)
for clearedTransaction in clearedTransactions {
var hasTransparentOutputs = false

View File

@ -17,13 +17,15 @@ extension RequestZecCoordFlow {
// MARK: - Request Zec
case .path(.element(id: _, action: .requestZec(.requestTapped))):
for element in state.path {
if case .requestZec(let requestZecState) = element {
state.requestZecState.memoState = requestZecState.memoState
break
}
}
state.path.append(.requestZecSummary(state.requestZecState))
return .none
case .path(.element(id: _, action: .requestZec(.onDisappearMemoStep(let memoText)))):
state.memo = memoText
return .none
// MARK: - Zec Keyboard
case .zecKeyboard(.nextTapped):

View File

@ -45,7 +45,7 @@ extension RestoreWalletCoordFlow {
// MARK: - Wallet Birthday
case .path(.element(id: _, action: .walletBirthday(.helpSheetRequested))):
state.isHelpSheetPreseted.toggle()
state.isHelpSheetPresented.toggle()
return .none
case .path(.element(id: _, action: .walletBirthday(.estimateHeightTapped))):
@ -61,7 +61,7 @@ extension RestoreWalletCoordFlow {
return .none
case .path(.element(id: _, action: .estimateBirthdaysDate(.helpSheetRequested))):
state.isHelpSheetPreseted.toggle()
state.isHelpSheetPresented.toggle()
return .none
case .path(.element(id: _, action: .estimateBirthdaysDate(.estimateHeightReady))):

View File

@ -29,7 +29,8 @@ public struct RestoreWalletCoordFlow {
@ObservableState
public struct State {
public var isHelpSheetPreseted = false
public var isHelpSheetPresented = false
public var isKeyboardVisible = false
public var isValidSeed = false
public var nextIndex: Int?
public var path = StackState<Path.State>()
@ -54,6 +55,7 @@ public struct RestoreWalletCoordFlow {
case successfullyRecovered
case suggestedWordTapped(String)
case suggestionsRequested(Int)
case updateKeyboardFlag(Bool)
#if DEBUG
case debugPasteSeed
#endif
@ -91,6 +93,7 @@ public struct RestoreWalletCoordFlow {
case .selectedIndex(let index):
state.selectedIndex = index
state.nextIndex = state.selectedIndex
if let index {
return .send(.suggestionsRequested(index))
}
@ -109,32 +112,47 @@ public struct RestoreWalletCoordFlow {
case .suggestedWordTapped(let word):
if let index = state.selectedIndex {
state.words[index] = word
state.prevWords = state.words
state.nextIndex = index + 1 < 24 ? index + 1 : 0
if !state.isValidSeed && state.selectedIndex != 23 {
state.prevWords = state.words
state.nextIndex = index + 1 < 24 ? index + 1 : 0
}
return .send(.evaluateSeedValidity)
}
return .none
case .helpSheetRequested:
state.isHelpSheetPreseted.toggle()
state.isHelpSheetPresented.toggle()
return .none
case .evaluateSeedValidity:
do {
try mnemonic.isValid(state.words.joined(separator: " "))
state.isValidSeed = true
state.isKeyboardVisible = false
} catch {
state.isValidSeed = false
if let index = state.selectedIndex {
let prefix = state.words[index]
if let first = state.suggestedWords.first, first == prefix && !state.isValidSeed {
state.prevWords = state.words
state.nextIndex = index + 1 < 24 ? index + 1 : 0
}
}
}
return .none
case .updateKeyboardFlag(let value):
state.isKeyboardVisible = value
return .none
#if DEBUG
case .debugPasteSeed:
do {
let seedToPaste = pasteboard.getString()?.data ?? ""
try mnemonic.isValid(seedToPaste)
state.words = seedToPaste.components(separatedBy: " ")
state.isValidSeed = true
state.isKeyboardVisible = false
state.words = seedToPaste.components(separatedBy: " ")
} catch {
state.isValidSeed = false
}

View File

@ -57,9 +57,16 @@ public struct RestoreWalletCoordFlowView: View {
ForEach(0..<3, id: \.self) { i in
HStack(spacing: 0) {
Text("\(j * 3 + i + 1)")
.zFont(.medium, size: 14, style: Design.Text.primary)
.zFont(.medium, size: 14, style: Design.Tags.tcCountFg)
.frame(minWidth: 12)
.padding(.vertical, 2)
.padding(.horizontal, 4)
.background {
RoundedRectangle(cornerRadius: Design.Radius._lg)
.fill(Design.Tags.tcCountBg.color(colorScheme))
}
.padding(.trailing, 4)
TextField("", text: $store.words[j * 3 + i])
.zFont(size: 16, style: Design.Text.primary)
.disableAutocorrection(true)
@ -136,6 +143,12 @@ public struct RestoreWalletCoordFlowView: View {
focusedField = .field(nextIndex)
}
}
.onChange(of: store.isKeyboardVisible) { value in
if keyboardVisible && !value {
keyboardVisible = value
focusedField = nil
}
}
.applyScreenBackground()
.overlay(
VStack(spacing: 0) {
@ -176,7 +189,6 @@ public struct RestoreWalletCoordFlowView: View {
)
)
.frame(height: 38)
//.clipped()
Spacer()
@ -186,7 +198,6 @@ public struct RestoreWalletCoordFlowView: View {
Text(L10n.General.done.uppercased())
.zFont(.regular, size: 14, style: Design.Text.primary)
}
// .padding(.bottom, 4)
.padding(.trailing, 24)
.padding(.leading, 4)
}
@ -196,7 +207,6 @@ public struct RestoreWalletCoordFlowView: View {
.opacity(keyboardVisible ? 1 : 0)
}
)
// .navigationBarHidden(true)
} destination: { store in
switch store.case {
case let .estimateBirthdaysDate(store):
@ -220,7 +230,7 @@ public struct RestoreWalletCoordFlowView: View {
.padding(8)
}
)
.zashiSheet(isPresented: $store.isHelpSheetPreseted) {
.zashiSheet(isPresented: $store.isHelpSheetPresented) {
helpSheetContent()
.screenHorizontalPadding()
}
@ -234,11 +244,13 @@ public struct RestoreWalletCoordFlowView: View {
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in
withAnimation {
keyboardVisible = true
store.send(.updateKeyboardFlag(true))
}
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
withAnimation {
keyboardVisible = false
store.send(.updateKeyboardFlag(false))
}
}
}

View File

@ -22,7 +22,7 @@ public struct WalletBackupCoordFlow {
@ObservableState
public struct State {
public var isHelpSheetPreseted = false
public var isHelpSheetPresented = false
public var path = StackState<Path.State>()
public var recoveryPhraseDisplayState = RecoveryPhraseDisplay.State.initial
@ -50,7 +50,7 @@ public struct WalletBackupCoordFlow {
Reduce { state, action in
switch action {
case .helpSheetRequested:
state.isHelpSheetPreseted.toggle()
state.isHelpSheetPresented.toggle()
return .none
default: return .none

View File

@ -51,7 +51,7 @@ public struct WalletBackupCoordFlowView: View {
.padding(8)
}
)
.zashiSheet(isPresented: $store.isHelpSheetPreseted) {
.zashiSheet(isPresented: $store.isHelpSheetPresented) {
helpSheetContent()
.screenHorizontalPadding()
}

View File

@ -45,13 +45,15 @@ extension Receive {
// MARK: - Request Zec
case .path(.element(id: _, action: .requestZec(.requestTapped))):
for element in state.path {
if case .requestZec(let requestZecState) = element {
state.requestZecState.memoState = requestZecState.memoState
break
}
}
state.path.append(.requestZecSummary(state.requestZecState))
return .none
case .path(.element(id: _, action: .requestZec(.onDisappearMemoStep(let memoText)))):
state.memo = memoText
return .none
case .path(.element(id: _, action: .requestZecSummary(.cancelRequestTapped))):
state.path.removeAll()
return .none

View File

@ -22,7 +22,7 @@ public struct RecoveryPhraseDisplay {
public var birthday: Birthday?
public var birthdayValue: String?
public var isBirthdayHintVisible = false
public var isHelpSheetPreseted = false
public var isHelpSheetPresented = false
public var isRecoveryPhraseHidden = true
public var isWalletBackup = false
public var phrase: RecoveryPhrase?
@ -138,7 +138,7 @@ public struct RecoveryPhraseDisplay {
return .none
case .helpSheetRequested:
state.isHelpSheetPreseted.toggle()
state.isHelpSheetPresented.toggle()
return .none
case .seedSavedTapped:

View File

@ -91,7 +91,7 @@ public struct RecoveryPhraseDisplayView: View {
.onAppear { store.send(.onAppear) }
.alert($store.scope(state: \.alert, action: \.alert))
.zashiBack()
.zashiSheet(isPresented: $store.isHelpSheetPreseted) {
.zashiSheet(isPresented: $store.isHelpSheetPresented) {
helpSheetContent()
.screenHorizontalPadding()
}

View File

@ -42,7 +42,6 @@ public struct RequestZec {
case memo(MessageEditor.Action)
case onAppear
case onDisappear
case onDisappearMemoStep(String)
case qrCodeTapped
case rememberQR(CGImage?)
case requestTapped
@ -70,9 +69,6 @@ public struct RequestZec {
case .onDisappear:
return .cancel(id: state.cancelId)
case .onDisappearMemoStep:
return .none
case .cancelRequestTapped:
return .none

View File

@ -87,7 +87,6 @@ public struct RequestZecView: View {
observeKeyboardNotifications()
}
}
.onDisappear { store.send(.onDisappearMemoStep(store.memoState.text)) }
.overlay(
VStack(spacing: 0) {
Spacer()

View File

@ -195,16 +195,21 @@ extension Root {
}
case .initialization(.registerForSynchronizersUpdate):
return .merge(
.publisher {
sdkSynchronizer.stateStream()
.throttle(for: .seconds(0.2), scheduler: mainQueue, latest: true)
.map { $0.redacted }
.map(Root.Action.synchronizerStateChanged)
}
.cancellable(id: CancelStateId, cancelInFlight: true),
.send(.home(.smartBanner(.evaluatePriority1)))
)
let stateStreamEffect = Effect.publisher {
sdkSynchronizer.stateStream()
.throttle(for: .seconds(0.2), scheduler: mainQueue, latest: true)
.map { $0.redacted }
.map(Root.Action.synchronizerStateChanged)
}
.cancellable(id: CancelStateId, cancelInFlight: true)
if state.bgTask != nil {
return stateStreamEffect
} else {
return .merge(
stateStreamEffect,
.send(.home(.smartBanner(.evaluatePriority1)))
)
}
case .initialization(.checkWalletConfig):
return .publisher {

View File

@ -123,6 +123,17 @@ public enum Design {
}
}
public enum Tags: Colorable {
case tcDefaultFg
case tcHoverBg
case tcHoverFg
case tcCountBg
case tcCountFg
case surfaceIndicator
case surfacePrimary
case surfaceStroke
}
public enum Inputs {
public enum Default: Colorable {
case bg
@ -515,6 +526,21 @@ public extension Design.Btns.Ghost {
}
}
public extension Design.Tags {
func color(_ colorScheme: ColorScheme) -> Color {
switch self {
case .tcDefaultFg: return Design.col(Asset.Colors.ZDesign.gray400.color, Asset.Colors.ZDesign.shark500.color, colorScheme)
case .tcHoverBg: return Design.col(Asset.Colors.ZDesign.gray50.color, Asset.Colors.ZDesign.shark800.color, colorScheme)
case .tcHoverFg: return Design.col(Asset.Colors.ZDesign.gray600.color, Asset.Colors.ZDesign.shark200.color, colorScheme)
case .tcCountBg: return Design.col(Asset.Colors.ZDesign.gray50.color, Asset.Colors.ZDesign.shark700.color, colorScheme)
case .tcCountFg: return Design.col(Asset.Colors.ZDesign.gray700.color, Asset.Colors.ZDesign.shark300.color, colorScheme)
case .surfaceIndicator: return Design.col(Asset.Colors.ZDesign.successGreen600.color, Asset.Colors.ZDesign.successGreen500.color, colorScheme)
case .surfacePrimary: return Design.col(Asset.Colors.ZDesign.Base.bone.color, Asset.Colors.ZDesign.Base.midnight.color, colorScheme)
case .surfaceStroke: return Design.col(Asset.Colors.ZDesign.gray300.color, Asset.Colors.ZDesign.shark700.color, colorScheme)
}
}
}
public extension Design.Inputs.Default {
func color(_ colorScheme: ColorScheme) -> Color {
switch self {

View File

@ -271,7 +271,7 @@ extension TransactionState {
transaction: ZcashTransaction.Overview,
memos: [Memo]? = nil,
hasTransparentOutputs: Bool = false,
latestBlockHeight: BlockHeight
latestBlockHeight: BlockHeight?
) {
expiryHeight = transaction.expiryHeight
minedHeight = transaction.minedHeight
@ -293,10 +293,18 @@ extension TransactionState {
// state of the transaction. SDK knows the latestBlockHeight so ideally ZcashTransaction.Overview
// already knows and provides isPending as a bool value.
// Once SDK's #1313 is done, adopt the SDK and remove latestBlockHeight here.
let isPending = transaction.isPending(currentHeight: latestBlockHeight)
var isPending = false
var isExpired = false
if let latestBlockHeight {
isPending = transaction.isPending(currentHeight: latestBlockHeight)
if let expiryHeight = transaction.expiryHeight, expiryHeight <= latestBlockHeight && minedHeight == nil {
isExpired = true
}
}
// failed check
if let expiryHeight = transaction.expiryHeight, expiryHeight <= latestBlockHeight && minedHeight == nil {
if isExpired {
status = .failed
} else if isShieldingTransaction {
status = isPending ? .shielding : .shielded

View File

@ -464,7 +464,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/LukasKorba/ZcashLightClientKit",
"state" : {
"revision" : "16a80d2efb2fbb4921a8c6be528e6a8644d4a6d8"
"revision" : "1a2db6b167614fca4161f94ac1cb41cae976222f"
}
}
],