diff --git a/BDKSwiftExampleWallet/App/BDKSwiftExampleWalletApp.swift b/BDKSwiftExampleWallet/App/BDKSwiftExampleWalletApp.swift index ef0e15d7..cde3b0f0 100644 --- a/BDKSwiftExampleWallet/App/BDKSwiftExampleWalletApp.swift +++ b/BDKSwiftExampleWallet/App/BDKSwiftExampleWalletApp.swift @@ -11,15 +11,20 @@ import SwiftUI @main struct BDKSwiftExampleWalletApp: App { @AppStorage("isOnboarding") var isOnboarding: Bool = true + @State private var navigationPath = NavigationPath() var body: some Scene { WindowGroup { - if isOnboarding { - OnboardingView(viewModel: .init(bdkClient: .live)) - } else { - HomeView(viewModel: .init(bdkClient: .live)) + NavigationStack(path: $navigationPath) { + if isOnboarding { + OnboardingView(viewModel: .init(bdkClient: .live)) + } else { + HomeView(viewModel: .init(bdkClient: .live)) + } + } + .onChange(of: isOnboarding) { oldValue, newValue in + navigationPath = NavigationPath() } } } - } diff --git a/BDKSwiftExampleWallet/View/Settings/SettingsView.swift b/BDKSwiftExampleWallet/View/Settings/SettingsView.swift index 0d2bfc33..7e2c4eeb 100644 --- a/BDKSwiftExampleWallet/View/Settings/SettingsView.swift +++ b/BDKSwiftExampleWallet/View/Settings/SettingsView.swift @@ -13,6 +13,7 @@ struct SettingsView: View { @State private var showingDeleteSeedConfirmation = false @State private var showingShowSeedConfirmation = false @State private var isSeedPresented = false + @Environment(\.dismiss) private var dismiss var body: some View { @@ -112,6 +113,7 @@ struct SettingsView: View { ) { Button("Yes", role: .destructive) { viewModel.delete() + dismiss() } Button("No", role: .cancel) {} } diff --git a/BDKSwiftExampleWallet/View/WalletView.swift b/BDKSwiftExampleWallet/View/WalletView.swift index 2d0f29bf..b03a1962 100644 --- a/BDKSwiftExampleWallet/View/WalletView.swift +++ b/BDKSwiftExampleWallet/View/WalletView.swift @@ -21,261 +21,239 @@ struct WalletView: View { var body: some View { - NavigationStack(path: $sendNavigationPath) { + ZStack { + Color(uiColor: .systemBackground) + .ignoresSafeArea() - ZStack { - Color(uiColor: .systemBackground) - .ignoresSafeArea() + VStack(spacing: 20) { - VStack(spacing: 20) { - - VStack(spacing: 10) { - Text("Bitcoin".uppercased()) - .fontWeight(.semibold) - .fontWidth(.expanded) - .foregroundColor(.bitcoinOrange) - .scaleEffect(isAnimating ? 1.0 : 0.6) - .onAppear { - withAnimation(.easeOut(duration: 0.5)) { - isAnimating = true - } - } - withAnimation { - HStack(spacing: 15) { - Image(systemName: "bitcoinsign") - .foregroundColor(.secondary) - .font(.title) - .fontWeight(.thin) - Text(viewModel.balanceTotal.formattedSatoshis()) - .contentTransition(.numericText()) - .fontWeight(.semibold) - .fontDesign(.rounded) - Text("sats") - .foregroundColor(.secondary) - .fontWeight(.thin) + VStack(spacing: 10) { + Text("Bitcoin".uppercased()) + .fontWeight(.semibold) + .fontWidth(.expanded) + .foregroundColor(.bitcoinOrange) + .scaleEffect(isAnimating ? 1.0 : 0.6) + .onAppear { + withAnimation(.easeOut(duration: 0.5)) { + isAnimating = true } - .font(.largeTitle) - .lineLimit(1) - .minimumScaleFactor(0.5) } - HStack { - if viewModel.walletSyncState == .syncing { - Image(systemName: "chart.bar.fill") - .symbolEffect( - .variableColor.cumulative - ) - } - Text(viewModel.satsPrice, format: .currency(code: "USD")) + withAnimation { + HStack(spacing: 15) { + Image(systemName: "bitcoinsign") + .foregroundColor(.secondary) + .font(.title) + .fontWeight(.thin) + Text(viewModel.balanceTotal.formattedSatoshis()) .contentTransition(.numericText()) + .fontWeight(.semibold) .fontDesign(.rounded) + Text("sats") + .foregroundColor(.secondary) + .fontWeight(.thin) } - .foregroundColor(.secondary) - .font(.subheadline) + .font(.largeTitle) + .lineLimit(1) + .minimumScaleFactor(0.5) } - .padding(.vertical, 20.0) + HStack { + if viewModel.walletSyncState == .syncing { + Image(systemName: "chart.bar.fill") + .symbolEffect( + .variableColor.cumulative + ) + } + Text(viewModel.satsPrice, format: .currency(code: "USD")) + .contentTransition(.numericText()) + .fontDesign(.rounded) + } + .foregroundColor(.secondary) + .font(.subheadline) + } + .padding(.vertical, 20.0) - VStack { - HStack { - Text("Activity") - Spacer() - if viewModel.walletSyncState == .syncing { - HStack { - if viewModel.progress < 1.0 { - Text("\(viewModel.inspectedScripts)") + 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) - .fontWeight(.semibold) + .transition(.opacity) + Text("\(viewModel.totalScripts)") .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 - ) + if !viewModel.bdkClient.needsFullScan() { + Text( + String( + format: "%.0f%%", + viewModel.progress * 100 ) - .contentTransition(.numericText()) - .transition(.opacity) - } + ) + .contentTransition(.numericText()) + .transition(.opacity) } - .fontDesign(.monospaced) - .foregroundColor(.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 - ) - .contentTransition(.symbolEffect(.replace.offUp)) - } else if viewModel.walletSyncState == .synced { - Image(systemName: "checkmark.circle") - .foregroundColor( - viewModel.walletSyncState == .synced - ? .green : .secondary - ) - } else if viewModel.walletSyncState == .notStarted { - Image(systemName: "goforward") - } else { - Image( - systemName: "person.crop.circle.badge.exclamationmark" + .fontDesign(.monospaced) + .foregroundColor(.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 ) - } - + .contentTransition(.symbolEffect(.replace.offUp)) + } else if viewModel.walletSyncState == .synced { + Image(systemName: "checkmark.circle") + .foregroundColor( + viewModel.walletSyncState == .synced + ? .green : .secondary + ) + } else if viewModel.walletSyncState == .notStarted { + Image(systemName: "goforward") + } else { + Image( + systemName: "person.crop.circle.badge.exclamationmark" + ) } - } - .foregroundColor(.secondary) - .font(.caption) - if viewModel.walletSyncState == .synced { - Button(action: { - showAllTransactions = true - }) { - HStack(spacing: 2) { - Text("Show All") - Image(systemName: "arrow.right") - } - .font(.caption) - .foregroundColor(.secondary) - .fontWeight(.regular) - } } - - } - .fontWeight(.bold) - TransactionListView( - transactions: viewModel.recentTransactions, - walletSyncState: viewModel.walletSyncState, - viewModel: .init() - ) - .refreshable { - await viewModel.syncOrFullScan() - viewModel.getBalance() - viewModel.getTransactions() - await viewModel.getPrices() } + .foregroundColor(.secondary) + .font(.caption) - HStack { + if viewModel.walletSyncState == .synced { Button(action: { - showReceiveView = true + showAllTransactions = true }) { - Image(systemName: "qrcode") - .font(.title) - .foregroundColor(.primary) + HStack(spacing: 2) { + Text("Show All") + Image(systemName: "arrow.right") + } + .font(.caption) + .foregroundColor(.secondary) + .fontWeight(.regular) } + } - Spacer() - - Button(action: { - sendNavigationPath.append(NavigationDestination.address) - }) { - Image(systemName: "qrcode.viewfinder") - .font(.title) - .foregroundColor(.primary) + } + .fontWeight(.bold) + TransactionListView( + transactions: viewModel.recentTransactions, + walletSyncState: viewModel.walletSyncState, + viewModel: .init() + ) + .refreshable { + await viewModel.syncOrFullScan() + viewModel.getBalance() + viewModel.getTransactions() + await viewModel.getPrices() + } - } + HStack { + Button(action: { + showReceiveView = true + }) { + Image(systemName: "qrcode") + .font(.title) + .foregroundColor(.primary) } - .padding([.horizontal, .bottom]) - } + Spacer() - } - .padding() - .onReceive( - NotificationCenter.default.publisher(for: Notification.Name("TransactionSent")), - perform: { _ in - newTransactionSent = true - } - ) - .onReceive( - NotificationCenter.default.publisher( - for: Notification.Name("AddressGenerated") - ), - perform: { _ in - Task { - await viewModel.syncOrFullScan() - viewModel.getBalance() - viewModel.getTransactions() - await viewModel.getPrices() + NavigationLink(value: NavigationDestination.address) { + Image(systemName: "qrcode.viewfinder") + .font(.title) + .foregroundColor(.primary) } } - ) - .task { - viewModel.getBalance() - if isFirstAppear || newTransactionSent { - await viewModel.syncOrFullScan() - isFirstAppear = false - newTransactionSent = false - viewModel.getBalance() - } - viewModel.getTransactions() - await viewModel.getPrices() + .padding([.horizontal, .bottom]) + } } - .navigationDestination(isPresented: $showAllTransactions) { - ActivityListView(viewModel: .init()) - } - .navigationDestination(for: NavigationDestination.self) { destination in - switch destination { - case .address: - AddressView(navigationPath: $sendNavigationPath) - case .amount(let address): - AmountView( - address: address, - viewModel: .init(), - navigationPath: $sendNavigationPath - ) - case .fee(let amount, let address): - FeeView( - amount: amount, - address: address, - viewModel: .init(), - navigationPath: $sendNavigationPath - ) - case .buildTransaction(let amount, let address, let fee): - BuildTransactionView( - amount: amount, - address: address, - fee: fee, - viewModel: .init(), - navigationPath: $sendNavigationPath - ) + .padding() + .onReceive( + NotificationCenter.default.publisher(for: Notification.Name("TransactionSent")), + perform: { _ in + newTransactionSent = true } - } - .toolbar { - ToolbarItem(placement: .navigation) { - VStack { - Text("Navigation Title") - .foregroundColor(.clear) + ) + .onReceive( + NotificationCenter.default.publisher( + for: Notification.Name("AddressGenerated") + ), + perform: { _ in + Task { + await viewModel.syncOrFullScan() + viewModel.getBalance() + viewModel.getTransactions() + await viewModel.getPrices() } } - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - showSettingsView = true - }) { - Image(systemName: "person.and.background.dotted") - } + ) + .task { + viewModel.getBalance() + if isFirstAppear || newTransactionSent { + await viewModel.syncOrFullScan() + isFirstAppear = false + newTransactionSent = false + viewModel.getBalance() } + viewModel.getTransactions() + await viewModel.getPrices() } } + .navigationDestination(isPresented: $showAllTransactions) { + ActivityListView(viewModel: .init()) + } + .navigationDestination(for: NavigationDestination.self) { destination in + switch destination { + case .address: + AddressView(navigationPath: $sendNavigationPath) + case .amount(let address): + AmountView( + address: address, + viewModel: .init(), + navigationPath: $sendNavigationPath + ) + case .fee(let amount, let address): + FeeView( + amount: amount, + address: address, + viewModel: .init(), + navigationPath: $sendNavigationPath + ) + case .buildTransaction(let amount, let address, let fee): + BuildTransactionView( + amount: amount, + address: address, + fee: fee, + viewModel: .init(), + navigationPath: $sendNavigationPath + ) + } + } .sheet( isPresented: $showReceiveView, onDismiss: { @@ -299,6 +277,15 @@ struct WalletView: View { } ) } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + showSettingsView = true + }) { + Image(systemName: "person.and.background.dotted") + } + } + } }