minor fixes

This commit is contained in:
Arseni
2026-01-21 16:59:38 +03:00
parent d14e6d0f7a
commit 32350ac571
5 changed files with 57 additions and 23 deletions

View File

@@ -96,13 +96,12 @@ class QuotationIntentBuilder {
if (name != null && name.isNotEmpty) {
final parts = name.split(RegExp(r'\s+'));
if (parts.length == 1) {
firstName = parts.first;
} else if (parts.length == 2) {
if (parts.isNotEmpty) {
firstName = parts.first;
}
if (parts.length == 2) {
lastName = parts.last;
} else {
firstName = parts.first;
} else if (parts.length > 2) {
lastName = parts.last;
middleName = parts.sublist(1, parts.length - 1).join(' ');
}

View File

@@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:collection/collection.dart';
import 'dart:convert';
import 'package:uuid/uuid.dart';
@@ -23,6 +23,7 @@ import 'package:pshared/provider/resource.dart';
import 'package:pshared/provider/payment/quotation/auto_refresh.dart';
import 'package:pshared/provider/payment/quotation/intent_builder.dart';
import 'package:pshared/service/payment/quotation.dart';
import 'package:pshared/utils/exception.dart';
class QuotationProvider extends ChangeNotifier {
@@ -36,6 +37,11 @@ class QuotationProvider extends ChangeNotifier {
QuotationAutoRefreshController();
AutoRefreshMode _autoRefreshMode = AutoRefreshMode.on;
QuotationProvider() {
addListener(_handleStateChanged);
_syncAutoRefresh();
}
void update(
OrganizationsProvider venue,
PaymentAmountProvider payment,
@@ -53,11 +59,10 @@ class QuotationProvider extends ChangeNotifier {
methods: methods,
);
if (intent == null) return;
final lastIntentDto = _lastIntent?.toDTO().toJson();
final isSameIntent = lastIntentDto != null &&
const DeepCollectionEquality().equals(intent.toDTO().toJson(), lastIntentDto);
if (isSameIntent) return;
getQuotation(intent);
final intentKey = _buildIntentKey(intent);
final lastIntent = _lastIntent;
if (lastIntent != null && intentKey == _buildIntentKey(lastIntent)) return;
getQuotation(intent, idempotencyKey: intentKey);
}
PaymentQuote? get quotation => _quotation.data;
@@ -86,7 +91,7 @@ class QuotationProvider extends ChangeNotifier {
return timeLeft <= Duration.zero;
}
QuoteStatusType get quoteStatusType {
QuoteStatusType get quoteStatus {
if (isLoading) return QuoteStatusType.loading;
if (error != null) return QuoteStatusType.error;
if (quotation == null) return QuoteStatusType.missing;
@@ -103,34 +108,37 @@ class QuotationProvider extends ChangeNotifier {
return createAsset(money.currency, money.amount);
}
void _handleStateChanged() {
_syncAutoRefresh();
}
void _setResource(Resource<PaymentQuote> quotation) {
_quotation = quotation;
_syncAutoRefresh();
notifyListeners();
}
void setAutoRefreshMode(AutoRefreshMode mode) {
if (_autoRefreshMode == mode) return;
_autoRefreshMode = mode;
_syncAutoRefresh();
notifyListeners();
}
Future<PaymentQuote?> refreshQuotation() async {
final intent = _lastIntent;
if (intent == null) return null;
return getQuotation(intent);
return getQuotation(intent, idempotencyKey: _buildIntentKey(intent));
}
Future<PaymentQuote?> getQuotation(PaymentIntent intent) async {
Future<PaymentQuote?> getQuotation(PaymentIntent intent, {String? idempotencyKey}) async {
if (!_organizations.isOrganizationSet) throw StateError('Organization is not set');
_lastIntent = intent;
final intentKey = idempotencyKey ?? _buildIntentKey(intent);
try {
_setResource(_quotation.copyWith(isLoading: true, error: null));
final response = await QuotationService.getQuotation(
_organizations.current.id,
QuotePaymentRequest(
idempotencyKey: Uuid().v4(),
idempotencyKey: intentKey,
intent: intent.toDTO(),
),
);
@@ -140,7 +148,7 @@ class QuotationProvider extends ChangeNotifier {
_logger.warning('Failed to get quotation', e, st);
_setResource(_quotation.copyWith(
data: null,
error: e is Exception ? e : Exception(e.toString()),
error: toException(e),
isLoading: false,
));
}
@@ -169,7 +177,13 @@ class QuotationProvider extends ChangeNotifier {
@override
void dispose() {
removeListener(_handleStateChanged);
_autoRefreshController.dispose();
super.dispose();
}
String _buildIntentKey(PaymentIntent intent) {
final payload = jsonEncode(intent.toDTO().toJson());
return Uuid().v5(Uuid.NAMESPACE_URL, 'quote:$payload');
}
}

View File

@@ -45,7 +45,7 @@ class _QuoteStatusState extends State<QuoteStatus> {
final provider = context.watch<QuotationProvider>();
final timeLeft = provider.quoteTimeLeft;
final isLoading = provider.isLoading;
final statusType = provider.quoteStatusType;
final statusType = provider.quoteStatus;
final autoRefreshMode = provider.autoRefreshMode;
String statusText;

View File

@@ -1,11 +1,31 @@
import 'package:duration/duration.dart';
String formatQuoteDuration(Duration duration) {
final totalSeconds = duration.inSeconds < 0 ? 0 : duration.inSeconds;
final hours = totalSeconds ~/ 3600;
final minutes = (totalSeconds % 3600) ~/ 60;
final seconds = totalSeconds % 60;
final clampedDuration = duration.isNegative ? Duration.zero : duration;
final pretty = prettyDuration(
clampedDuration,
tersity: DurationTersity.second,
upperTersity: DurationTersity.hour,
abbreviated: true,
delimiter: ':',
spacer: '',
);
final units = _extractHms(pretty);
final hours = units['h'] ?? 0;
final minutes = units['m'] ?? 0;
final seconds = units['s'] ?? 0;
if (hours > 0) {
return '${hours.toString()}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
}
return '${minutes.toString()}:${seconds.toString().padLeft(2, '0')}';
}
Map<String, int> _extractHms(String pretty) {
final matches = RegExp(r'(\d+)([hms])').allMatches(pretty);
final units = <String, int>{};
for (final match in matches) {
units[match.group(2)!] = int.parse(match.group(1)!);
}
return units;
}

View File

@@ -69,6 +69,7 @@ dependencies:
flutter_multi_formatter: ^2.13.7
dotted_border: ^3.1.0
qr_flutter: ^4.1.0
duration: ^4.0.3