Skip to content

Commit fb31e53

Browse files
committed
Merge branch 'feat/issue-307' of github.com:rubensmachion/BDKSwiftExampleWallet into feat/issue-307
* 'feat/issue-307' of github.com:rubensmachion/BDKSwiftExampleWallet: feat: added formatted in BalanceDisplayFormat refactor: client chore: onboarding text ui: fee view format ui: menu in receiveview feat: bip84 support ui: remove bip21q balance format fix: infreq could not load wallet chore: persister+extensions fix: show unspent amount
2 parents 3ca8e72 + 8408625 commit fb31e53

23 files changed

+687
-155
lines changed

BDKSwiftExampleWallet.xcodeproj/project.pbxproj

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
779E70872DB9C98A006E22D3 /* WalletSyncScriptInspector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779E70862DB9C98A006E22D3 /* WalletSyncScriptInspector.swift */; };
1212
779E70892DB9C9AB006E22D3 /* WalletFullScanScriptInspector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779E70882DB9C9AB006E22D3 /* WalletFullScanScriptInspector.swift */; };
1313
77AD9F062DBB031D00182E65 /* ActivityHomeHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AD9F052DBB031D00182E65 /* ActivityHomeHeaderView.swift */; };
14-
77F0FDC92DA9A93D00B30E4F /* Connection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F0FDC82DA9A93700B30E4F /* Connection+Extensions.swift */; };
14+
77EDA65B2E2A5B4000A5E3AD /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77EDA65A2E2A5B3800A5E3AD /* URL+Extensions.swift */; };
15+
77F0FDC92DA9A93D00B30E4F /* Persister+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F0FDC82DA9A93700B30E4F /* Persister+Extensions.swift */; };
1516
A733D6D02A81113000F333B4 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = A733D6CF2A81113000F333B4 /* Localizable.xcstrings */; };
1617
A73F7A362A3B778E00B87FC6 /* Int+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A73F7A352A3B778E00B87FC6 /* Int+Extensions.swift */; };
1718
AE0C30F72A804A2D008F1EAE /* TransactionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE0C30F62A804A2D008F1EAE /* TransactionListView.swift */; };
@@ -80,7 +81,9 @@
8081
AE91CEED2C0FDB70000AAD20 /* SentAndReceivedValues+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE91CEEC2C0FDB70000AAD20 /* SentAndReceivedValues+Extensions.swift */; };
8182
AE91CEEF2C0FDBC7000AAD20 /* CanonicalTx+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE91CEEE2C0FDBC7000AAD20 /* CanonicalTx+Extensions.swift */; };
8283
AE96F6622A424C400055623C /* BDKSwiftExampleWalletReceiveViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE96F6612A424C400055623C /* BDKSwiftExampleWalletReceiveViewModelTests.swift */; };
84+
AE97E74D2E315A8F000A407D /* AddressType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE97E74C2E315A8F000A407D /* AddressType+Extensions.swift */; };
8385
AEA0A6272E297203008A525B /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = AEA0A6262E297203008A525B /* BitcoinDevKit */; };
86+
AEAA61BF2E380D62006ED2D0 /* Notification+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEAA61BE2E380D62006ED2D0 /* Notification+Extensions.swift */; };
8487
AEAB03112ABDDB86000C9528 /* FeeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEAB03102ABDDB86000C9528 /* FeeViewModel.swift */; };
8588
AEAB03132ABDDBF4000C9528 /* AmountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEAB03122ABDDBF4000C9528 /* AmountViewModel.swift */; };
8689
AEAF83B62B7BD4D10019B23B /* CodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = AEAF83B52B7BD4D10019B23B /* CodeScanner */; };
@@ -121,7 +124,8 @@
121124
779E70862DB9C98A006E22D3 /* WalletSyncScriptInspector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSyncScriptInspector.swift; sourceTree = "<group>"; };
122125
779E70882DB9C9AB006E22D3 /* WalletFullScanScriptInspector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletFullScanScriptInspector.swift; sourceTree = "<group>"; };
123126
77AD9F052DBB031D00182E65 /* ActivityHomeHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityHomeHeaderView.swift; sourceTree = "<group>"; };
124-
77F0FDC82DA9A93700B30E4F /* Connection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Connection+Extensions.swift"; sourceTree = "<group>"; };
127+
77EDA65A2E2A5B3800A5E3AD /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = "<group>"; };
128+
77F0FDC82DA9A93700B30E4F /* Persister+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Persister+Extensions.swift"; sourceTree = "<group>"; };
125129
A733D6CF2A81113000F333B4 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
126130
A73F7A352A3B778E00B87FC6 /* Int+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Extensions.swift"; sourceTree = "<group>"; };
127131
AE0C30F62A804A2D008F1EAE /* TransactionListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionListView.swift; sourceTree = "<group>"; };
@@ -185,6 +189,8 @@
185189
AE91CEEC2C0FDB70000AAD20 /* SentAndReceivedValues+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SentAndReceivedValues+Extensions.swift"; sourceTree = "<group>"; };
186190
AE91CEEE2C0FDBC7000AAD20 /* CanonicalTx+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CanonicalTx+Extensions.swift"; sourceTree = "<group>"; };
187191
AE96F6612A424C400055623C /* BDKSwiftExampleWalletReceiveViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletReceiveViewModelTests.swift; sourceTree = "<group>"; };
192+
AE97E74C2E315A8F000A407D /* AddressType+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddressType+Extensions.swift"; sourceTree = "<group>"; };
193+
AEAA61BE2E380D62006ED2D0 /* Notification+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Extensions.swift"; sourceTree = "<group>"; };
188194
AEAB03102ABDDB86000C9528 /* FeeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeeViewModel.swift; sourceTree = "<group>"; };
189195
AEAB03122ABDDBF4000C9528 /* AmountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmountViewModel.swift; sourceTree = "<group>"; };
190196
AEB130C82A44E4850087785B /* TransactionDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionDetailView.swift; sourceTree = "<group>"; };
@@ -289,6 +295,7 @@
289295
AE7F67062A744CE200CED561 /* Double+Extensions.swift */,
290296
AEB159D42D51A8680006AE9E /* View+Extensions.swift */,
291297
AE8D001B2D19F1760029C4C9 /* UIScreen+Extensions.swift */,
298+
AEAA61BE2E380D62006ED2D0 /* Notification+Extensions.swift */,
292299
AEE6C74D2ABCB48600442ADD /* BDK+Extensions */,
293300
);
294301
path = Extensions;
@@ -564,7 +571,9 @@
564571
AEE6C74D2ABCB48600442ADD /* BDK+Extensions */ = {
565572
isa = PBXGroup;
566573
children = (
567-
77F0FDC82DA9A93700B30E4F /* Connection+Extensions.swift */,
574+
77EDA65A2E2A5B3800A5E3AD /* URL+Extensions.swift */,
575+
AE97E74C2E315A8F000A407D /* AddressType+Extensions.swift */,
576+
77F0FDC82DA9A93700B30E4F /* Persister+Extensions.swift */,
568577
AEE6C74B2ABCB3E200442ADD /* Transaction+Extensions.swift */,
569578
AE83EFDA2C9D07B200B41244 /* ChainPosition+Extensions.swift */,
570579
AE2381B02C60690900F6B00C /* LocalOutput+Extensions.swift */,
@@ -739,6 +748,7 @@
739748
AEB130C92A44E4850087785B /* TransactionDetailView.swift in Sources */,
740749
AE287E772C0F6D200036A748 /* Array+Extensions.swift in Sources */,
741750
AE6715FD2A9AC056005C193F /* PriceServiceError.swift in Sources */,
751+
AEAA61BF2E380D62006ED2D0 /* Notification+Extensions.swift in Sources */,
742752
AE34DDAC2B6B31ED00F04AD4 /* WalletRecoveryView.swift in Sources */,
743753
AE2ADD742B61E8F500C2A823 /* SettingsView.swift in Sources */,
744754
AE2381AF2C605B1D00F6B00C /* ActivityListViewModel.swift in Sources */,
@@ -759,9 +769,11 @@
759769
AE783A012AB4E5E1005F0CBA /* BuildTransactionView.swift in Sources */,
760770
AE6F34DA2AA6C1E00087E700 /* Balance+Extensions.swift in Sources */,
761771
AED4CC0C2A1D3A9400CE1831 /* OnboardingView.swift in Sources */,
762-
77F0FDC92DA9A93D00B30E4F /* Connection+Extensions.swift in Sources */,
772+
AE97E74D2E315A8F000A407D /* AddressType+Extensions.swift in Sources */,
773+
77F0FDC92DA9A93D00B30E4F /* Persister+Extensions.swift in Sources */,
763774
AE6716012A9AC089005C193F /* KeyServiceError.swift in Sources */,
764775
77AD9F062DBB031D00182E65 /* ActivityHomeHeaderView.swift in Sources */,
776+
77EDA65B2E2A5B4000A5E3AD /* URL+Extensions.swift in Sources */,
765777
AE0C30FB2A804B95008F1EAE /* WalletViewModel.swift in Sources */,
766778
AE49847C2A1BBBD6009951E2 /* BDKSwiftExampleWalletApp.swift in Sources */,
767779
AE6715FF2A9AC066005C193F /* FeeServiceError.swift in Sources */,

BDKSwiftExampleWallet/App/BDKSwiftExampleWalletApp.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import SwiftUI
1212
struct BDKSwiftExampleWalletApp: App {
1313
@AppStorage("isOnboarding") var isOnboarding: Bool = true
1414
@State private var navigationPath = NavigationPath()
15+
@State private var refreshTrigger = UUID()
1516

1617
var body: some Scene {
1718
WindowGroup {
1819
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) {
20+
if !walletExists {
2321
OnboardingView(viewModel: .init(bdkClient: .live))
22+
.onReceive(NotificationCenter.default.publisher(for: .walletCreated)) { _ in
23+
refreshTrigger = UUID()
24+
}
2425
} else {
2526
HomeView(viewModel: .init(bdkClient: .live), navigationPath: $navigationPath)
2627
}
@@ -32,3 +33,12 @@ struct BDKSwiftExampleWalletApp: App {
3233
}
3334
}
3435
}
36+
37+
extension BDKSwiftExampleWalletApp {
38+
private var walletExists: Bool {
39+
// Force re-evaluation by reading refreshTrigger and isOnboarding
40+
let _ = refreshTrigger
41+
let _ = isOnboarding
42+
return (try? KeyClient.live.getBackupInfo()) != nil
43+
}
44+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// AddressType+Extensions.swift
3+
// BDKSwiftExampleWallet
4+
//
5+
// Created by Matthew Ramsden on 7/23/25.
6+
//
7+
8+
import Foundation
9+
10+
enum AddressType: String, CaseIterable {
11+
case bip86 = "bip86"
12+
case bip84 = "bip84"
13+
14+
var description: String {
15+
switch self {
16+
case .bip86: return "bip86"
17+
case .bip84: return "bip84"
18+
}
19+
}
20+
21+
var displayName: String {
22+
switch self {
23+
case .bip86: return "BIP86 (Taproot)"
24+
case .bip84: return "BIP84 (SegWit)"
25+
}
26+
}
27+
28+
init?(stringValue: String) {
29+
switch stringValue {
30+
case "bip86": self = .bip86
31+
case "bip84": self = .bip84
32+
default: return nil
33+
}
34+
}
35+
}

BDKSwiftExampleWallet/Extensions/BDK+Extensions/Connection+Extensions.swift

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import BitcoinDevKit
2+
import Foundation
3+
4+
extension Persister {
5+
static func createConnection() throws -> Persister {
6+
try deleteConnection()
7+
try FileManager.default.ensureDirectoryExists(at: URL.walletDataDirectoryURL)
8+
try FileManager.default.removeOldFlatFileIfNeeded(at: URL.defaultWalletDirectory)
9+
let persister = try Persister.newSqlite(path: URL.persistenceBackendPath)
10+
return persister
11+
}
12+
13+
static func loadConnection() throws -> Persister {
14+
let persistenceBackendPath = URL.persistenceBackendPath
15+
let persister = try Persister.newSqlite(path: persistenceBackendPath)
16+
return persister
17+
}
18+
19+
static func deleteConnection() throws {
20+
let walletDataDirectoryURL = URL.walletDataDirectoryURL
21+
if FileManager.default.fileExists(atPath: walletDataDirectoryURL.path) {
22+
try FileManager.default.removeItem(at: walletDataDirectoryURL)
23+
}
24+
}
25+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// URL+Extensions.swift
3+
// BDKSwiftExampleWallet
4+
//
5+
// Created by Rubens Machion on 17/05/25.
6+
//
7+
8+
import Foundation
9+
10+
extension URL {
11+
12+
static var defaultWalletDirectory: URL {
13+
URL.documentsDirectory
14+
}
15+
16+
static var walletDirectoryName: String {
17+
"wallet_data"
18+
}
19+
20+
static var walletDBName: String {
21+
"wallet.sqlite"
22+
}
23+
24+
static var walletDataDirectoryURL: URL {
25+
defaultWalletDirectory.appendingPathComponent(walletDirectoryName)
26+
}
27+
28+
static var persistenceBackendPath: String {
29+
walletDataDirectoryURL.appendingPathComponent(walletDBName).path
30+
}
31+
}

BDKSwiftExampleWallet/Extensions/Int+Extensions.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,49 +40,49 @@ extension UInt64 {
4040
numberFormatter.usesGroupingSeparator = true
4141
numberFormatter.groupingSeparator = ","
4242
numberFormatter.generatesDecimalNumbers = false
43-
43+
4444
return numberFormatter
4545
}
46-
46+
4747
func formattedSatoshis() -> String {
4848
if self == 0 {
4949
return "0.00 000 000"
5050
} else {
5151
// Convert satoshis to BTC (1 BTC = 100,000,000 sats)
5252
let btcValue = Double(self) / 100_000_000.0
53-
53+
5454
// Format BTC value to exactly 8 decimal places
5555
let btcString = String(format: "%.8f", btcValue)
56-
56+
5757
// Split the string at the decimal point
5858
let parts = btcString.split(separator: ".")
5959
guard parts.count == 2 else { return btcString }
60-
60+
6161
let wholePart = String(parts[0])
6262
let decimalPart = String(parts[1])
63-
63+
6464
// Ensure decimal part is exactly 8 digits
6565
let paddedDecimal = decimalPart.padding(toLength: 8, withPad: "0", startingAt: 0)
66-
66+
6767
// Format as XX.XX XXX XXX
6868
let first = paddedDecimal.prefix(2)
6969
let second = paddedDecimal.dropFirst(2).prefix(3)
7070
let third = paddedDecimal.dropFirst(5).prefix(3)
71-
71+
7272
let formattedBalance = "\(wholePart).\(first) \(second) \(third)"
7373

7474
return formattedBalance
7575
}
7676
}
77-
77+
7878
func formattedBip177() -> String {
7979
if self != .zero && self >= 1_000_000 && self % 1_000_000 == .zero {
8080
return "\(self / 1_000_000)M"
81-
81+
8282
} else if self != .zero && self % 1_000 == 0 {
8383
return "\(self / 1_000)K"
8484
}
85-
85+
8686
return numberFormatter.string(from: NSNumber(value: self)) ?? "0"
8787
}
8888
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// Notification+Extensions.swift
3+
// BDKSwiftExampleWallet
4+
//
5+
// Created by Matthew Ramsden on 7/28/25.
6+
//
7+
8+
import Foundation
9+
10+
extension Notification.Name {
11+
static let walletCreated = Notification.Name("walletCreated")
12+
}

BDKSwiftExampleWallet/Model/BalanceDisplayFormat.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ enum BalanceDisplayFormat: String, CaseIterable, Codable {
1111
case bitcoinSats = "bitcoinSats"
1212
case bitcoin = "btc"
1313
case sats = "sats"
14-
case bip21q = "bip21q"
14+
// case bip21q = "bip21q"
1515
case fiat = "usd"
1616
case bip177 = "bip177"
1717

1818
var displayText: String {
1919
switch self {
2020
case .sats, .bitcoinSats: return "sats"
2121
case .bitcoin, .bip177: return ""
22-
case .bip21q: return ""
22+
// case .bip21q: return "₿"
2323
case .fiat: return "USD"
2424
}
2525
}

0 commit comments

Comments
 (0)