Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
14 changes: 13 additions & 1 deletion BDKSwiftExampleWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
774586B52DB7B2BC00A631E1 /* BalanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 774586B42DB7B2BC00A631E1 /* BalanceView.swift */; };
779E70872DB9C98A006E22D3 /* WalletSyncScriptInspector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779E70862DB9C98A006E22D3 /* WalletSyncScriptInspector.swift */; };
779E70892DB9C9AB006E22D3 /* WalletFullScanScriptInspector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779E70882DB9C9AB006E22D3 /* WalletFullScanScriptInspector.swift */; };
77AD9F062DBB031D00182E65 /* ActivityHomeHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AD9F052DBB031D00182E65 /* ActivityHomeHeaderView.swift */; };
77F0FDC92DA9A93D00B30E4F /* Connection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F0FDC82DA9A93700B30E4F /* Connection+Extensions.swift */; };
A733D6D02A81113000F333B4 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = A733D6CF2A81113000F333B4 /* Localizable.xcstrings */; };
A73F7A362A3B778E00B87FC6 /* Int+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A73F7A352A3B778E00B87FC6 /* Int+Extensions.swift */; };
Expand Down Expand Up @@ -114,6 +115,7 @@
774586B42DB7B2BC00A631E1 /* BalanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceView.swift; sourceTree = "<group>"; };
779E70862DB9C98A006E22D3 /* WalletSyncScriptInspector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSyncScriptInspector.swift; sourceTree = "<group>"; };
779E70882DB9C9AB006E22D3 /* WalletFullScanScriptInspector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletFullScanScriptInspector.swift; sourceTree = "<group>"; };
77AD9F052DBB031D00182E65 /* ActivityHomeHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityHomeHeaderView.swift; sourceTree = "<group>"; };
77F0FDC82DA9A93700B30E4F /* Connection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Connection+Extensions.swift"; sourceTree = "<group>"; };
A733D6CF2A81113000F333B4 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
A73F7A352A3B778E00B87FC6 /* Int+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Extensions.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -235,6 +237,15 @@
path = Actor;
sourceTree = "<group>";
};
77AD9F072DBB0DBE00182E65 /* Home */ = {
isa = PBXGroup;
children = (
774586B42DB7B2BC00A631E1 /* BalanceView.swift */,
77AD9F052DBB031D00182E65 /* ActivityHomeHeaderView.swift */,
);
path = Home;
sourceTree = "<group>";
};
A7FBCE392A72944C007C960E /* Resources */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -283,7 +294,7 @@
AE2381B92C61255100F6B00C /* Receive */,
AE2381B82C61254B00F6B00C /* Send */,
AE2381B72C61254200F6B00C /* Settings */,
774586B42DB7B2BC00A631E1 /* BalanceView.swift */,
77AD9F072DBB0DBE00182E65 /* Home */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -733,6 +744,7 @@
AED4CC0C2A1D3A9400CE1831 /* OnboardingView.swift in Sources */,
77F0FDC92DA9A93D00B30E4F /* Connection+Extensions.swift in Sources */,
AE6716012A9AC089005C193F /* KeyServiceError.swift in Sources */,
77AD9F062DBB031D00182E65 /* ActivityHomeHeaderView.swift in Sources */,
AE0C30FB2A804B95008F1EAE /* WalletViewModel.swift in Sources */,
AE49847C2A1BBBD6009951E2 /* BDKSwiftExampleWalletApp.swift in Sources */,
AE6715FF2A9AC066005C193F /* FeeServiceError.swift in Sources */,
Expand Down
136 changes: 136 additions & 0 deletions BDKSwiftExampleWallet/View/Home/ActivityHomeHeaderView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//
// TransactionListHeaderView.swift
// BDKSwiftExampleWallet
//
// Created by Rubens Machion on 24/04/25.
//

import SwiftUI

