[#1290] Inform a user to plug in a device when restoring
- Changelog updated - Screen with the syncing tips has been implemented - The sync starts immediately after we know seed + BD (optional) and the view is just presented to inform users
This commit is contained in:
parent
891461e6f9
commit
d72307e080
|
@ -6,7 +6,10 @@ directly impact users rather than highlighting other crucial architectural updat
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## Fixed
|
||||
### Added
|
||||
- Screen summarizing successful restoration with some syncing tips.
|
||||
|
||||
### Fixed
|
||||
- The application startup pipeline has been optimized, significantly improving performance. Consequently, Zashi now features faster cold and warm starts, and the transaction history is populated almost instantly.
|
||||
- Transaction messages are now checked for duplicity and removed if duplicates are found.
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ let package = Package(
|
|||
.library(name: "PrivateDataConsent", targets: ["PrivateDataConsent"]),
|
||||
.library(name: "QRImageDetector", targets: ["QRImageDetector"]),
|
||||
.library(name: "RecoveryPhraseDisplay", targets: ["RecoveryPhraseDisplay"]),
|
||||
.library(name: "RestoreInfo", targets: ["RestoreInfo"]),
|
||||
.library(name: "ReviewRequest", targets: ["ReviewRequest"]),
|
||||
.library(name: "Root", targets: ["Root"]),
|
||||
.library(name: "Sandbox", targets: ["Sandbox"]),
|
||||
|
@ -286,6 +287,7 @@ let package = Package(
|
|||
dependencies: [
|
||||
"Generated",
|
||||
"MnemonicClient",
|
||||
"RestoreInfo",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletStorage",
|
||||
|
@ -424,6 +426,15 @@ let package = Package(
|
|||
],
|
||||
path: "Sources/Dependencies/RestoreWalletStorage"
|
||||
),
|
||||
.target(
|
||||
name: "RestoreInfo",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"UIComponents",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/RestoreInfo"
|
||||
),
|
||||
.target(
|
||||
name: "ReviewRequest",
|
||||
dependencies: [
|
||||
|
|
|
@ -13,6 +13,7 @@ import Generated
|
|||
import WalletStorage
|
||||
import MnemonicClient
|
||||
import ZcashSDKEnvironment
|
||||
import RestoreInfo
|
||||
|
||||
public typealias ImportWalletStore = Store<ImportWalletReducer.State, ImportWalletReducer.Action>
|
||||
public typealias ImportWalletViewStore = ViewStore<ImportWalletReducer.State, ImportWalletReducer.Action>
|
||||
|
@ -31,6 +32,8 @@ public struct ImportWalletReducer: Reducer {
|
|||
public var isValidMnemonic = false
|
||||
public var isValidNumberOfWords = false
|
||||
public var maxWordsCount = 0
|
||||
public var restoreInfoState: RestoreInfo.State
|
||||
public var restoreInfoViewBinding: Bool = false
|
||||
public var wordsCount = 0
|
||||
|
||||
public var mnemonicStatus: String {
|
||||
|
@ -55,9 +58,10 @@ public struct ImportWalletReducer: Reducer {
|
|||
isValidMnemonic: Bool = false,
|
||||
isValidNumberOfWords: Bool = false,
|
||||
maxWordsCount: Int = 0,
|
||||
restoreInfoState: RestoreInfo.State,
|
||||
restoreInfoViewBinding: Bool = false,
|
||||
wordsCount: Int = 0
|
||||
) {
|
||||
self.alert = alert
|
||||
self.birthdayHeight = birthdayHeight
|
||||
self.birthdayHeightValue = birthdayHeightValue
|
||||
self.destination = destination
|
||||
|
@ -65,6 +69,8 @@ public struct ImportWalletReducer: Reducer {
|
|||
self.isValidMnemonic = isValidMnemonic
|
||||
self.isValidNumberOfWords = isValidNumberOfWords
|
||||
self.maxWordsCount = maxWordsCount
|
||||
self.restoreInfoState = restoreInfoState
|
||||
self.restoreInfoViewBinding = restoreInfoViewBinding
|
||||
self.wordsCount = wordsCount
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +82,8 @@ public struct ImportWalletReducer: Reducer {
|
|||
case initializeSDK
|
||||
case nextPressed
|
||||
case onAppear
|
||||
case restoreInfo(RestoreInfo.Action)
|
||||
case restoreInfoRequested(Bool)
|
||||
case restoreWallet
|
||||
case seedPhraseInputChanged(RedactableString)
|
||||
case successfullyRecovered
|
||||
|
@ -89,6 +97,10 @@ public struct ImportWalletReducer: Reducer {
|
|||
public init() { }
|
||||
|
||||
public var body: some Reducer<State, Action> {
|
||||
Scope(state: \.restoreInfoState, action: /Action.restoreInfo) {
|
||||
RestoreInfo()
|
||||
}
|
||||
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .onAppear:
|
||||
|
@ -134,6 +146,13 @@ public struct ImportWalletReducer: Reducer {
|
|||
case .nextPressed:
|
||||
return .none
|
||||
|
||||
case .restoreInfo:
|
||||
return .none
|
||||
|
||||
case .restoreInfoRequested(let newValue):
|
||||
state.restoreInfoViewBinding = newValue
|
||||
return .none
|
||||
|
||||
case .restoreWallet:
|
||||
do {
|
||||
// validate the seed
|
||||
|
@ -170,6 +189,7 @@ public struct ImportWalletReducer: Reducer {
|
|||
return .none
|
||||
|
||||
case .successfullyRecovered:
|
||||
state.restoreInfoViewBinding = true
|
||||
return .none
|
||||
|
||||
case .initializeSDK:
|
||||
|
@ -225,7 +245,7 @@ extension AlertState where Action == ImportWalletReducer.Action {
|
|||
// MARK: - Placeholders
|
||||
|
||||
extension ImportWalletReducer.State {
|
||||
public static let initial = ImportWalletReducer.State()
|
||||
public static let initial = ImportWalletReducer.State(restoreInfoState: .initial)
|
||||
}
|
||||
|
||||
extension ImportWalletStore {
|
||||
|
|
|
@ -10,6 +10,7 @@ import ComposableArchitecture
|
|||
import Generated
|
||||
import UIComponents
|
||||
import Utils
|
||||
import RestoreInfo
|
||||
|
||||
public struct ImportWalletView: View {
|
||||
private enum InputID: Hashable {
|
||||
|
@ -111,6 +112,20 @@ public struct ImportWalletView: View {
|
|||
isActive: viewStore.bindingForDestination(.birthday),
|
||||
destination: { ImportBirthdayView(store: store) }
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: Binding(
|
||||
get: { viewStore.state.restoreInfoViewBinding },
|
||||
set: { viewStore.send(.restoreInfoRequested($0)) }
|
||||
),
|
||||
destination: {
|
||||
RestoreInfoView(
|
||||
store: store.scope(
|
||||
state: \.restoreInfoState,
|
||||
action: ImportWalletReducer.Action.restoreInfo
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
.alert(store: store.scope(
|
||||
state: \.$alert,
|
||||
action: { .alert($0) }
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// RestoreInfoStore.swift
|
||||
// Zashi
|
||||
//
|
||||
// Created by Lukáš Korba on 06-03-2024
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
import Generated
|
||||
|
||||
@Reducer
|
||||
public struct RestoreInfo {
|
||||
@ObservableState
|
||||
public struct State: Equatable { }
|
||||
|
||||
public enum Action: Equatable {
|
||||
case gotItTapped
|
||||
}
|
||||
|
||||
public init() { }
|
||||
|
||||
public var body: some Reducer<State, Action> {
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .gotItTapped:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// RestoreInfoView.swift
|
||||
// Zashi
|
||||
//
|
||||
// Created by Lukáš Korba on 06-03-2024
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
import Generated
|
||||
import UIComponents
|
||||
|
||||
public struct RestoreInfoView: View {
|
||||
@Perception.Bindable var store: StoreOf<RestoreInfo>
|
||||
|
||||
public init(store: StoreOf<RestoreInfo>) {
|
||||
self.store = store
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
WithPerceptionTracking {
|
||||
ScrollView {
|
||||
Text(L10n.RestoreInfo.title)
|
||||
.font(.custom(FontFamily.Archivo.semiBold.name, size: 25))
|
||||
.padding(.vertical, 30)
|
||||
|
||||
Asset.Assets.restoreInfo.image
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 106, height: 168)
|
||||
.foregroundColor(Asset.Colors.primary.color)
|
||||
.padding(.bottom, 30)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(L10n.RestoreInfo.tips)
|
||||
.font(.custom(FontFamily.Inter.bold.name, size: 14))
|
||||
|
||||
bulletpoint(L10n.RestoreInfo.tip1)
|
||||
bulletpoint(L10n.RestoreInfo.tip2)
|
||||
bulletpoint(L10n.RestoreInfo.tip3)
|
||||
|
||||
Text(L10n.RestoreInfo.note)
|
||||
.font(.custom(FontFamily.Inter.medium.name, size: 11))
|
||||
.padding(.top, 20)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
|
||||
Button(L10n.RestoreInfo.gotIt.uppercased()) {
|
||||
store.send(.gotItTapped)
|
||||
}
|
||||
.zcashStyle()
|
||||
.padding(.vertical, 50)
|
||||
.padding(.horizontal, 40)
|
||||
}
|
||||
.padding(.horizontal, 50)
|
||||
.padding(.vertical, 1)
|
||||
.zashiBack(hidden: true)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.applyScreenBackground(withPattern: true)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func bulletpoint(_ text: String) -> some View {
|
||||
HStack(alignment: .top) {
|
||||
Circle()
|
||||
.frame(width: 4, height: 4)
|
||||
.padding(.top, 7)
|
||||
.padding(.leading, 8)
|
||||
|
||||
Text(text)
|
||||
.font(.custom(FontFamily.Inter.regular.name, size: 14))
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
#Preview {
|
||||
RestoreInfoView(store: RestoreInfo.initial)
|
||||
}
|
||||
|
||||
// MARK: - Store
|
||||
|
||||
extension RestoreInfo {
|
||||
public static var initial = StoreOf<RestoreInfo>(
|
||||
initialState: .initial
|
||||
) {
|
||||
RestoreInfo()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Placeholders
|
||||
|
||||
extension RestoreInfo.State {
|
||||
public static let initial = RestoreInfo.State()
|
||||
}
|
|
@ -444,8 +444,7 @@ extension RootReducer {
|
|||
return .none
|
||||
}
|
||||
|
||||
case .onboarding(.importWallet(.successfullyRecovered)):
|
||||
state.alert = AlertState.successfullyRecovered()
|
||||
case .onboarding(.importWallet(.restoreInfo(.gotItTapped))):
|
||||
return Effect.send(.destination(.updateDestination(.tabs)))
|
||||
|
||||
case .onboarding(.importWallet(.initializeSDK)):
|
||||
|
|
|
@ -303,6 +303,22 @@ public enum L10n {
|
|||
public static let wroteItDown = L10n.tr("Localizable", "recoveryPhraseDisplay.button.wroteItDown", fallback: "I've saved it")
|
||||
}
|
||||
}
|
||||
public enum RestoreInfo {
|
||||
/// Got it!
|
||||
public static let gotIt = L10n.tr("Localizable", "restoreInfo.gotIt", fallback: "Got it!")
|
||||
/// *Note: During the initial sync your funds cannot be sent or spent. Depending on the age of your wallet, it may take a few hours to fully sync.
|
||||
public static let note = L10n.tr("Localizable", "restoreInfo.note", fallback: "*Note: During the initial sync your funds cannot be sent or spent. Depending on the age of your wallet, it may take a few hours to fully sync.")
|
||||
/// Zashi needs to stay open in order to continue syncing.
|
||||
public static let tip1 = L10n.tr("Localizable", "restoreInfo.tip1", fallback: "Zashi needs to stay open in order to continue syncing.")
|
||||
/// To prevent interruption, plug your open phone into a power source.
|
||||
public static let tip2 = L10n.tr("Localizable", "restoreInfo.tip2", fallback: "To prevent interruption, plug your open phone into a power source.")
|
||||
/// Keep your open phone in a secure place.
|
||||
public static let tip3 = L10n.tr("Localizable", "restoreInfo.tip3", fallback: "Keep your open phone in a secure place.")
|
||||
/// Syncing Tips:
|
||||
public static let tips = L10n.tr("Localizable", "restoreInfo.tips", fallback: "Syncing Tips:")
|
||||
/// Your wallet has been successfully restored!*
|
||||
public static let title = L10n.tr("Localizable", "restoreInfo.title", fallback: "Your wallet has been successfully restored!*")
|
||||
}
|
||||
public enum Root {
|
||||
public enum Debug {
|
||||
/// Startup
|
||||
|
|
12
modules/Sources/Generated/Resources/Assets.xcassets/restoreInfo.imageset/Contents.json
vendored
Normal file
12
modules/Sources/Generated/Resources/Assets.xcassets/restoreInfo.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "restoreInfo.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
modules/Sources/Generated/Resources/Assets.xcassets/restoreInfo.imageset/restoreInfo.png
vendored
Normal file
BIN
modules/Sources/Generated/Resources/Assets.xcassets/restoreInfo.imageset/restoreInfo.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
|
@ -45,6 +45,15 @@
|
|||
"importWallet.optionalBirthday" = "(optional)";
|
||||
"importWallet.enterPlaceholder" = "privacy dignity freedom ...";
|
||||
|
||||
// MARK: - Restore Info
|
||||
"restoreInfo.title" = "Your wallet has been successfully restored!*";
|
||||
"restoreInfo.tips" = "Syncing Tips:";
|
||||
"restoreInfo.tip1" = "Zashi needs to stay open in order to continue syncing.";
|
||||
"restoreInfo.tip2" = "To prevent interruption, plug your open phone into a power source.";
|
||||
"restoreInfo.tip3" = "Keep your open phone in a secure place.";
|
||||
"restoreInfo.note" = "*Note: During the initial sync your funds cannot be sent or spent. Depending on the age of your wallet, it may take a few hours to fully sync.";
|
||||
"restoreInfo.gotIt" = "Got it!";
|
||||
|
||||
// MARK: - Tabs
|
||||
"tabs.account" = "Account";
|
||||
"tabs.send" = "Send";
|
||||
|
|
|
@ -34,6 +34,7 @@ public enum Asset {
|
|||
public static let eyeOn = ImageAsset(name: "eyeOn")
|
||||
public static let flyReceivedFilled = ImageAsset(name: "flyReceivedFilled")
|
||||
public static let gridTile = ImageAsset(name: "gridTile")
|
||||
public static let restoreInfo = ImageAsset(name: "restoreInfo")
|
||||
public static let share = ImageAsset(name: "share")
|
||||
public static let shield = ImageAsset(name: "shield")
|
||||
public static let surroundedShield = ImageAsset(name: "surroundedShield")
|
||||
|
|
Loading…
Reference in New Issue