This commit is contained in:
Arseni
2026-03-04 17:43:18 +03:00
parent 80b25a8608
commit aff804ec58
46 changed files with 1090 additions and 345 deletions

View File

@@ -1,22 +0,0 @@
import 'package:flutter/material.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class SourceQuotePanelHeader extends StatelessWidget {
const SourceQuotePanelHeader({
super.key,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final l10n = AppLocalizations.of(context)!;
return Text(
l10n.sourceOfFunds,
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
);
}
}

View File

@@ -2,93 +2,134 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pshared/controllers/payment/source.dart';
import 'package:pshared/provider/payment/multiple/quotation.dart';
import 'package:pweb/controllers/payouts/multiple_payouts.dart';
import 'package:pweb/controllers/payouts/payout_verification.dart';
import 'package:pweb/models/payment/source_funds.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/actions.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/panels/source_quote/header.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/panels/source_quote/summary.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/widgets/quote_status.dart';
import 'package:pweb/pages/payout_page/send/widgets/send_button.dart';
import 'package:pweb/widgets/payment/source_of_funds_panel.dart';
import 'package:pweb/widgets/payment/source_wallet_selector.dart';
import 'package:pweb/widgets/cooldown_hint.dart';
import 'package:pweb/widgets/refresh_balance/wallet.dart';
import 'package:pweb/models/state/control_state.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class SourceQuotePanel extends StatelessWidget {
const SourceQuotePanel({
super.key,
required this.controller,
required this.walletsController,
});
const SourceQuotePanel({super.key, required this.controller});
final MultiplePayoutsController controller;
final WalletsController walletsController;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final verificationController =
context.watch<PayoutVerificationController>();
final l10n = AppLocalizations.of(context)!;
final sourceController = context.watch<PaymentSourceController>();
final verificationController = context
.watch<PayoutVerificationController>();
final quotationProvider = context.watch<MultiQuotationProvider>();
final verificationContextKey = quotationProvider.quotation?.quoteRef ??
final verificationContextKey =
quotationProvider.quotation?.quoteRef ??
quotationProvider.quotation?.idempotencyKey;
final isCooldownActive = verificationController.isCooldownActiveFor(
verificationContextKey,
);
final canSend = controller.canSend && !isCooldownActive;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: theme.colorScheme.outlineVariant),
return SourceOfFundsPanel(
title: l10n.sourceOfFunds,
sourceSelector: SourceWalletSelector(
sourceController: sourceController,
isBusy: controller.isBusy,
),
visibleStates: const <SourceOfFundsVisibleState>{
SourceOfFundsVisibleState.headerAction,
SourceOfFundsVisibleState.summary,
SourceOfFundsVisibleState.quoteStatus,
SourceOfFundsVisibleState.sendAction,
},
stateWidgets: <SourceOfFundsVisibleState, Widget>{
SourceOfFundsVisibleState.headerAction: _MultipleRefreshAction(
sourceController: sourceController,
),
SourceOfFundsVisibleState.summary: SourceQuoteSummary(
controller: controller,
spacing: 12,
),
SourceOfFundsVisibleState.quoteStatus: MultipleQuoteStatusCard(
controller: controller,
),
SourceOfFundsVisibleState.sendAction: _MultipleSendAction(
controller: controller,
canSend: canSend,
isCooldownActive: isCooldownActive,
verificationController: verificationController,
verificationContextKey: verificationContextKey,
),
},
);
}
}
class _MultipleRefreshAction extends StatelessWidget {
const _MultipleRefreshAction({required this.sourceController});
final PaymentSourceController sourceController;
@override
Widget build(BuildContext context) {
final selectedWallet = sourceController.selectedWallet;
if (selectedWallet == null) {
return const SizedBox.shrink();
}
return WalletBalanceRefreshButton(walletRef: selectedWallet.id);
}
}
class _MultipleSendAction extends StatelessWidget {
const _MultipleSendAction({
required this.controller,
required this.canSend,
required this.isCooldownActive,
required this.verificationController,
required this.verificationContextKey,
});
final MultiplePayoutsController controller;
final bool canSend;
final bool isCooldownActive;
final PayoutVerificationController verificationController;
final String? verificationContextKey;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SourceQuotePanelHeader(),
const SizedBox(height: 8),
SourceWalletSelector(
walletsController: walletsController,
isBusy: controller.isBusy,
SendButton(
onPressed: () => handleMultiplePayoutSend(context, controller),
state: controller.isSending
? ControlState.loading
: canSend
? ControlState.enabled
: ControlState.disabled,
),
const SizedBox(height: 12),
const Divider(height: 1),
const SizedBox(height: 12),
SourceQuoteSummary(controller: controller, spacing: 12),
const SizedBox(height: 12),
MultipleQuoteStatusCard(controller: controller),
const SizedBox(height: 12),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SendButton(
onPressed: () => handleMultiplePayoutSend(context, controller),
state: controller.isSending
? ControlState.loading
: canSend
? ControlState.enabled
: ControlState.disabled,
),
if (isCooldownActive) ...[
const SizedBox(height: 8),
CooldownHint(
seconds: verificationController.cooldownRemainingSecondsFor(
verificationContextKey,
),
),
],
],
if (isCooldownActive) ...[
const SizedBox(height: 8),
CooldownHint(
seconds: verificationController.cooldownRemainingSecondsFor(
verificationContextKey,
),
),
),
],
],
),
);
}
}