struct ActivityHomeHeaderView: View {

enum State {
case synced
case fullSyncing(inspectedScripts: UInt64)
case syncing(progress: Float, inspectedScripts: UInt64, totalScripts: UInt64)
case notStarted
case error(Error)
}

let state: State

let showAllTransactions: () -> Void

var body: some View {
HStack {
Text("Activity")
Spacer()

HStack {
if case let .fullSyncing(inspectedScripts) = state {
Text("\(inspectedScripts)")
.padding(.trailing, -5.0)
.fontWeight(.semibold)
.contentTransition(.numericText())
.transition(.opacity)
.fontDesign(.monospaced)
.foregroundStyle(.secondary)
.font(.caption2)
.fontWeight(.thin)
.animation(.easeInOut, value: inspectedScripts)
}
if case let .syncing(progress, inspectedScripts, totalScripts) = state {
HStack {
if progress < 1.0 {
Text("\(inspectedScripts)")
.padding(.trailing, -5.0)
.fontWeight(.semibold)
.contentTransition(.numericText())
.transition(.opacity)

Text("/")
.padding(.trailing, -5.0)
.transition(.opacity)
Text("\(totalScripts)")
.contentTransition(.numericText())
.transition(.opacity)
}

Text(
String(
format: "%.0f%%",
progress * 100
)
)
.contentTransition(.numericText())
.transition(.opacity)
}
.fontDesign(.monospaced)
.foregroundStyle(.secondary)
.font(.caption2)
.fontWeight(.thin)
.animation(.easeInOut, value: inspectedScripts)
.animation(.easeInOut, value: totalScripts)
.animation(.easeInOut, value: progress)
}
}
HStack {
HStack(spacing: 5) {
state.syncImageIndicator
}
.contentTransition(.symbolEffect(.replace.offUp))

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

if case .synced = state {
Button {
self.showAllTransactions()
} label: {
HStack(spacing: 2) {
Text("Show All")
Image(systemName: "arrow.right")
}
.font(.caption)
.foregroundStyle(.secondary)
.fontWeight(.regular)
}
}
}
.fontWeight(.bold)
}
}


fileprivate extension ActivityHomeHeaderView.State {

var syncImageIndicator: some View {
switch self {
case .synced:
return AnyView(
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green)
)

case .syncing(_, _, _), .fullSyncing(_):
return AnyView(
Image(systemName: "slowmo")
.symbolEffect(
.variableColor.cumulative
)
)

case .notStarted:
return AnyView(
Image(systemName: "arrow.clockwise")
)
default:
return AnyView(
Image(
systemName: "person.crop.circle.badge.exclamationmark"
)
)
}
}
}
110 changes: 27 additions & 83 deletions BDKSwiftExampleWallet/View/WalletView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,90 +42,12 @@ struct WalletView: View {
}

VStack {
HStack {
Text("Activity")
Spacer()
if viewModel.walletSyncState == .syncing {
HStack {
if viewModel.progress < 1.0 {
Text("\(viewModel.inspectedScripts)")
.padding(.trailing, -5.0)
.fontWeight(.semibold)
.contentTransition(.numericText())
.transition(.opacity)

if !viewModel.bdkClient.needsFullScan() {
Text("/")
.padding(.trailing, -5.0)
.transition(.opacity)
Text("\(viewModel.totalScripts)")
.contentTransition(.numericText())
.transition(.opacity)
}
}

if !viewModel.bdkClient.needsFullScan() {
Text(
String(
format: "%.0f%%",
viewModel.progress * 100
)
)
.contentTransition(.numericText())
.transition(.opacity)
}
}
.fontDesign(.monospaced)
.foregroundStyle(.secondary)
.font(.caption2)
.fontWeight(.thin)
.animation(.easeInOut, value: viewModel.inspectedScripts)
.animation(.easeInOut, value: viewModel.totalScripts)
.animation(.easeInOut, value: viewModel.progress)
}
HStack {
HStack(spacing: 5) {
if viewModel.walletSyncState == .syncing {
Image(systemName: "slowmo")
.symbolEffect(
.variableColor.cumulative
)
} else if viewModel.walletSyncState == .synced {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(
viewModel.walletSyncState == .synced
? .green : .secondary
)
} else if viewModel.walletSyncState == .notStarted {
Image(systemName: "arrow.clockwise")
} else {
Image(
systemName: "person.crop.circle.badge.exclamationmark"
)
}
}
.contentTransition(.symbolEffect(.replace.offUp))

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

if viewModel.walletSyncState == .synced {
Button {
showAllTransactions = true
} label: {
HStack(spacing: 2) {
Text("Show All")
Image(systemName: "arrow.right")
}
.font(.caption)
.foregroundStyle(.secondary)
.fontWeight(.regular)
}
}

ActivityHomeHeaderView(
state: viewModel.activityHeaderStateSync
) {
showAllTransactions = true
}
.fontWeight(.bold)

TransactionListView(
viewModel: .init(),
transactions: viewModel.recentTransactions,
Expand Down Expand Up @@ -259,6 +181,28 @@ struct WalletView: View {
}
}

fileprivate extension WalletViewModel {

var activityHeaderStateSync: ActivityHomeHeaderView.State {
let walletSyncState = walletSyncState
let needsFullScan = bdkClient.needsFullScan()

if needsFullScan {
return .fullSyncing(inspectedScripts: inspectedScripts)
} else if walletSyncState == .synced {
return .synced
} else if walletSyncState == .syncing {
return .syncing(
progress: progress,
inspectedScripts: inspectedScripts,
totalScripts: totalScripts
)
} else {
return .notStarted
}
}
}

#if DEBUG
#Preview("WalletView - en") {
WalletView(
Expand Down