BUG: broken seek of the cursor in the restore wallet inputs
This commit is contained in:
parent
f105a1adf4
commit
6bbdf05abd
|
@ -31,7 +31,7 @@ public struct ImportBirthdayView: View {
|
|||
|
||||
Text(L10n.ImportWallet.optionalBirthday)
|
||||
|
||||
TextField("", text: store.bindingForRedactableBirthday(store.birthdayHeight))
|
||||
TextField("", text: $store.birthdayHeight)
|
||||
.frame(height: 40)
|
||||
.font(.custom(FontFamily.Inter.semiBold.name, size: 25))
|
||||
.focused($isFocused)
|
||||
|
|
|
@ -25,10 +25,10 @@ public struct ImportWallet {
|
|||
}
|
||||
|
||||
@Presents public var alert: AlertState<Action>?
|
||||
public var birthdayHeight = RedactableString.empty
|
||||
public var birthdayHeight = ""
|
||||
public var birthdayHeightValue: RedactableBlockHeight?
|
||||
public var destination: Destination?
|
||||
public var importedSeedPhrase = RedactableString.empty
|
||||
public var importedSeedPhrase = ""
|
||||
public var isValidMnemonic = false
|
||||
public var isValidNumberOfWords = false
|
||||
public var maxWordsCount = 0
|
||||
|
@ -46,15 +46,15 @@ public struct ImportWallet {
|
|||
|
||||
public var isValidForm: Bool {
|
||||
isValidMnemonic &&
|
||||
(birthdayHeight.data.isEmpty ||
|
||||
(!birthdayHeight.data.isEmpty && birthdayHeightValue != nil))
|
||||
(birthdayHeight.isEmpty ||
|
||||
(!birthdayHeight.isEmpty && birthdayHeightValue != nil))
|
||||
}
|
||||
|
||||
public init(
|
||||
birthdayHeight: RedactableString = .empty,
|
||||
birthdayHeight: String = "",
|
||||
birthdayHeightValue: RedactableBlockHeight? = nil,
|
||||
destination: Destination? = nil,
|
||||
importedSeedPhrase: RedactableString = .empty,
|
||||
importedSeedPhrase: String = "",
|
||||
isValidMnemonic: Bool = false,
|
||||
isValidNumberOfWords: Bool = false,
|
||||
maxWordsCount: Int = 0,
|
||||
|
@ -76,7 +76,6 @@ public struct ImportWallet {
|
|||
public enum Action: BindableAction, Equatable {
|
||||
case alert(PresentationAction<Action>)
|
||||
case binding(BindingAction<ImportWallet.State>)
|
||||
case birthdayInputChanged(RedactableString)
|
||||
case importPrivateOrViewingKey
|
||||
case initializeSDK
|
||||
case nextPressed
|
||||
|
@ -84,7 +83,6 @@ public struct ImportWallet {
|
|||
case restoreInfo(RestoreInfo.Action)
|
||||
case restoreInfoRequested(Bool)
|
||||
case restoreWallet
|
||||
case seedPhraseInputChanged(RedactableString)
|
||||
case successfullyRecovered
|
||||
case updateDestination(ImportWallet.State.Destination?)
|
||||
}
|
||||
|
@ -107,17 +105,16 @@ public struct ImportWallet {
|
|||
case .onAppear:
|
||||
state.maxWordsCount = zcashSDKEnvironment.mnemonicWordsMaxCount
|
||||
return .none
|
||||
|
||||
case .binding:
|
||||
|
||||
case .binding(\.importedSeedPhrase):
|
||||
return .none
|
||||
|
||||
case .seedPhraseInputChanged(let redactedSeedPhrase):
|
||||
state.importedSeedPhrase = redactedSeedPhrase
|
||||
state.wordsCount = state.importedSeedPhrase.data.split(separator: " ").count
|
||||
|
||||
case .binding(\.importedSeedPhrase):
|
||||
state.wordsCount = state.importedSeedPhrase.split(separator: " ").count
|
||||
state.isValidNumberOfWords = state.wordsCount == state.maxWordsCount
|
||||
// is the mnemonic valid one?
|
||||
do {
|
||||
try mnemonic.isValid(state.importedSeedPhrase.data)
|
||||
try mnemonic.isValid(state.importedSeedPhrase)
|
||||
} catch {
|
||||
state.isValidMnemonic = false
|
||||
return .none
|
||||
|
@ -125,18 +122,19 @@ public struct ImportWallet {
|
|||
state.isValidMnemonic = true
|
||||
return .none
|
||||
|
||||
case .birthdayInputChanged(let redactedBirthday):
|
||||
case .binding(\.birthdayHeight):
|
||||
let saplingActivation = zcashSDKEnvironment.network.constants.saplingActivationHeight
|
||||
|
||||
state.birthdayHeight = redactedBirthday
|
||||
|
||||
if let birthdayHeight = BlockHeight(state.birthdayHeight.data), birthdayHeight >= saplingActivation {
|
||||
if let birthdayHeight = BlockHeight(state.birthdayHeight), birthdayHeight >= saplingActivation {
|
||||
state.birthdayHeightValue = birthdayHeight.redacted
|
||||
} else {
|
||||
state.birthdayHeightValue = nil
|
||||
}
|
||||
return .none
|
||||
|
||||
case .binding:
|
||||
return .none
|
||||
|
||||
case .alert(.presented(let action)):
|
||||
return Effect.send(action)
|
||||
|
||||
|
@ -160,19 +158,19 @@ public struct ImportWallet {
|
|||
case .restoreWallet:
|
||||
do {
|
||||
// validate the seed
|
||||
try mnemonic.isValid(state.importedSeedPhrase.data)
|
||||
try mnemonic.isValid(state.importedSeedPhrase)
|
||||
|
||||
// store it to the keychain, if the user did not input a height,
|
||||
// fall back to sapling activation
|
||||
let birthday = state.birthdayHeightValue ?? zcashSDKEnvironment.network.constants.saplingActivationHeight.redacted
|
||||
|
||||
try walletStorage.importWallet(state.importedSeedPhrase.data, birthday.data, .english, false)
|
||||
try walletStorage.importWallet(state.importedSeedPhrase, birthday.data, .english, false)
|
||||
|
||||
// update the backup phrase validation flag
|
||||
try walletStorage.markUserPassedPhraseBackupTest(true)
|
||||
|
||||
state.birthdayHeight = .empty
|
||||
state.importedSeedPhrase = .empty
|
||||
state.birthdayHeight = ""
|
||||
state.importedSeedPhrase = ""
|
||||
|
||||
// notify user
|
||||
return .concatenate(
|
||||
|
|
|
@ -48,7 +48,7 @@ public struct ImportWalletView: View {
|
|||
.padding(.horizontal, 10)
|
||||
|
||||
WithPerceptionTracking {
|
||||
TextEditor(text: store.bindingForRedactableSeedPhrase(store.importedSeedPhrase))
|
||||
TextEditor(text: $store.importedSeedPhrase)
|
||||
.autocapitalization(.none)
|
||||
.padding(8)
|
||||
.background {
|
||||
|
@ -74,7 +74,7 @@ public struct ImportWalletView: View {
|
|||
}
|
||||
.overlay {
|
||||
WithPerceptionTracking {
|
||||
if store.importedSeedPhrase.data.isEmpty {
|
||||
if store.importedSeedPhrase.isEmpty {
|
||||
HStack {
|
||||
VStack {
|
||||
Text(L10n.ImportWallet.enterPlaceholder)
|
||||
|
@ -209,20 +209,6 @@ extension StoreOf<ImportWallet> {
|
|||
set: { self.send(.updateDestination($0 ? destination : nil)) }
|
||||
)
|
||||
}
|
||||
|
||||
func bindingForRedactableSeedPhrase(_ importedSeedPhrase: RedactableString) -> Binding<String> {
|
||||
Binding<String>(
|
||||
get: { importedSeedPhrase.data },
|
||||
set: { self.send(.seedPhraseInputChanged($0.redacted)) }
|
||||
)
|
||||
}
|
||||
|
||||
func bindingForRedactableBirthday(_ birthdayHeight: RedactableString) -> Binding<String> {
|
||||
Binding<String>(
|
||||
get: { birthdayHeight.data },
|
||||
set: { self.send(.birthdayInputChanged($0.redacted)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Placeholders
|
||||
|
|
|
@ -528,7 +528,7 @@ extension Root {
|
|||
|
||||
case .onboarding(.importWallet(.nextPressed)):
|
||||
if state.appInitializationState == .keysMissing {
|
||||
let seedPhrase = state.onboardingState.importWalletState.importedSeedPhrase.data
|
||||
let seedPhrase = state.onboardingState.importWalletState.importedSeedPhrase
|
||||
return .run { send in
|
||||
do {
|
||||
let seedBytes = try mnemonic.toSeed(seedPhrase)
|
||||
|
|
|
@ -91,8 +91,8 @@ extension SecantApp {
|
|||
featureFlags = FeatureFlags()
|
||||
#elseif SECANT_TESTNET
|
||||
featureFlags = FeatureFlags(
|
||||
flexa: true,
|
||||
appLaunchBiometric: true,
|
||||
flexa: true,
|
||||
sendingScreen: true
|
||||
)
|
||||
#else
|
||||
|
|
|
@ -38,14 +38,12 @@ class ImportWalletTests: XCTestCase {
|
|||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.mnemonic.isValid = { _ in throw "invalid mnemonic" }
|
||||
|
||||
let seedPhrase = "one two three".redacted
|
||||
let seedPhrase = "one two three"
|
||||
|
||||
await store.send(.seedPhraseInputChanged(seedPhrase)) { state in
|
||||
await store.send(.binding(.set(\.importedSeedPhrase, seedPhrase))) { state in
|
||||
state.importedSeedPhrase = seedPhrase
|
||||
state.wordsCount = 3
|
||||
state.isValidMnemonic = false
|
||||
}
|
||||
|
||||
|
||||
await store.finish()
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,9 @@ class SettingsTests: XCTestCase {
|
|||
markUserPassedPhraseBackupTest: { _ in
|
||||
throw WalletStorage.KeychainError.encoding
|
||||
},
|
||||
resetZashi: { }
|
||||
resetZashi: { },
|
||||
importAddressBookEncryptionKeys: { _ in },
|
||||
exportAddressBookEncryptionKeys: { .empty }
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
|
@ -91,30 +93,7 @@ class SettingsTests: XCTestCase {
|
|||
|
||||
await store.finish()
|
||||
}
|
||||
|
||||
func testCopySupportEmail() async throws {
|
||||
let store = TestStore(
|
||||
initialState: .initial
|
||||
) {
|
||||
Settings()
|
||||
}
|
||||
|
||||
let testPasteboard = PasteboardClient.testPasteboard
|
||||
store.dependencies.pasteboard = testPasteboard
|
||||
|
||||
await store.send(.copyEmail)
|
||||
|
||||
let supportEmail = SupportDataGenerator.Constants.email
|
||||
|
||||
XCTAssertEqual(
|
||||
testPasteboard.getString()?.data,
|
||||
supportEmail,
|
||||
"SettingsTests: `testCopySupportEmail` is expected to match the input `\(supportEmail)`"
|
||||
)
|
||||
|
||||
await store.finish()
|
||||
}
|
||||
|
||||
func testSupportDataGeneratorSubject() async throws {
|
||||
let generator = SupportDataGenerator.generate()
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ class TabsTests: XCTestCase {
|
|||
store.dependencies.sdkSynchronizer = .mock
|
||||
let proposal = Proposal.testOnlyFakeProposal(totalFee: 10_000)
|
||||
store.dependencies.sdkSynchronizer.proposeShielding = { _, _, _, _ in proposal }
|
||||
store.dependencies.sdkSynchronizer.createProposedTransactions = { _, _ in .success }
|
||||
store.dependencies.sdkSynchronizer.createProposedTransactions = { _, _ in .success(txIds: []) }
|
||||
store.dependencies.derivationTool = .liveValue
|
||||
store.dependencies.mnemonic = .mock
|
||||
store.dependencies.walletStorage.exportWallet = { .placeholder }
|
||||
|
@ -192,7 +192,7 @@ class TabsTests: XCTestCase {
|
|||
}
|
||||
|
||||
let accountsBalances = [AccountUUID(id: Array<UInt8>(repeating: 0, count: 16)): AccountBalance(saplingBalance: .zero, orchardBalance: .zero, unshielded: .zero)]
|
||||
await store.receive(.balanceBreakdown(.walletBalances(.balancesUpdated(accountsBalances))))
|
||||
await store.receive(.balanceBreakdown(.walletBalances(.balanceUpdated(accountsBalances.first?.value))))
|
||||
|
||||
await store.receive(.balanceBreakdown(.updateBalances(accountsBalances)))
|
||||
|
||||
|
|
Loading…
Reference in New Issue