Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BDKSwiftExampleWallet/View/Activity/ActivityListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SwiftUI

struct ActivityListView: View {
@AppStorage("balanceDisplayFormat") private var balanceFormat: BalanceDisplayFormat =
.bitcoinSats
.bip177
@Bindable var viewModel: ActivityListViewModel

var body: some View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SwiftUI

struct LocalOutputItemView: View {
@AppStorage("balanceDisplayFormat") private var balanceFormat: BalanceDisplayFormat =
.bitcoinSats
.bip177
@Environment(\.dynamicTypeSize) var dynamicTypeSize
let isRedacted: Bool
let output: LocalOutput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import SwiftUI

struct TransactionDetailView: View {
@AppStorage("balanceDisplayFormat") private var balanceFormat: BalanceDisplayFormat =
.bitcoinSats
.bip177
@Bindable var viewModel: TransactionDetailViewModel
@State private var isCopied = false
@State private var showCheckmark = false
Expand Down
82 changes: 41 additions & 41 deletions BDKSwiftExampleWallet/View/Activity/TransactionItemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,49 +30,49 @@ struct TransactionItemView: View {

var body: some View {

VStack(alignment: .leading, spacing: 20) {
VStack(alignment: .leading, spacing: 6) {

let delta = txDetails.balanceDelta
let prefix = (delta >= 0 ? "+ " : "- ").appending("\(format.displayPrefix) ")
let amount = format.formatted(UInt64(abs(delta)), fiatPrice: fiatPrice)
let suffix = format.displayText

Text("\(prefix)\(amount) \(suffix)")
.font(.title)
.font(.title3)
.fontWeight(.semibold)
.fontDesign(.rounded)
.lineLimit(1)
.redacted(reason: isRedacted ? .placeholder : [])

HStack {
if isRedacted {
Image(
systemName:
"circle.fill"
)
.symbolRenderingMode(.palette)
.foregroundStyle(
Color.gray.opacity(0.5)
)
} else {
ZStack {
Image(
systemName:
txDetails.balanceDelta >= 0
? "arrow.down" : "arrow.up"
)
.foregroundStyle(
{
switch txDetails.chainPosition {
case .confirmed(_, _):
Color.bitcoinOrange
case .unconfirmed(_):
Color.gray.opacity(0.5)
}
}()
)
}
}
// if isRedacted {
// Image(
// systemName:
// "circle.fill"
// )
// .symbolRenderingMode(.palette)
// .foregroundStyle(
// Color.gray.opacity(0.5)
// )
// } else {
// ZStack {
// Image(
// systemName:
// txDetails.balanceDelta >= 0
// ? "arrow.down" : "arrow.up"
// )
// .foregroundStyle(
// {
// switch txDetails.chainPosition {
// case .confirmed(_, _):
// Color.bitcoinOrange
// case .unconfirmed(_):
// Color.gray.opacity(0.5)
// }
// }()
// )
// }
// }

switch txDetails.chainPosition {
case .confirmed(let confirmationBlockTime, _):
Expand Down Expand Up @@ -103,18 +103,18 @@ struct TransactionItemView: View {

}
.foregroundStyle(.secondary)
.font(.callout)
.font(.caption)

HStack {
Text(txDetails.txid.description)
.truncationMode(.middle)
.lineLimit(1)
.fontDesign(.monospaced)
.font(.callout)
.foregroundStyle(.primary)
Spacer(minLength: 80)
}
.redacted(reason: isRedacted ? .placeholder : [])
// HStack {
// Text(txDetails.txid.description)
// .truncationMode(.middle)
// .lineLimit(1)
// .fontDesign(.monospaced)
// .font(.callout)
// .foregroundStyle(.primary)
// Spacer(minLength: 80)
// }
// .redacted(reason: isRedacted ? .placeholder : [])

}
.padding(.vertical)
Expand Down
19 changes: 10 additions & 9 deletions BDKSwiftExampleWallet/View/Activity/TransactionListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ struct TransactionListView: View {

var body: some View {

List {
LazyVStack(alignment: .leading) {
if transactions.isEmpty && walletSyncState == .syncing {
TransactionItemView(
txDetails: .mock,
isRedacted: true,
format: format,
fiatPrice: fiatPrice
)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
} else if transactions.isEmpty {

VStack(alignment: .leading) {
Expand Down Expand Up @@ -94,8 +92,6 @@ struct TransactionListView: View {
}

}
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)

} else {

Expand All @@ -122,6 +118,14 @@ struct TransactionListView: View {
format: format,
fiatPrice: fiatPrice
)
.frame(maxWidth: .infinity, alignment: .leading)
.overlay(alignment: .trailing) {
Image(systemName: "chevron.right")
.font(.footnote.weight(.semibold))
.foregroundStyle(.tertiary)
.padding(.leading, 8)
}
.padding(.trailing, 4)
}

} else {
Expand All @@ -134,14 +138,11 @@ struct TransactionListView: View {
}

}
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)

}

}
.listStyle(.plain)
.frame(maxWidth: .infinity, alignment: .leading)
.alert(isPresented: $viewModel.showingWalletTransactionsViewErrorAlert) {
Alert(
title: Text("Wallet Transaction Error"),
Expand Down
104 changes: 54 additions & 50 deletions BDKSwiftExampleWallet/View/WalletView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SwiftUI

struct WalletView: View {
@AppStorage("balanceDisplayFormat") private var balanceFormat: BalanceDisplayFormat =
.bitcoinSats
.bip177
@AppStorage("KyotoLastBlockHeight") private var kyotoLastHeight: Int = 0
@Bindable var viewModel: WalletViewModel
@Binding var sendNavigationPath: NavigationPath
Expand All @@ -27,64 +27,68 @@ struct WalletView: View {
Color(uiColor: .systemBackground)
.ignoresSafeArea()

VStack(spacing: 20) {
ScrollView {
VStack(spacing: 20) {

BalanceView(
format: balanceFormat,
balance: viewModel.balanceTotal,
fiatPrice: viewModel.price
).onTapGesture {
withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
balanceFormat =
BalanceDisplayFormat.allCases[
(balanceFormat.index + 1) % BalanceDisplayFormat.allCases.count
]
}
}

VStack {
ActivityHomeHeaderView(
walletSyncState: viewModel.walletSyncState,
progress: viewModel.progress,
inspectedScripts: viewModel.inspectedScripts,
totalScripts: viewModel.totalScripts,
needsFullScan: viewModel.needsFullScan,
isKyotoClient: viewModel.isKyotoClient,
isKyotoConnected: viewModel.isKyotoConnected,
currentBlockHeight: viewModel.currentBlockHeight
) {
showAllTransactions = true
BalanceView(
format: balanceFormat,
balance: viewModel.balanceTotal,
fiatPrice: viewModel.price
).onTapGesture {
withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
balanceFormat =
BalanceDisplayFormat.allCases[
(balanceFormat.index + 1)
% BalanceDisplayFormat
.allCases.count
]
}
}

if shouldShowKyotoInitialSyncNotice {
KyotoInitialSyncNoticeView(isConnected: viewModel.isKyotoConnected)
.transition(.opacity)
}
VStack {
ActivityHomeHeaderView(
walletSyncState: viewModel.walletSyncState,
progress: viewModel.progress,
inspectedScripts: viewModel.inspectedScripts,
totalScripts: viewModel.totalScripts,
needsFullScan: viewModel.needsFullScan,
isKyotoClient: viewModel.isKyotoClient,
isKyotoConnected: viewModel.isKyotoConnected,
currentBlockHeight: viewModel.currentBlockHeight
) {
showAllTransactions = true
}

TransactionListView(
viewModel: .init(),
transactions: viewModel.recentTransactions,
walletSyncState: viewModel.walletSyncState,
format: balanceFormat,
fiatPrice: viewModel.price
)
.refreshable {
if viewModel.isKyotoClient {
viewModel.getBalance()
viewModel.getTransactions()
await viewModel.getPrices()
} else {
await viewModel.syncOrFullScan()
viewModel.getBalance()
viewModel.getTransactions()
await viewModel.getPrices()
if shouldShowKyotoInitialSyncNotice {
KyotoInitialSyncNoticeView(isConnected: viewModel.isKyotoConnected)
.transition(.opacity)
}

TransactionListView(
viewModel: .init(),
transactions: viewModel.recentTransactions,
walletSyncState: viewModel.walletSyncState,
format: balanceFormat,
fiatPrice: viewModel.price
)

}

}

.padding()
}
.refreshable {
if viewModel.isKyotoClient {
viewModel.getBalance()
viewModel.getTransactions()
await viewModel.getPrices()
} else {
await viewModel.syncOrFullScan()
viewModel.getBalance()
viewModel.getTransactions()
await viewModel.getPrices()
}
}
.padding()
.onReceive(
NotificationCenter.default.publisher(for: Notification.Name("TransactionSent")),
perform: { _ in
Expand Down
Binary file added Docs/wallet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Docs/walletview.png
Binary file not shown.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

A native iOS app example using [Bitcoin Dev Kit](https://github.com/bitcoindevkit) via [language bindings](https://github.com/bitcoindevkit/bdk-ffi).

<img src="Docs/walletview.png" alt="Screenshot" width="210.5" height="420">
<img src="Docs/wallet.png" alt="Screenshot" width="210.5" height="420">

Download the app on [TestFlight](https://testflight.apple.com/join/A3nAuYvZ).

Expand Down