Skip to content

Commit 220ee6a

Browse files
committed
fix: keep contact payment boundaries in view layer
1 parent 85858ee commit 220ee6a

6 files changed

Lines changed: 124 additions & 69 deletions

File tree

Bitkit/Services/PublicPaykitService.swift

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ enum PublicPaykitError: LocalizedError {
2020
}
2121

2222
enum PublicPaykitPaymentLaunchResult {
23-
case opened
23+
case opened(paymentRequest: String)
2424
case noEndpoint
2525
case notOpened
2626

@@ -176,13 +176,8 @@ enum PublicPaykitService {
176176
return payableEndpoints
177177
}
178178

179-
@MainActor
180179
static func beginPayment(
181-
to publicKey: String,
182-
app: AppViewModel,
183-
currency: CurrencyViewModel,
184-
settings: SettingsViewModel,
185-
sheets: SheetViewModel
180+
to publicKey: String
186181
) async throws -> PublicPaykitPaymentLaunchResult {
187182
let endpoints = try await fetchPublicEndpoints(publicKey: publicKey)
188183
let payableEndpoints = await payableEndpoints(from: endpoints)
@@ -191,16 +186,7 @@ enum PublicPaykitService {
191186
return endpoints.isEmpty ? .noEndpoint : .notOpened
192187
}
193188

194-
try await app.handleScannedData(paymentRequest(from: payableEndpoints))
195-
196-
guard let route = contactPaymentRoute(app: app, currency: currency, settings: settings) else {
197-
return .notOpened
198-
}
199-
200-
app.contactPaymentContext = ContactPaymentContext(publicKey: publicKey)
201-
sheets.showSheet(.send, data: SendConfig(view: route))
202-
203-
return .opened
189+
return .opened(paymentRequest: paymentRequest(from: payableEndpoints))
204190
}
205191

206192
static func paymentRequest(from endpoints: [Endpoint]) -> String {
@@ -213,37 +199,6 @@ enum PublicPaykitService {
213199
return "bitcoin:\(onchainEndpoint.paymentRequest)?lightning=\(bolt11Endpoint.paymentRequest)"
214200
}
215201

216-
@MainActor
217-
private static func contactPaymentRoute(
218-
app: AppViewModel,
219-
currency: CurrencyViewModel,
220-
settings: SettingsViewModel
221-
) -> SendRoute? {
222-
guard let route = PaymentNavigationHelper.appropriateSendRoute(app: app, currency: currency, settings: settings) else {
223-
return nil
224-
}
225-
226-
switch route {
227-
case .quickpay:
228-
if app.lnurlPayData != nil {
229-
return .lnurlPayAmount
230-
}
231-
232-
if app.scannedLightningInvoice != nil || app.scannedOnchainInvoice != nil {
233-
return .amount
234-
}
235-
236-
return route
237-
case .confirm:
238-
if app.scannedLightningInvoice != nil || app.scannedOnchainInvoice != nil {
239-
return .amount
240-
}
241-
return route
242-
default:
243-
return route
244-
}
245-
}
246-
247202
static func onchainMethodId(for address: String) -> MethodId {
248203
let normalizedAddress = address.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
249204

Bitkit/ViewModels/ActivityListViewModel.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class ActivityListViewModel: ObservableObject {
4747

4848
@Published private(set) var availableTags: [String] = []
4949

50+
var activitiesChangedPublisher: AnyPublisher<Void, Never> {
51+
coreService.activity.activitiesChangedPublisher
52+
}
53+
5054
private func updateAvailableTags() async {
5155
do {
5256
availableTags = try await coreService.activity.allPossibleTags()
@@ -268,6 +272,10 @@ class ActivityListViewModel: ObservableObject {
268272
return activity
269273
}
270274

275+
func contactActivities(publicKey: String) async throws -> [Activity] {
276+
try await coreService.activity.get(contact: publicKey, sortDirection: .desc)
277+
}
278+
271279
func setContact(_ contactPublicKey: String, forPaymentId paymentId: String, syncLdkPayments: Bool = true) async throws {
272280
if syncLdkPayments {
273281
try? await syncLdkNodePayments()

Bitkit/Views/Contacts/AddContactView.swift

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -273,17 +273,18 @@ struct AddContactView: View {
273273
}
274274

275275
do {
276-
let result = try await PublicPaykitService.beginPayment(
277-
to: normalizedPublicKey,
278-
app: app,
279-
currency: currency,
280-
settings: settings,
281-
sheets: sheets
282-
)
276+
let result = try await PublicPaykitService.beginPayment(to: normalizedPublicKey)
283277

284278
switch result {
285-
case .opened:
286-
break
279+
case let .opened(paymentRequest):
280+
guard await openContactPayment(paymentRequest: paymentRequest, publicKey: normalizedPublicKey) else {
281+
app.toast(
282+
type: .warning,
283+
title: t("slashtags__error_pay_title"),
284+
description: t("slashtags__error_pay_not_opened_msg")
285+
)
286+
return
287+
}
287288
case .noEndpoint:
288289
app.toast(
289290
type: .warning,
@@ -306,6 +307,51 @@ struct AddContactView: View {
306307
)
307308
}
308309
}
310+
311+
@MainActor
312+
private func openContactPayment(paymentRequest: String, publicKey: String) async -> Bool {
313+
do {
314+
try await app.handleScannedData(paymentRequest)
315+
} catch {
316+
Logger.warn("Failed to decode contact payment request: \(error)", context: "AddContactView")
317+
return false
318+
}
319+
320+
guard let route = contactPaymentRoute() else {
321+
return false
322+
}
323+
324+
app.contactPaymentContext = ContactPaymentContext(publicKey: publicKey)
325+
sheets.showSheet(.send, data: SendConfig(view: route))
326+
return true
327+
}
328+
329+
@MainActor
330+
private func contactPaymentRoute() -> SendRoute? {
331+
guard let route = PaymentNavigationHelper.appropriateSendRoute(app: app, currency: currency, settings: settings) else {
332+
return nil
333+
}
334+
335+
switch route {
336+
case .quickpay:
337+
if app.lnurlPayData != nil {
338+
return .lnurlPayAmount
339+
}
340+
341+
if app.scannedLightningInvoice != nil || app.scannedOnchainInvoice != nil {
342+
return .amount
343+
}
344+
345+
return route
346+
case .confirm:
347+
if app.scannedLightningInvoice != nil || app.scannedOnchainInvoice != nil {
348+
return .amount
349+
}
350+
return route
351+
default:
352+
return route
353+
}
354+
}
309355
}
310356

311357
#Preview {

Bitkit/Views/Contacts/ContactActivityView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct ContactActivityView: View {
4040
resolveContactName()
4141
await loadActivities()
4242
}
43-
.onReceive(CoreService.shared.activity.activitiesChangedPublisher) { _ in
43+
.onReceive(activityList.activitiesChangedPublisher) { _ in
4444
Task {
4545
await loadActivities()
4646
}
@@ -138,7 +138,7 @@ struct ContactActivityView: View {
138138
defer { isLoading = false }
139139

140140
do {
141-
activities = try await CoreService.shared.activity.get(contact: publicKey, sortDirection: .desc)
141+
activities = try await activityList.contactActivities(publicKey: publicKey)
142142
hasError = false
143143
} catch {
144144
Logger.error(error, context: "ContactActivityView")

Bitkit/Views/Contacts/ContactDetailView.swift

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -279,17 +279,18 @@ struct ContactDetailView: View {
279279

280280
private func payContact() async {
281281
do {
282-
let result = try await PublicPaykitService.beginPayment(
283-
to: publicKey,
284-
app: app,
285-
currency: currency,
286-
settings: settings,
287-
sheets: sheets
288-
)
282+
let result = try await PublicPaykitService.beginPayment(to: publicKey)
289283

290284
switch result {
291-
case .opened:
292-
break
285+
case let .opened(paymentRequest):
286+
guard await openContactPayment(paymentRequest: paymentRequest) else {
287+
app.toast(
288+
type: .warning,
289+
title: t("slashtags__error_pay_title"),
290+
description: t("slashtags__error_pay_not_opened_msg")
291+
)
292+
return
293+
}
293294
case .noEndpoint:
294295
app.toast(
295296
type: .warning,
@@ -312,6 +313,51 @@ struct ContactDetailView: View {
312313
)
313314
}
314315
}
316+
317+
@MainActor
318+
private func openContactPayment(paymentRequest: String) async -> Bool {
319+
do {
320+
try await app.handleScannedData(paymentRequest)
321+
} catch {
322+
Logger.warn("Failed to decode contact payment request: \(error)", context: "ContactDetailView")
323+
return false
324+
}
325+
326+
guard let route = contactPaymentRoute() else {
327+
return false
328+
}
329+
330+
app.contactPaymentContext = ContactPaymentContext(publicKey: publicKey)
331+
sheets.showSheet(.send, data: SendConfig(view: route))
332+
return true
333+
}
334+
335+
@MainActor
336+
private func contactPaymentRoute() -> SendRoute? {
337+
guard let route = PaymentNavigationHelper.appropriateSendRoute(app: app, currency: currency, settings: settings) else {
338+
return nil
339+
}
340+
341+
switch route {
342+
case .quickpay:
343+
if app.lnurlPayData != nil {
344+
return .lnurlPayAmount
345+
}
346+
347+
if app.scannedLightningInvoice != nil || app.scannedOnchainInvoice != nil {
348+
return .amount
349+
}
350+
351+
return route
352+
case .confirm:
353+
if app.scannedLightningInvoice != nil || app.scannedOnchainInvoice != nil {
354+
return .amount
355+
}
356+
return route
357+
default:
358+
return route
359+
}
360+
}
315361
}
316362

317363
#Preview {

BitkitTests/PublicPaykitServiceTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ final class PublicPaykitServiceTests: XCTestCase {
155155
}
156156

157157
func testPaymentLaunchResultFailureMessageKeys() {
158-
XCTAssertNil(PublicPaykitPaymentLaunchResult.opened.contactPaymentFailureMessageKey)
158+
XCTAssertNil(PublicPaykitPaymentLaunchResult.opened(paymentRequest: "bitcoin:bcrt1ptest").contactPaymentFailureMessageKey)
159159
XCTAssertEqual(PublicPaykitPaymentLaunchResult.noEndpoint.contactPaymentFailureMessageKey, "slashtags__error_pay_empty_msg")
160160
XCTAssertEqual(PublicPaykitPaymentLaunchResult.notOpened.contactPaymentFailureMessageKey, "slashtags__error_pay_not_opened_msg")
161161
}

0 commit comments

Comments
 (0)