-
Notifications
You must be signed in to change notification settings - Fork 3
feat: home-screen hardware wallet (watch-only) #605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
658f76e
feat: xpub persistence
jvsena42 e4be493
bump bitkit-core and adapt code
jvsena42 8e1d8ad
feat: adapt code to pesist activities via bitkit-core wallet-scoped s…
jvsena42 4f8a292
feat: balance + home device row
jvsena42 02f2dfc
feat: hardware suggestion and sheet
jvsena42 69d725c
feat: activity merge and sheet receive
jvsena42 befcb93
refactor: dependency decoupling
jvsena42 571dfed
test: test parity
jvsena42 fad790d
doc: changelog
jvsena42 5510a4d
fix: reimport device ilustrations
jvsena42 9540676
refactor: extract magic numbers and use better constant naming
jvsena42 097b08c
refactor: extract HW onChain methods to a vendor agnostic protocol
jvsena42 7c8fb79
refactor: make chunck code more readable
jvsena42 763d0a4
refactor: remove redundant comments
jvsena42 1b03abf
refactor: remove redundant comment
jvsena42 9a92952
chore: add preview
jvsena42 a6b48e7
fix: disable RBF, contact and tag features for HW activity detail
jvsena42 e336467
fix: set wallet scope for tag methods
jvsena42 d239df2
fix: set wallet id for refresh method in explore
jvsena42 384e62f
fix: set fallback timestamp for unconfirmed HW transactions
jvsena42 4f62696
fix: get tx direction from core
jvsena42 893a53e
fix: clean orphaned activities from deleted devices
jvsena42 ca78969
fix: watch idenpotency
jvsena42 79ae836
fix: dont cancel pairing when bracgrouding the device
jvsena42 914acaf
fix: clear dev dashboard results on wallet disconnect
jvsena42 c22f682
refactor: consolidate network conversion
jvsena42 b940159
test: regression tests
jvsena42 32d4915
refactor: implement core 0.3.2 wallet id derivation and adopt the red…
jvsena42 5729279
fix: trigger activitiesChangedSubject after persist and delet HW acti…
jvsena42 6dc2104
fix: guard reconnect under connectedDevice
jvsena42 a8c451e
fix: protect headlineSats from overflow
jvsena42 a26a474
refactor: remove unused method
jvsena42 a3a67c6
fix: stop only dahboard watcher on dashboard dismiss
jvsena42 8685359
fix: re-check watcher ids after the async watcher start
jvsena42 d2aa3f8
fix: reconcile hardware watchers when the Electrum server or monitore…
jvsena42 a039796
fix: set hasHardwareWallet for home widgets and widgets preview
jvsena42 bae69fd
fix: sort watches for a deterministic merge
jvsena42 39bbf3e
chore: add TODO for next iterations
jvsena42 5632064
chore: lint
jvsena42 6b76cc3
fix: narrow settings watcher trigger
jvsena42 6e0248f
fix: every watch event was performing a full activity reload and FFi …
jvsena42 a8fe2c8
refactor: consolidate HwAddressType
jvsena42 5777dbb
fix: update balance on watcher update, like adding/removing address type
jvsena42 798ba4c
refactor: consolidate saturation check
jvsena42 f0d63f8
fix: restart hardware watcher when a device's xpub changes
jvsena42 4d788bd
fix: only save device after successfully fetch all addressess
jvsena42 14566f6
fix: match zero balance sugggestion with android
jvsena42 e83dd03
fix: remove old remove device check with possibly stable data and reu…
jvsena42 a80db29
fix: set device as know after setting passphrase
jvsena42 eea9bb1
fix: auto-reconnect gated on isPinVerified || with an .onChange(of: i…
jvsena42 6ca4ce7
refactor: single source of true electrum url
jvsena42 136d6df
fix: unniform device name rules
jvsena42 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
Bitkit/Assets.xcassets/Illustrations/ledger.imageset/Contents.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "images" : [ | ||
| { | ||
| "filename" : "ledger.png", | ||
| "idiom" : "universal", | ||
| "scale" : "1x" | ||
| }, | ||
| { | ||
| "filename" : "ledger@2x.png", | ||
| "idiom" : "universal", | ||
| "scale" : "2x" | ||
| }, | ||
| { | ||
| "idiom" : "universal", | ||
| "scale" : "3x" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| } | ||
| } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions
22
Bitkit/Assets.xcassets/Illustrations/trezor.imageset/Contents.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "images" : [ | ||
| { | ||
| "filename" : "trezor.png", | ||
| "idiom" : "universal", | ||
| "scale" : "1x" | ||
| }, | ||
| { | ||
| "filename" : "trezor@2x.png", | ||
| "idiom" : "universal", | ||
| "scale" : "2x" | ||
| }, | ||
| { | ||
| "idiom" : "universal", | ||
| "scale" : "3x" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| } | ||
| } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions
16
Bitkit/Assets.xcassets/icons/bluetooth-connected.imageset/Contents.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "images" : [ | ||
| { | ||
| "filename" : "bluetooth-connected.svg", | ||
| "idiom" : "universal" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| }, | ||
| "properties" : { | ||
| "preserves-vector-representation" : true, | ||
| "template-rendering-intent" : "template" | ||
| } | ||
| } |
8 changes: 8 additions & 0 deletions
8
Bitkit/Assets.xcassets/icons/bluetooth-connected.imageset/bluetooth-connected.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions
15
Bitkit/Assets.xcassets/icons/btc-circle-blue.imageset/Contents.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "images" : [ | ||
| { | ||
| "filename" : "btc-circle-blue.svg", | ||
| "idiom" : "universal" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| }, | ||
| "properties" : { | ||
| "preserves-vector-representation" : true | ||
| } | ||
| } |
4 changes: 4 additions & 0 deletions
4
Bitkit/Assets.xcassets/icons/btc-circle-blue.imageset/btc-circle-blue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import SwiftUI | ||
|
|
||
| /// Two-column grid of paired hardware wallets shown on Home, under the Savings/Spending tiles. | ||
| /// Mirrors bitkit-android's `HwDevices` (rows chunked in pairs, divided like the on-chain tiles). | ||
| struct HardwareWalletsGrid: View { | ||
| let wallets: [HwWallet] | ||
| let onTap: (HwWallet) -> Void | ||
|
|
||
| private var rows: [[HwWallet]] { | ||
| chunked(wallets, into: 2) | ||
| } | ||
|
|
||
| private func chunked(_ wallets: [HwWallet], into size: Int) -> [[HwWallet]] { | ||
| stride(from: 0, to: wallets.count, by: size).map { start in | ||
| let end = min(start + size, wallets.count) | ||
| return Array(wallets[start ..< end]) | ||
| } | ||
| } | ||
|
|
||
| var body: some View { | ||
| VStack(spacing: 16) { | ||
| ForEach(Array(rows.enumerated()), id: \.offset) { _, row in | ||
| HStack(spacing: 16) { | ||
| HardwareWalletCell(wallet: row[0], onTap: onTap) | ||
|
|
||
| CustomDivider(color: .gray4, type: .vertical) | ||
|
|
||
| if row.count > 1 { | ||
| HardwareWalletCell(wallet: row[1], onTap: onTap) | ||
| } else { | ||
| Color.clear.frame(maxWidth: .infinity) | ||
| } | ||
| } | ||
| .frame(height: 50) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private struct HardwareWalletCell: View { | ||
| let wallet: HwWallet | ||
| let onTap: (HwWallet) -> Void | ||
|
|
||
| var body: some View { | ||
| Button { | ||
| onTap(wallet) | ||
| } label: { | ||
| VStack(alignment: .leading) { | ||
| CaptionMText(wallet.name) | ||
| .lineLimit(1) | ||
| .padding(.bottom, 4) | ||
|
|
||
| HStack(spacing: 4) { | ||
| Image("btc-circle-blue") | ||
| .resizable() | ||
| .scaledToFit() | ||
| .frame(width: 24, height: 24) | ||
| .padding(.trailing, 4) | ||
|
|
||
| MoneyText( | ||
| sats: Int(clamping: wallet.balanceSats), | ||
| size: .subtitle, | ||
| enableHide: true, | ||
| symbolColor: .textPrimary | ||
| ) | ||
|
|
||
| HwWalletConnectionIcon(isConnected: wallet.isConnected) | ||
| .frame(width: 16, height: 16) | ||
| } | ||
| } | ||
| .frame(maxWidth: .infinity, alignment: .leading) | ||
| } | ||
| .buttonStyle(.plain) | ||
| .accessibilityIdentifier("ActivityHardware") | ||
| } | ||
| } | ||
|
|
||
| #Preview { | ||
| func wallet(_ id: String, _ name: String, connected: Bool, sats: UInt64) -> HwWallet { | ||
| HwWallet(id: id, walletId: "trezor:\(id)", name: name, model: name, isConnected: connected, balanceSats: sats) | ||
| } | ||
|
|
||
| return VStack(spacing: 32) { | ||
| // Single device | ||
| HardwareWalletsGrid( | ||
| wallets: [wallet("1", "Trezor Safe 5", connected: true, sats: 1_234_567)], | ||
| onTap: { _ in } | ||
| ) | ||
|
|
||
| CustomDivider() | ||
|
|
||
| // Two devices (full 2-column row), one connected, one not | ||
| HardwareWalletsGrid( | ||
| wallets: [ | ||
| wallet("1", "Trezor Safe 5", connected: true, sats: 1_234_567), | ||
| wallet("2", "Trezor Model T", connected: false, sats: 89000), | ||
| ], | ||
| onTap: { _ in } | ||
| ) | ||
| } | ||
| .padding() | ||
| .environmentObject(CurrencyViewModel()) | ||
| .environmentObject(SettingsViewModel.shared) | ||
| .preferredColorScheme(.dark) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import SwiftUI | ||
|
|
||
| /// Staggered hardware-device hero used by the hardware intro sheet: a Trezor on the left and a | ||
| /// blurred Ledger bleeding off the right. Ports bitkit-android's `HwDeviceIllustrations`. | ||
| struct HwDeviceIllustrations: View { | ||
| /// All measurements are expressed as fractions of the Figma design frame's width, so the hero | ||
| /// scales proportionally to whatever width it's given. Each device is rendered at its natural | ||
| /// (non-square) aspect ratio; the Trezor's left bleed is baked into the exported asset, while | ||
| /// the Ledger is offset to bleed off the right edge. | ||
| private enum Layout { | ||
| static let referenceWidth: CGFloat = 375 | ||
|
|
||
| static let proportionalHeight: CGFloat = 256 / referenceWidth | ||
| static let trezorProportionalWidth: CGFloat = 172 / referenceWidth | ||
| static let ledgerProportionalWidth: CGFloat = 203 / referenceWidth | ||
| static let ledgerProportionalX: CGFloat = 172 / referenceWidth | ||
| static let proportionalStagger: CGFloat = 11.6 / referenceWidth | ||
| } | ||
|
|
||
| var body: some View { | ||
| GeometryReader { geo in | ||
| let width = geo.size.width | ||
| let imageHeight = width * Layout.proportionalHeight | ||
| let staggerY = width * Layout.proportionalStagger | ||
|
|
||
| ZStack { | ||
| Image("trezor") | ||
| .resizable() | ||
| .scaledToFit() | ||
| .frame(width: width * Layout.trezorProportionalWidth, height: imageHeight) | ||
| .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | ||
| .offset(y: staggerY) | ||
|
|
||
| Image("ledger") | ||
| .resizable() | ||
| .scaledToFit() | ||
| .frame(width: width * Layout.ledgerProportionalWidth, height: imageHeight) | ||
| .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | ||
| .offset(x: width * Layout.ledgerProportionalX, y: -staggerY) | ||
| } | ||
| } | ||
| .accessibilityHidden(true) | ||
| } | ||
| } | ||
|
|
||
| #Preview { | ||
| HwDeviceIllustrations() | ||
| .frame(height: 300) | ||
| .background(Color.black) | ||
| .preferredColorScheme(.dark) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import SwiftUI | ||
|
|
||
| /// Bluetooth connection indicator for a paired hardware wallet. iOS supports Bluetooth only, | ||
| /// so there is a single transport glyph — tinted green when connected, gray when disconnected. | ||
| /// Mirrors bitkit-android's `HwWalletConnectionIcon` (BLE branch). | ||
| struct HwWalletConnectionIcon: View { | ||
| let isConnected: Bool | ||
|
|
||
| var body: some View { | ||
| Image("bluetooth-connected") | ||
| .renderingMode(.template) | ||
| .resizable() | ||
| .scaledToFit() | ||
| .foregroundColor(isConnected ? .greenAccent : .gray1) | ||
| .accessibilityLabel( | ||
| isConnected | ||
| ? t("hardware__connection_badge_connected_bluetooth") | ||
| : t("hardware__connection_badge_disconnected_bluetooth") | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| #Preview { | ||
| HStack(spacing: 24) { | ||
| HwWalletConnectionIcon(isConnected: true).frame(width: 16, height: 16) | ||
| HwWalletConnectionIcon(isConnected: false).frame(width: 16, height: 16) | ||
| } | ||
| .padding() | ||
| .preferredColorScheme(.dark) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.