This commit is contained in:
Arseni
2025-12-30 17:56:15 +03:00
parent f3ad4c2d4f
commit c3ec50c8e4
4 changed files with 64 additions and 77 deletions

View File

@@ -84,12 +84,9 @@ class QuotationProvider extends ChangeNotifier {
return _lastRequestSignature == _signature(_pendingIntent!);
}
bool get hasLiveQuote =>
_isLoaded &&
!_isExpired &&
!_quotation.isLoading &&
_quotation.error == null &&
quotation != null;
bool get isReady => _isLoaded && !_isExpired && !_quotation.isLoading && _quotation.error == null;
bool get hasLiveQuote => isReady && quotation != null;
Duration? get timeToExpire {
final expiresAt = _quoteExpiry;
@@ -176,9 +173,10 @@ class QuotationProvider extends ChangeNotifier {
void refreshNow({bool force = true}) {
_debounceTimer?.cancel();
if (!_organizationAttached) return;
if (_pendingIntent == null) {
_reset();
if (!canRequestQuote) {
if (_pendingIntent == null) {
_reset();
}
return;
}
unawaited(_requestQuotation(_pendingIntent!, force: force));

View File

@@ -15,8 +15,6 @@ import 'package:pweb/pages/payment_methods/payment_page/body.dart';
import 'package:pweb/widgets/sidebar/destinations.dart';
import 'package:pweb/services/posthog.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentPage extends StatefulWidget {
final ValueChanged<Recipient?>? onBack;
@@ -85,16 +83,12 @@ class _PaymentPageState extends State<PaymentPage> {
final flowProvider = context.read<PaymentFlowProvider>();
final paymentProvider = context.read<PaymentProvider>();
final quotationProvider = context.read<QuotationProvider>();
final loc = AppLocalizations.of(context)!;
if (paymentProvider.isLoading) return;
if (!quotationProvider.hasLiveQuote) {
if (quotationProvider.canRequestQuote) {
quotationProvider.refreshNow();
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(quotationProvider.canRequestQuote ? loc.quoteExpired : loc.quoteUnavailable)),
);
return;
}

View File

@@ -1,14 +1,9 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/payment/provider.dart';
import 'package:pshared/provider/payment/quotation.dart';
import 'package:pshared/provider/recipient/provider.dart';
import 'package:pweb/models/button_state.dart';
import 'package:pweb/pages/dashboard/payouts/form.dart';
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
import 'package:pweb/pages/payment_methods/payment_page/header.dart';
@@ -103,18 +98,7 @@ class PaymentPageContent extends StatelessWidget {
SizedBox(height: dimensions.paddingLarge),
const QuoteStatus(),
SizedBox(height: dimensions.paddingXXLarge),
Consumer2<QuotationProvider, PaymentProvider>(
builder: (context, quotation, payment, _) {
final canSend = quotation.hasLiveQuote && !payment.isLoading;
final state = payment.isLoading
? ButtonState.loading
: (canSend ? ButtonState.enabled : ButtonState.disabled);
return SendButton(
onPressed: canSend ? onSend : null,
state: state,
);
},
),
SendButton(onPressed: onSend),
SizedBox(height: dimensions.paddingLarge),
],
),

View File

@@ -1,5 +1,10 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/provider/payment/provider.dart';
import 'package:pshared/provider/payment/quotation.dart';
import 'package:pweb/models/button_state.dart';
import 'package:pweb/utils/dimensions.dart';
@@ -8,58 +13,64 @@ import 'package:pweb/generated/i18n/app_localizations.dart';
class SendButton extends StatelessWidget {
final VoidCallback? onPressed;
final ButtonState state;
const SendButton({
super.key,
required this.onPressed,
this.state = ButtonState.enabled,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final dimensions = AppDimensions();
final isLoading = state == ButtonState.loading;
final isActive = state == ButtonState.enabled && onPressed != null && !isLoading;
final backgroundColor = isActive
? theme.colorScheme.primary
: theme.colorScheme.primary.withValues(alpha: 0.5);
final textColor = theme.colorScheme.onSecondary.withValues(alpha: isActive ? 1 : 0.7);
Widget build(BuildContext context) => Consumer2<QuotationProvider, PaymentProvider>(
builder: (context, quotation, payment, _) {
final theme = Theme.of(context);
final dimensions = AppDimensions();
return Center(
child: SizedBox(
width: dimensions.buttonWidth,
height: dimensions.buttonHeight,
child: InkWell(
borderRadius: BorderRadius.circular(dimensions.borderRadiusSmall),
onTap: isActive ? onPressed : null,
child: Container(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(dimensions.borderRadiusSmall),
final canSend = quotation.hasLiveQuote && !payment.isLoading;
final state = payment.isLoading
? ButtonState.loading
: (canSend ? ButtonState.enabled : ButtonState.disabled);
final isLoading = state == ButtonState.loading;
final isActive = state == ButtonState.enabled && onPressed != null;
final backgroundColor = isActive
? theme.colorScheme.primary
: theme.colorScheme.primary.withValues(alpha: 0.5);
final textColor = theme.colorScheme.onSecondary.withValues(alpha: isActive ? 1 : 0.7);
return Center(
child: SizedBox(
width: dimensions.buttonWidth,
height: dimensions.buttonHeight,
child: InkWell(
borderRadius: BorderRadius.circular(dimensions.borderRadiusSmall),
onTap: isActive ? onPressed : null,
child: Container(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(dimensions.borderRadiusSmall),
),
child: Center(
child: isLoading
? SizedBox(
height: dimensions.iconSizeSmall,
width: dimensions.iconSizeSmall,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(textColor),
),
)
: Text(
AppLocalizations.of(context)!.send,
style: theme.textTheme.bodyLarge?.copyWith(
color: textColor,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
child: Center(
child: isLoading
? SizedBox(
height: dimensions.iconSizeSmall,
width: dimensions.iconSizeSmall,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(textColor),
),
)
: Text(
AppLocalizations.of(context)!.send,
style: theme.textTheme.bodyLarge?.copyWith(
color: textColor,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
);
}
);
},
);
}