From a8443c919a1fa683412e2396656887b3ef9b1cfc Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Thu, 2 May 2024 21:24:41 +0800 Subject: [PATCH 1/3] feat: update pay verification interval on opened request --- .../screens/payment_request_screen.dart | 18 ++++++ .../services/payment_request_service.dart | 56 +++++++++++++++---- .../payment_request/widgets/extensions.dart | 5 ++ .../widgets/share_request.dart | 7 +-- 4 files changed, 71 insertions(+), 15 deletions(-) diff --git a/packages/espressocash_app/lib/features/payment_request/screens/payment_request_screen.dart b/packages/espressocash_app/lib/features/payment_request/screens/payment_request_screen.dart index d6a5b6a7db..e7592e547a 100644 --- a/packages/espressocash_app/lib/features/payment_request/screens/payment_request_screen.dart +++ b/packages/espressocash_app/lib/features/payment_request/screens/payment_request_screen.dart @@ -1,9 +1,12 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import '../../../di.dart'; import '../../../ui/loader.dart'; import '../data/repository.dart'; import '../models/payment_request.dart'; +import '../services/payment_request_service.dart'; import '../widgets/request_success.dart'; import '../widgets/share_request.dart'; @@ -33,6 +36,21 @@ class _PaymentRequestScreenState extends State { void initState() { super.initState(); _stream = sl().watchById(widget.id); + + _watcher(); + } + + Future _watcher() async { + final request = await _stream.first; + + sl().initWatcher(request); + } + + @override + void dispose() { + sl().disposeWatcher(); + + super.dispose(); } @override diff --git a/packages/espressocash_app/lib/features/payment_request/services/payment_request_service.dart b/packages/espressocash_app/lib/features/payment_request/services/payment_request_service.dart index cd4966563c..0e42073c48 100644 --- a/packages/espressocash_app/lib/features/payment_request/services/payment_request_service.dart +++ b/packages/espressocash_app/lib/features/payment_request/services/payment_request_service.dart @@ -5,6 +5,7 @@ import 'package:dfunc/dfunc.dart'; import 'package:espressocash_api/espressocash_api.dart'; import 'package:flutter/foundation.dart'; +import 'package:get_it/get_it.dart'; import 'package:injectable/injectable.dart'; import 'package:rxdart/rxdart.dart'; import 'package:solana/solana.dart'; @@ -20,7 +21,7 @@ import '../data/repository.dart'; import '../models/payment_request.dart'; @Singleton(scope: authScope) -class PaymentRequestService { +class PaymentRequestService implements Disposable { PaymentRequestService( this._repository, this._solanaClient, @@ -38,6 +39,8 @@ class PaymentRequestService { final Map> _subscriptions = {}; final Map _currentBackoffs = {}; + StreamSubscription? _watcher; + @PostConstruct(preResolve: true) Future init() async { final pendingPayments = await _repository.getAllPending(); @@ -48,14 +51,32 @@ class PaymentRequestService { } void _subscribe(PaymentRequest request) { - _waitForTx(request); + if (!request.state.isInitial) return; + + _subscriptions[request.id]?.cancel(); + _subscriptions[request.id] = _createSubscription(request); } - void _waitForTx(PaymentRequest request) { + void initWatcher(PaymentRequest request) { if (!request.state.isInitial) return; + _watcher?.cancel(); + _watcher = _createSubscription(request, interval: _focusedInterval); + } + + void disposeWatcher() { + _watcher?.cancel(); + } + + StreamSubscription _createSubscription( + PaymentRequest request, { + Duration interval = _backgroundInterval, + }) { final reference = request.payRequest.reference?.firstOrNull; - if (reference == null) return; + + if (reference == null) { + return const Stream.empty().listen(null); + } Stream solanaPayTransaction() => _solanaClient .findSolanaPayTransaction( @@ -65,10 +86,9 @@ class PaymentRequestService { .asStream() .whereType(); - _subscriptions[request.id] = - Stream.periodic(const Duration(seconds: 30)) - .flatMap((a) => solanaPayTransaction()) - .mergeWith([solanaPayTransaction()]).listen( + return Stream.periodic(interval) + .flatMap((a) => solanaPayTransaction()) + .mergeWith([solanaPayTransaction()]).listen( (id) { _verifyTx(id, request); }, @@ -80,8 +100,8 @@ class PaymentRequestService { _currentBackoffs[request.id] = _maxBackoff; } await Future.delayed(_currentBackoffs[request.id]!); - // ignore: avoid-recursive-calls, called in async callback - _waitForTx(request); + + _subscribe(request); }, ); } @@ -113,6 +133,7 @@ class PaymentRequestService { _refreshBalance(); await _subscriptions[request.id]?.cancel(); + await _watcher?.cancel(); } on Exception { _currentBackoffs[request.id] = (_currentBackoffs[request.id] ?? _minBackoff) * _backoffStep; @@ -169,9 +190,21 @@ class PaymentRequestService { return paymentRequest; } + Future cancel(String id) async { + await _repository.delete(id); + + await _subscriptions[id]?.cancel(); + } + Future unshortenLink(String shortLink) => _ecClient .unshortenLink(UnshortenLinkRequestDto(shortLink: shortLink)) .then((e) => Uri.parse(e.fullLink)); + + @override + Future onDispose() async { + await _watcher?.cancel(); + await Future.wait(_subscriptions.values.map((it) => it.cancel())); + } } Future _randomPublicKey([dynamic _]) async { @@ -184,6 +217,9 @@ const _backoffStep = 2; const _minBackoff = Duration(seconds: 2); const _maxBackoff = Duration(minutes: 1); +const _backgroundInterval = Duration(seconds: 30); +const _focusedInterval = Duration(seconds: 1); + extension on PaymentRequestState { bool get isInitial => this == PaymentRequestState.initial; } diff --git a/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart b/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart index c92657d773..83872e2c35 100644 --- a/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart @@ -25,4 +25,9 @@ extension PaymentRequestExt on BuildContext { return payment.id; }); + + void cancelRequest({required String id}) { + sl().cancel(id); + Navigator.of(this).pop(); + } } diff --git a/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart b/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart index 22ab4452df..5a85fa22ae 100644 --- a/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart +++ b/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart @@ -12,8 +12,8 @@ import '../../../ui/text_button.dart'; import '../../../ui/theme.dart'; import '../../conversion_rates/widgets/extensions.dart'; import '../../tokens/token_list.dart'; -import '../data/repository.dart'; import '../models/payment_request.dart'; +import 'extensions.dart'; class ShareRequestPayment extends StatelessWidget { const ShareRequestPayment({ @@ -93,10 +93,7 @@ class ShareRequestPayment extends StatelessWidget { .toUpperCase(), message: context .l10n.paymentRequest_lblCancelConfirmationSubtitle, - onConfirm: () { - sl().delete(request.id); - Navigator.of(context).pop(); - }, + onConfirm: () => context.cancelRequest(id: request.id), ), ), ), From 52bdae20d368ce78d53b3b6ac9346fddcaf87a01 Mon Sep 17 00:00:00 2001 From: ookami-kb Date: Thu, 2 May 2024 22:57:15 +0200 Subject: [PATCH 2/3] upd --- .../lib/features/payment_request/widgets/extensions.dart | 5 ----- .../lib/features/payment_request/widgets/share_request.dart | 6 +++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart b/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart index 83872e2c35..c92657d773 100644 --- a/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/payment_request/widgets/extensions.dart @@ -25,9 +25,4 @@ extension PaymentRequestExt on BuildContext { return payment.id; }); - - void cancelRequest({required String id}) { - sl().cancel(id); - Navigator.of(this).pop(); - } } diff --git a/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart b/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart index 5a85fa22ae..5bc64c3a98 100644 --- a/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart +++ b/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart @@ -13,6 +13,7 @@ import '../../../ui/theme.dart'; import '../../conversion_rates/widgets/extensions.dart'; import '../../tokens/token_list.dart'; import '../models/payment_request.dart'; +import '../services/payment_request_service.dart'; import 'extensions.dart'; class ShareRequestPayment extends StatelessWidget { @@ -93,7 +94,10 @@ class ShareRequestPayment extends StatelessWidget { .toUpperCase(), message: context .l10n.paymentRequest_lblCancelConfirmationSubtitle, - onConfirm: () => context.cancelRequest(id: request.id), + onConfirm: () { + sl().cancel(request.id); + Navigator.of(context).pop(); + }, ), ), ), From 334b112c39501e994fe81a5c8cd78ef6345d30df Mon Sep 17 00:00:00 2001 From: ookami-kb Date: Thu, 2 May 2024 23:03:05 +0200 Subject: [PATCH 3/3] upd --- .../lib/features/payment_request/widgets/share_request.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart b/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart index 5bc64c3a98..298f64109f 100644 --- a/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart +++ b/packages/espressocash_app/lib/features/payment_request/widgets/share_request.dart @@ -14,7 +14,6 @@ import '../../conversion_rates/widgets/extensions.dart'; import '../../tokens/token_list.dart'; import '../models/payment_request.dart'; import '../services/payment_request_service.dart'; -import 'extensions.dart'; class ShareRequestPayment extends StatelessWidget { const ShareRequestPayment({