View File

@@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pweb/controllers/payouts/multiple_payouts.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/panels/source_quote/widget.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/panels/upload_panel/widget.dart';
@@ -9,14 +7,9 @@ import 'package:pweb/pages/dashboard/payouts/multiple/sections/upload_csv/panel_
class UploadCsvLayout extends StatelessWidget {
const UploadCsvLayout({
super.key,
required this.controller,
required this.walletsController,
});
const UploadCsvLayout({super.key, required this.controller});
final MultiplePayoutsController controller;
final WalletsController walletsController;
@override
Widget build(BuildContext context) {
@@ -27,28 +20,17 @@ class UploadCsvLayout extends StatelessWidget {
if (!useHorizontal) {
return Column(
children: [
PanelCard(
child: UploadPanel(
controller: controller,
),
),
PanelCard(child: UploadPanel(controller: controller)),
if (hasFile) ...[
const SizedBox(height: 12),
SourceQuotePanel(
controller: controller,
walletsController: walletsController,
),
SourceQuotePanel(controller: controller),
],
],
);
}
if (!hasFile) {
return PanelCard(
child: UploadPanel(
controller: controller,
),
);
return PanelCard(child: UploadPanel(controller: controller));
}
return IntrinsicHeight(
@@ -57,19 +39,12 @@ class UploadCsvLayout extends StatelessWidget {
children: [
Expanded(
flex: 3,
child: PanelCard(
child: UploadPanel(
controller: controller,
),
),
child: PanelCard(child: UploadPanel(controller: controller)),
),
const SizedBox(width: 12),
Expanded(
flex: 5,
child: SourceQuotePanel(
controller: controller,
walletsController: walletsController,
),
child: SourceQuotePanel(controller: controller),
),
],
),

View File

@@ -6,7 +6,6 @@ import 'package:pweb/controllers/payouts/multiple_payouts.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/sections/upload_csv/header.dart';
import 'package:pweb/pages/dashboard/payouts/multiple/sections/upload_csv/layout.dart';
class UploadCSVSection extends StatelessWidget {
const UploadCSVSection({super.key});
@@ -22,10 +21,7 @@ class UploadCSVSection extends StatelessWidget {
children: [
UploadCsvHeader(theme: theme),
const SizedBox(height: _verticalSpacing),
UploadCsvLayout(
controller: controller,
walletsController: context.watch(),
),
UploadCsvLayout(controller: controller),
],
);
}