Skip to content

Commit ee90b03

Browse files
committed
fix: address switch refresh
1 parent e1a621c commit ee90b03

File tree

5 files changed

+102
-23
lines changed

5 files changed

+102
-23
lines changed

BDKSwiftExampleWallet/App/BDKSwiftExampleWalletApp.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,31 @@
88
import BitcoinDevKit
99
import SwiftUI
1010

11+
extension Notification.Name {
12+
static let walletCreated = Notification.Name("walletCreated")
13+
}
14+
1115
@main
1216
struct BDKSwiftExampleWalletApp: App {
1317
@AppStorage("isOnboarding") var isOnboarding: Bool = true
1418
@State private var navigationPath = NavigationPath()
19+
@State private var refreshTrigger = UUID()
20+
21+
private var walletExists: Bool {
22+
// Force re-evaluation by reading refreshTrigger and isOnboarding
23+
let _ = refreshTrigger
24+
let _ = isOnboarding
25+
return (try? KeyClient.live.getBackupInfo()) != nil
26+
}
1527

1628
var body: some Scene {
1729
WindowGroup {
1830
NavigationStack(path: $navigationPath) {
19-
let value = try? KeyClient.live.getBackupInfo()
20-
if isOnboarding && (value == nil) {
21-
OnboardingView(viewModel: .init(bdkClient: .live))
22-
} else if !isOnboarding && (value == nil) {
31+
if !walletExists {
2332
OnboardingView(viewModel: .init(bdkClient: .live))
33+
.onReceive(NotificationCenter.default.publisher(for: .walletCreated)) { _ in
34+
refreshTrigger = UUID()
35+
}
2436
} else {
2537
HomeView(viewModel: .init(bdkClient: .live), navigationPath: $navigationPath)
2638
}

BDKSwiftExampleWallet/Resources/Localizable.xcstrings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@
535535
}
536536
}
537537
}
538+
},
539+
"Creating..." : {
540+
538541
},
539542
"Danger Zone" : {
540543
"localizations" : {

BDKSwiftExampleWallet/Service/BDK Service/BDKService.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,6 @@ private class BDKService {
408408
self.wallet = wallet
409409
} catch is LoadWithPersistError {
410410
// Database is corrupted or incompatible, delete and recreate
411-
print("Wallet database is corrupted, recreating...")
412411
try Persister.deleteConnection()
413412

414413
let persister = try Persister.createConnection()
@@ -583,7 +582,13 @@ extension BDKService {
583582
}
584583

585584
func updateAddressType(_ newAddressType: AddressType) {
585+
let currentType = getCurrentAddressType()
586586
try? keyClient.saveAddressType(newAddressType.description)
587+
588+
// If address type changed, we need a full scan to find transactions with new derivation paths
589+
if currentType != newAddressType {
590+
needsFullScan = true
591+
}
587592
}
588593

589594
func updateClientType(_ newType: BlockchainClientType) {

BDKSwiftExampleWallet/View Model/OnboardingViewModel.swift

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,34 @@ import BitcoinDevKit
99
import Foundation
1010
import SwiftUI
1111

12+
struct TimeoutError: Error {}
13+
14+
func withTimeout<T>(seconds: TimeInterval, operation: @escaping () throws -> T) async throws -> T {
15+
try await withThrowingTaskGroup(of: T.self) { group in
16+
group.addTask {
17+
return try operation()
18+
}
19+
20+
group.addTask {
21+
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
22+
throw TimeoutError()
23+
}
24+
25+
let result = try await group.next()!
26+
group.cancelAll()
27+
return result
28+
}
29+
}
30+
1231
// Can't make @Observable yet
1332
// https://developer.apple.com/forums/thread/731187
1433
// Feature or Bug?
1534
class OnboardingViewModel: ObservableObject {
1635
let bdkClient: BDKClient
1736

18-
@AppStorage("isOnboarding") var isOnboarding: Bool?
37+
@AppStorage("isOnboarding") var isOnboarding: Bool = true
1938
@Published var createWithPersistError: CreateWithPersistError?
39+
@Published var isCreatingWallet = false
2040
var isDescriptor: Bool {
2141
words.hasPrefix("tr(") || words.hasPrefix("wpkh(") || words.hasPrefix("wsh(")
2242
|| words.hasPrefix("sh(")
@@ -90,24 +110,53 @@ class OnboardingViewModel: ObservableObject {
90110
}
91111

92112
func createWallet() {
93-
do {
94-
if isDescriptor {
95-
try bdkClient.createWalletFromDescriptor(words)
96-
} else if isXPub {
97-
try bdkClient.createWalletFromXPub(words)
98-
} else {
99-
try bdkClient.createWalletFromSeed(words)
100-
}
113+
// Check if wallet already exists
114+
if let existingBackup = try? bdkClient.getBackupInfo() {
101115
DispatchQueue.main.async {
102116
self.isOnboarding = false
103117
}
104-
} catch let error as CreateWithPersistError {
105-
DispatchQueue.main.async {
106-
self.createWithPersistError = error
107-
}
108-
} catch {
109-
DispatchQueue.main.async {
110-
self.onboardingViewError = .generic(message: error.localizedDescription)
118+
return
119+
}
120+
121+
guard !isCreatingWallet else {
122+
return
123+
}
124+
125+
DispatchQueue.main.async {
126+
self.isCreatingWallet = true
127+
}
128+
129+
Task {
130+
do {
131+
try await withTimeout(seconds: 30) {
132+
if self.isDescriptor {
133+
try self.bdkClient.createWalletFromDescriptor(self.words)
134+
} else if self.isXPub {
135+
try self.bdkClient.createWalletFromXPub(self.words)
136+
} else {
137+
try self.bdkClient.createWalletFromSeed(self.words)
138+
}
139+
}
140+
DispatchQueue.main.async {
141+
self.isCreatingWallet = false
142+
self.isOnboarding = false
143+
NotificationCenter.default.post(name: .walletCreated, object: nil)
144+
}
145+
} catch let error as CreateWithPersistError {
146+
DispatchQueue.main.async {
147+
self.isCreatingWallet = false
148+
self.createWithPersistError = error
149+
}
150+
} catch is TimeoutError {
151+
DispatchQueue.main.async {
152+
self.isCreatingWallet = false
153+
self.onboardingViewError = .generic(message: "Wallet creation timed out. Please try again.")
154+
}
155+
} catch {
156+
DispatchQueue.main.async {
157+
self.isCreatingWallet = false
158+
self.onboardingViewError = .generic(message: error.localizedDescription)
159+
}
111160
}
112161
}
113162
}

BDKSwiftExampleWallet/View/OnboardingView.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import BitcoinUI
1010
import SwiftUI
1111

1212
struct OnboardingView: View {
13-
@AppStorage("isOnboarding") var isOnboarding: Bool?
13+
@AppStorage("isOnboarding") var isOnboarding: Bool = true
1414
@ObservedObject var viewModel: OnboardingViewModel
1515
@State private var showingOnboardingViewErrorAlert = false
1616
@State private var showingImportView = false
@@ -176,9 +176,19 @@ struct OnboardingView: View {
176176

177177
Spacer()
178178

179-
Button("Create Wallet") {
179+
Button(action: {
180180
viewModel.createWallet()
181+
}) {
182+
HStack {
183+
if viewModel.isCreatingWallet {
184+
ProgressView()
185+
.scaleEffect(0.8)
186+
.foregroundColor(Color(uiColor: .systemBackground))
187+
}
188+
Text(viewModel.isCreatingWallet ? "Creating..." : "Create Wallet")
189+
}
181190
}
191+
.disabled(viewModel.isCreatingWallet)
182192
.buttonStyle(
183193
BitcoinFilled(
184194
tintColor: .primary,

0 commit comments

Comments
 (0)