Skip to content
Open
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 Bitkit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@
repositoryURL = "https://github.com/pubky/paykit-rs";
requirement = {
kind = exactVersion;
version = "0.1.0-rc37";
version = "0.1.0-rc39";
};
};
18D65DFE2EB9649F00252335 /* XCRemoteSwiftPackageReference "vss-rust-client-ffi" */ = {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

121 changes: 121 additions & 0 deletions Bitkit/AppScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import SwiftUI
import UserNotifications

struct AppScene: View {
private static let paykitPaymentRequestRefreshInterval: Duration = .seconds(30)

@Environment(\.scenePhase) var scenePhase
@EnvironmentObject private var session: SessionManager

Expand Down Expand Up @@ -35,6 +37,8 @@ struct AppScene: View {
@State private var trezorViewModel: TrezorViewModel
@State private var hwWalletManager: HwWalletManager
@State private var calculatorInputManager = CalculatorInputManager()
@State private var paykitPaymentRequestManager = PaykitPaymentRequestManager()
@State private var isPresentingPaykitPaymentRequest = false

@State private var hideSplash = false
@State private var removeSplash = false
Expand Down Expand Up @@ -133,6 +137,7 @@ struct AppScene: View {
config in AppUpdateSheet(config: config)
}
.task(priority: .userInitiated, setupTask)
.task(id: scenePhase) { await pollIncomingPaykitPaymentRequests() }
.onChange(of: currency.hasStaleData) { _, newValue in handleCurrencyStaleData(newValue) }
.onChange(of: wallet.walletExists) { _, newValue in handleWalletExistsChange(newValue) }
.onChange(of: wallet.nodeLifecycleState) { _, newValue in handleNodeLifecycleChange(newValue) }
Expand Down Expand Up @@ -191,17 +196,20 @@ struct AppScene: View {
.environment(trezorViewModel)
.environment(hwWalletManager)
.environment(calculatorInputManager)
.environment(paykitPaymentRequestManager)
.onChange(of: pubkyProfile.authState, initial: true) { _, authState in
if authState == .authenticated, let pk = pubkyProfile.publicKey {
Task {
try? await contactsManager.loadContacts(for: pk)
await refreshPrivateOnlyPaykitReceiverMarker()
await refreshIncomingPaykitPaymentRequests()
if !PaykitFeatureFlags.isUIEnabled, wallet.walletExists == true {
await retryPendingPaykitEndpointRemoval()
}
}
} else if authState == .idle {
contactsManager.reset()
paykitPaymentRequestManager.clear()
}
}
.onReceive(contactsManager.$contacts) { contacts in
Expand All @@ -212,8 +220,24 @@ struct AppScene: View {
let publicKeys = contacts.map(\.publicKey)
Task {
await PrivatePaykitService.shared.prepareSavedContacts(publicKeys, wallet: wallet)
await refreshIncomingPaykitPaymentRequests()
}
}
.onReceive(sheets.$activeSheetConfiguration) { configuration in
guard configuration == nil else { return }
Task { await presentNextIncomingPaykitPaymentRequest() }
}
.onChange(of: paykitPaymentRequestManager.pendingRequests) { _, requests in
guard let request = app.contactPaymentContext?.incomingPaymentRequest,
request.isExpired(at: Date()),
!requests.contains(where: { $0.id == request.id }),
sheets.activeSheetConfiguration?.id == .send
else { return }

app.resetSendState()
wallet.resetSendState(speed: settings.defaultTransactionSpeed)
sheets.hideSheetIfActive(.send, reason: "Incoming payment request expired")
}
.onChange(of: navigation.currentRoute) { oldRoute, newRoute in
guard shouldDiscardPendingImport(currentRoute: oldRoute, destination: newRoute) else {
return
Expand Down Expand Up @@ -639,6 +663,7 @@ struct AppScene: View {
contactsManager.contacts.map(\.publicKey),
wallet: wallet
)
await refreshIncomingPaykitPaymentRequests()
}
} else {
if case .errorStarting = state {
Expand Down Expand Up @@ -680,6 +705,7 @@ struct AppScene: View {
savedPublicKeys: contactPublicKeys,
wallet: wallet
)
await refreshIncomingPaykitPaymentRequests()
}
}
}
Expand All @@ -699,6 +725,100 @@ struct AppScene: View {
}
}

private func refreshIncomingPaykitPaymentRequests() async {
guard PaykitFeatureFlags.isUIEnabled,
wallet.walletExists == true,
pubkyProfile.authState == .authenticated
else { return }

await paykitPaymentRequestManager.refresh()
await presentNextIncomingPaykitPaymentRequest()
}

private func pollIncomingPaykitPaymentRequests() async {
guard scenePhase == .active else { return }

while !Task.isCancelled {
do {
try await Task.sleep(for: Self.paykitPaymentRequestRefreshInterval)
} catch {
return
}
await refreshIncomingPaykitPaymentRequests()
}
}

private func presentNextIncomingPaykitPaymentRequest() async {
guard !isPresentingPaykitPaymentRequest,
sheets.activeSheetConfiguration == nil,
app.contactPaymentContext == nil
else { return }

let requests = paykitPaymentRequestManager.requestsForPresentation()
guard !requests.isEmpty else { return }

isPresentingPaykitPaymentRequest = true
defer { isPresentingPaykitPaymentRequest = false }

for request in requests {
do {
let result = try await PrivatePaykitService.shared.beginPaymentRequest(request)
guard sheets.activeSheetConfiguration == nil, app.contactPaymentContext == nil else { return }
guard case let .opened(paymentTarget, privatePaymentContext) = result else { continue }

let contactPaymentContext = ContactPaymentContext(
publicKey: request.counterparty,
privatePaymentContext: privatePaymentContext,
incomingPaymentRequest: request
)
guard app.claimContactPaymentContext(contactPaymentContext) else { return }

do {
try await app.handleScannedData(
paymentTarget,
claimedContactPaymentContext: contactPaymentContext
)
guard app.ownsContactPaymentContext(contactPaymentContext),
sheets.activeSheetConfiguration == nil
else { return }
guard PaymentNavigationHelper.appropriateSendRoute(app: app, currency: currency, settings: settings) != nil else {
app.resetSendState()
wallet.resetSendState(speed: settings.defaultTransactionSpeed)
continue
}

guard paykitPaymentRequestManager.markPresentedIfPending(request) else {
app.resetSendState()
wallet.resetSendState(speed: settings.defaultTransactionSpeed)
continue
}
} catch is CancellationError {
if app.ownsContactPaymentContext(contactPaymentContext) {
app.resetSendState()
wallet.resetSendState(speed: settings.defaultTransactionSpeed)
}
return
} catch {
guard app.ownsContactPaymentContext(contactPaymentContext) else { return }
Logger.warn("Failed to present incoming Paykit payment request: \(error)", context: "AppScene")
app.resetSendState()
wallet.resetSendState(speed: settings.defaultTransactionSpeed)
continue
}

wallet.sendAmountSats = request.amountSats

let route: SendRoute = app.lnurlPayData == nil ? .confirm : .lnurlPayConfirm
sheets.showSheet(.send, data: SendConfig(view: route))
return
} catch is CancellationError {
return
} catch {
Logger.warn("Failed to present incoming Paykit payment request: \(error)", context: "AppScene")
}
}
}

private func retryPendingPaykitEndpointRemoval() async {
if PublicPaykitService.isCleanupPending {
do {
Expand Down Expand Up @@ -753,6 +873,7 @@ struct AppScene: View {
// to display balances (MoneyText returns "0" if rates are nil)
Task {
await currency.refresh()
await refreshIncomingPaykitPaymentRequests()
}

// Restart node if necessary (e.g. create/restore was skipped due to offline)
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/ar.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@
"widgets__weather__condition__poor__description" = "إذا لم تكن في عجلة للتعامل، قد يكون من الأفضل الانتظار قليلاً.";
"widgets__weather__current_fee" = "متوسط الرسوم الحالي";
"widgets__weather__next_block" = "تضمين الكتلة التالية";
"wallet__payment_request" = "طلب دفع";
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/ca.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@
"wallet__boost_fee_recomended" = "La teva transacció pot liquidar-se més ràpid si incloues una comissió de xarxa addicional. Aquí tens una recomanació:";
"wallet__boost_swipe" = "Llisca per impulsar";
"wallet__payment_received" = "Rebut Bitcoin";
"wallet__payment_request" = "Sol·licitud de pagament";
"wallet__instant_payment_received" = "Rebut Bitcoin instantani";
"wallet__filter_title" = "Selecciona rang";
"wallet__filter_clear" = "Neteja";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/cs.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,7 @@
"wallet__boost_recomended_button" = "Použít navrhovaný poplatek";
"wallet__boost_swipe" = "Přejetím posilte";
"wallet__payment_received" = "bitcoin přijatý";
"wallet__payment_request" = "Žádost o platbu";
"wallet__instant_payment_received" = "Přijatý okamžitý bitcoin";
"wallet__error_create_tx" = "Vytvoření transakce se nezdařilo";
"wallet__error_create_tx_msg" = "Došlo k chybě. Zkuste to prosím znovu {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@
"wallet__boost_recomended_button" = "Empfohlene Gebühr verwenden";
"wallet__boost_swipe" = "Zum Beschleunigen wischen";
"wallet__payment_received" = "Bitcoin empfangen";
"wallet__payment_request" = "Zahlungsanforderung";
"wallet__instant_payment_received" = "Sofortiger Bitcoin empfangen";
"wallet__error_create_tx" = "Transaktionserstellung fehlgeschlagen";
"wallet__error_create_tx_msg" = "Ein Fehler ist aufgetreten. Bitte versuche es erneut {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/el.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,7 @@
"wallet__boost_fee_recomended" = "Η συναλλαγή σας μπορεί να ολοκληρωθεί πιο γρήγορα αν συμπεριλάβετε ένα επιπλέον τέλος δικτύου. Ακολουθεί μια σύσταση:";
"wallet__boost_swipe" = "Σύρετε για Ενίσχυση";
"wallet__payment_received" = "Bitcoin Λήφθηκε";
"wallet__payment_request" = "Αίτημα πληρωμής";
"wallet__instant_payment_received" = "Άμεσο Bitcoin Λήφθηκε";
"wallet__filter_title" = "Επιλογή Εύρους";
"wallet__filter_clear" = "Εκκαθάριση";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,7 @@
"wallet__boost_recomended_button" = "Use Suggested Fee";
"wallet__boost_swipe" = "Swipe To Boost";
"wallet__payment_received" = "Received Bitcoin";
"wallet__payment_request" = "Payment Request";
"wallet__instant_payment_received" = "Received Instant Bitcoin";
"wallet__error_create_tx" = "Transaction Creation Failed";
"wallet__error_create_tx_msg" = "An error occurred. Please try again {raw}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@
"wallet__boost_recomended_button" = "Usar Tasa sugerida";
"wallet__boost_swipe" = "Deslizar para impulsar";
"wallet__payment_received" = "Bitcoin recibido";
"wallet__payment_request" = "Solicitud de pago";
"wallet__instant_payment_received" = "Bitcoin instantáneo recibido";
"wallet__error_create_tx" = "Fallo en la creación de la transacción";
"wallet__error_create_tx_msg" = "Se ha producido un error. Vuelva a intentarlo {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@
"wallet__boost_recomended_button" = "Usar Comisión Sugerida";
"wallet__boost_swipe" = "Deslizar para impulsar";
"wallet__payment_received" = "Bitcoin recibido";
"wallet__payment_request" = "Solicitud de pago";
"wallet__instant_payment_received" = "Bitcoin Instantáneo Recibido";
"wallet__error_create_tx_msg" = "Ocurrió un error. Por favor, intente de nuevo {raw}";
"wallet__filter_title" = "Seleccione Rango";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,7 @@
"wallet__boost_recomended_button" = "Utilise les frais suggérés";
"wallet__boost_swipe" = "Balayer pour booster";
"wallet__payment_received" = "Bitcoin reçus";
"wallet__payment_request" = "Demande de paiement";
"wallet__instant_payment_received" = "Réception de bitcoins instantanés";
"wallet__error_create_tx" = "Échec de la création d\'une transaction";
"wallet__error_create_tx_msg" = "Une erreur s\'est produite. Veuillez réessayer {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,7 @@
"wallet__boost_recomended_button" = "Utilizza la tariffa suggerita";
"wallet__boost_swipe" = "Scorri per Potenziare";
"wallet__payment_received" = "Bitcoin ricevuti";
"wallet__payment_request" = "Richiesta di pagamento";
"wallet__instant_payment_received" = "Ricevuti Bitcoin istantanei";
"wallet__error_create_tx" = "Creazione della transazione non riuscita";
"wallet__error_create_tx_msg" = "Si è verificato un errore. Per favore riprova {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/nl.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,7 @@
"wallet__boost_recomended_button" = "Voorgestelde Vergoeding";
"wallet__boost_swipe" = "Veeg Om Te Boosten";
"wallet__payment_received" = "Bitcoin Ontvangen";
"wallet__payment_request" = "Betaalverzoek";
"wallet__instant_payment_received" = "Direct Bitcoin Ontvangen";
"wallet__error_create_tx" = "Aanmaak Transactie Mislukt";
"wallet__error_create_tx_msg" = "Er is een fout opgetreden. Probeer opnieuw {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/pl.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,7 @@
"wallet__boost_recomended_button" = "Zastosuj sugerowaną opłatę";
"wallet__boost_swipe" = "Przesuń, aby przyspieszyć";
"wallet__payment_received" = "Otrzymano Bitcoinów";
"wallet__payment_request" = "Żądanie płatności";
"wallet__instant_payment_received" = "Otrzymano bitcoin natychmiastowo";
"wallet__error_create_tx" = "Tworzenie transakcji nie powiodło się";
"wallet__error_create_tx_msg" = "Wystąpił błąd. Proszę spróbować ponownie {raw}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,7 @@
"wallet__boost_recomended_button" = "Usar Taxa Sugerida";
"wallet__boost_swipe" = "Arraste para acelerar";
"wallet__payment_received" = "Bitcoin Recebido";
"wallet__payment_request" = "Solicitação de pagamento";
"wallet__instant_payment_received" = "Bitcoin Recebido Instantaneamente";
"wallet__error_create_tx" = "Falha na Criação da Transação";
"wallet__error_create_tx_msg" = "Ocorreu um erro. Por favor, tente novamente {raw}";
Expand Down
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/pt.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@
"widgets__weather__condition__poor__description" = "Se você não estiver com pressa para fazer uma transação, talvez seja melhor esperar um pouco.";
"widgets__weather__current_fee" = "Tarifa média atual";
"widgets__weather__next_block" = "Inclusão no próximo bloco";
"wallet__payment_request" = "Pedido de pagamento";
1 change: 1 addition & 0 deletions Bitkit/Resources/Localization/ru.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@
"wallet__boost_recomended_button" = "Использовать рекомендованную комиссию";
"wallet__boost_swipe" = "Ускорить";
"wallet__payment_received" = "Получен Биткоин";
"wallet__payment_request" = "Запрос на оплату";
"wallet__instant_payment_received" = "Получен Мгновенный Биткоин";
"wallet__error_create_tx" = "Ошибка создания транзакции";
"wallet__error_create_tx_msg" = "Произошла ошибка. Пожалуйста, попробуйте снова {raw}";
Expand Down
Loading
Loading