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
39 changes: 30 additions & 9 deletions Bitkit/AppScene.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Combine
import LDKNode
import SwiftUI
import UserNotifications

struct AppScene: View {
@Environment(\.scenePhase) var scenePhase
Expand Down Expand Up @@ -32,7 +33,7 @@ struct AppScene: View {
@State private var isPinVerified: Bool = false
@State private var showRecoveryScreen = false

// Check if there's a critical update available
/// Check if there's a critical update available
private var hasCriticalUpdate: Bool {
AppUpdateService.shared.availableUpdate?.critical == true
}
Expand Down Expand Up @@ -73,7 +74,6 @@ struct AppScene: View {
config in ForgotPinSheet(config: config)
}
.task(priority: .userInitiated, setupTask)
.handleLightningStateOnScenePhaseChange()
.onChange(of: currency.hasStaleData, perform: handleCurrencyStaleData)
.onChange(of: wallet.walletExists, perform: handleWalletExistsChange)
.onChange(of: wallet.nodeLifecycleState, perform: handleNodeLifecycleChange)
Expand Down Expand Up @@ -139,7 +139,6 @@ struct AppScene: View {
}
}

@ViewBuilder
private var mainContent: some View {
ZStack {
if migrations.isShowingMigrationLoading {
Expand All @@ -160,7 +159,6 @@ struct AppScene: View {
}
}

@ViewBuilder
private var migrationLoadingContent: some View {
VStack(spacing: 0) {
NavigationBar(title: t("migration__title"), showBackButton: false, showMenuButton: false)
Expand Down Expand Up @@ -250,7 +248,6 @@ struct AppScene: View {
}
}

@ViewBuilder
private var onboardingContent: some View {
NavigationStack {
TermsView()
Expand Down Expand Up @@ -496,13 +493,37 @@ struct AppScene: View {
}
}

private func handleScenePhaseChange(_: ScenePhase) {
// If PIN is enabled, lock the app when the app goes to the background
if scenePhase == .background && settings.pinEnabled {
isPinVerified = false
private func handleScenePhaseChange(_ newPhase: ScenePhase) {
Logger.debug("Scene phase changed: \(newPhase)")

if newPhase == .background {
if settings.pinEnabled {
// If PIN is enabled, lock the app when the app goes to the background
isPinVerified = false
}
if wallet.walletExists == true {
app.resetAppStatusInit()
}
}

if newPhase == .active {
if wallet.walletExists == true {
Task {
await clearDeliveredNotifications()
await LightningService.shared.reconnectPeers()
Comment thread
pwltr marked this conversation as resolved.
}
}
}
}

/// Removes all delivered notifications from Notification Center so the app can handle them when opened.
private func clearDeliveredNotifications() async {
let center = UNUserNotificationCenter.current()
let deliveredNotifications = await center.deliveredNotifications()
guard !deliveredNotifications.isEmpty else { return }
center.removeDeliveredNotifications(withIdentifiers: deliveredNotifications.map(\.request.identifier))
}

private func handleNetworkRestored() {
// Refresh currency rates when network is restored - critical for UI
// to display balances (MoneyText returns "0" if rates are nil)
Expand Down
60 changes: 47 additions & 13 deletions Bitkit/Services/LightningService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,28 @@
}
}

func reconnectPeers() async {
guard let node else {
Logger.debug("Node not setup, skipping peer reconnection", context: "LightningService")
return
}

let peers = node.listPeers()
Logger.debug("Reconnecting to \(peers.count) peers", context: "LightningService")
for peer in peers {
do {
try await ServiceQueue.background(.ldk) {
try node.connect(nodeId: peer.nodeId, address: peer.address, persist: true)
}
Logger.info("Reconnected to peer: \(peer.nodeId)@\(peer.address)", context: "LightningService")
} catch {
Logger.error(error, context: "Failed to reconnect to peer: \(peer.nodeId)@\(peer.address)")
}
}

Logger.debug("Finished peer reconnection attempt", context: "LightningService")
}

/// Temp fix for regtest where nodes might not agree on current fee rates
private func setMaxDustHtlcExposureForCurrentChannels() throws {
guard Env.network == .regtest else {
Expand Down Expand Up @@ -595,7 +617,7 @@
}

func closeChannel(_ channel: ChannelDetails, force: Bool = false, forceCloseReason: String? = nil) async throws {
guard let node else {

Check warning on line 620 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

value 'node' was defined but never used; consider replacing with boolean test

Check warning on line 620 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

value 'node' was defined but never used; consider replacing with boolean test
throw AppError(serviceError: .nodeNotStarted)
}

Expand Down Expand Up @@ -859,14 +881,30 @@
// MARK: UI Helpers (Published via WalletViewModel)

extension LightningService {
var nodeId: String? { node?.nodeId() }
var nodeId: String? {
node?.nodeId()
}

/// Use cached values to avoid blocking LDK calls on main thread
@MainActor var balances: BalanceDetails? {
cachedBalances
}

// Use cached values to avoid blocking LDK calls on main thread
@MainActor var balances: BalanceDetails? { cachedBalances }
@MainActor var status: NodeStatus? { cachedStatus }
@MainActor var peers: [PeerDetails]? { cachedPeers }
@MainActor var channels: [ChannelDetails]? { cachedChannels }
var payments: [PaymentDetails]? { node?.listPayments() }
@MainActor var status: NodeStatus? {
cachedStatus
}

@MainActor var peers: [PeerDetails]? {
cachedPeers
}

@MainActor var channels: [ChannelDetails]? {
cachedChannels
}

var payments: [PaymentDetails]? {
node?.listPayments()
}

/// Refresh all cached values asynchronously
/// Fetches from LDK on background queue, updates cache on main actor
Expand Down Expand Up @@ -1068,7 +1106,7 @@
onEvent?(event)

switch event {
case let .paymentSuccessful(paymentId, paymentHash, paymentPreimage, feePaidMsat):

Check warning on line 1109 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'paymentPreimage' was never used; consider replacing with '_' or removing it

Check warning on line 1109 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'paymentPreimage' was never used; consider replacing with '_' or removing it
Logger.info("✅ Payment successful: paymentId: \(paymentId ?? "?") paymentHash: \(paymentHash) feePaidMsat: \(feePaidMsat ?? 0)")
Task {
let hash = paymentId ?? paymentHash
Expand All @@ -1093,7 +1131,7 @@
Logger.warn("No paymentId or paymentHash available for failed payment", context: "LightningService")
}
}
case let .paymentReceived(paymentId, paymentHash, amountMsat, feePaidMsat):

Check warning on line 1134 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'feePaidMsat' was never used; consider replacing with '_' or removing it

Check warning on line 1134 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'feePaidMsat' was never used; consider replacing with '_' or removing it
Logger.info("🤑 Payment received: paymentId: \(paymentId ?? "?") paymentHash: \(paymentHash) amountMsat: \(amountMsat)")
Task {
let hash = paymentId ?? paymentHash
Expand All @@ -1103,7 +1141,7 @@
Logger.error("Failed to handle payment received for \(hash): \(error)", context: "LightningService")
}
}
case let .paymentClaimable(paymentId, paymentHash, claimableAmountMsat, claimDeadline, customRecords):

Check warning on line 1144 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'customRecords' was never used; consider replacing with '_' or removing it

Check warning on line 1144 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'claimDeadline' was never used; consider replacing with '_' or removing it

Check warning on line 1144 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'customRecords' was never used; consider replacing with '_' or removing it

Check warning on line 1144 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'claimDeadline' was never used; consider replacing with '_' or removing it
Logger.info(
"🫰 Payment claimable: paymentId: \(paymentId) paymentHash: \(paymentHash) claimableAmountMsat: \(claimableAmountMsat)"
)
Expand Down Expand Up @@ -1132,7 +1170,7 @@

if let channel {
await registerClosedChannel(channel: channel, reason: reasonString)
await MainActor.run {

Check warning on line 1173 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

result of call to 'run(resultType:body:)' is unused

Check warning on line 1173 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

result of call to 'run(resultType:body:)' is unused
channelCache.removeValue(forKey: channelIdString)
}
} else {
Expand All @@ -1155,7 +1193,7 @@
Logger.error("Failed to handle transaction received for \(txid): \(error)", context: "LightningService")
}
}
case let .onchainTransactionConfirmed(txid, blockHash, blockHeight, confirmationTime, details):

Check warning on line 1196 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'confirmationTime' was never used; consider replacing with '_' or removing it

Check warning on line 1196 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'blockHash' was never used; consider replacing with '_' or removing it

Check warning on line 1196 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'confirmationTime' was never used; consider replacing with '_' or removing it

Check warning on line 1196 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'blockHash' was never used; consider replacing with '_' or removing it
Logger.info("✅ Onchain transaction confirmed: txid=\(txid) blockHeight=\(blockHeight) amountSats=\(details.amountSats)")
Task {
do {
Expand Down Expand Up @@ -1209,7 +1247,7 @@

// MARK: Balance Events

case let .balanceChanged(oldSpendableOnchain, newSpendableOnchain, oldTotalOnchain, newTotalOnchain, oldLightning, newLightning):

Check warning on line 1250 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'newTotalOnchain' was never used; consider replacing with '_' or removing it

Check warning on line 1250 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'oldTotalOnchain' was never used; consider replacing with '_' or removing it

Check warning on line 1250 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

immutable value 'oldTotalOnchain' was never used; consider replacing with '_' or removing it
Logger
.info("💰 Balance changed: onchain=\(oldSpendableOnchain)->\(newSpendableOnchain) lightning=\(oldLightning)->\(newLightning)")

Expand Down Expand Up @@ -1376,14 +1414,12 @@
}

return try await ServiceQueue.background(.ldk) {
let fee = try node.onchainPayment().calculateTotalFee(
return try node.onchainPayment().calculateTotalFee(
address: address,
amountSats: amountSats,
feeRate: Self.convertVByteToKwu(satsPerVByte: satsPerVByte),
utxosToSpend: utxosToSpend
)

return fee
}
}

Expand Down Expand Up @@ -1421,9 +1457,7 @@
feesMsat = try node.bolt11Payment().estimateRoutingFees(invoice: invoice)
}

let feeSat = feesMsat / 1000

return feeSat
return feesMsat / 1000
}
}

Expand Down
213 changes: 0 additions & 213 deletions Bitkit/Utilities/ScenePhase.swift

This file was deleted.

Loading