WIP: integration with ledger

This commit is contained in:
Arseni
2026-02-04 02:01:22 +03:00
parent f1f16a30e6
commit f44ef56ff3
32 changed files with 1226 additions and 405 deletions

View File

@@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/controllers/payment/source.dart';
import 'package:pshared/provider/payment/flow.dart';
import 'package:pshared/provider/payment/provider.dart';
import 'package:pshared/provider/recipient/pmethods.dart';
@@ -45,7 +45,9 @@ class _PaymentPageState extends State<PaymentPage> {
_searchController = TextEditingController();
_searchFocusNode = FocusNode();
WidgetsBinding.instance.addPostFrameCallback((_) => _initializePaymentPage());
WidgetsBinding.instance.addPostFrameCallback(
(_) => _initializePaymentPage(),
);
}
@override
@@ -126,7 +128,7 @@ class _PaymentPageState extends State<PaymentPage> {
searchQuery: _query,
filteredRecipients: filteredRecipients,
methodsProvider: methodsProvider,
onWalletSelected: context.read<WalletsController>().selectWallet,
onSourceSelected: context.read<PaymentSourceController>().selectSource,
searchController: _searchController,
searchFocusNode: _searchFocusNode,
onSearchChanged: _handleSearchChanged,

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/models/payment/source.dart';
import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pshared/provider/recipient/provider.dart';
@@ -11,7 +11,6 @@ import 'package:pweb/pages/payment_methods/payment_page/page.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentPageBody extends StatelessWidget {
final ValueChanged<Recipient?>? onBack;
final Recipient? recipient;
@@ -20,7 +19,7 @@ class PaymentPageBody extends StatelessWidget {
final String searchQuery;
final List<Recipient> filteredRecipients;
final PaymentMethodsProvider methodsProvider;
final ValueChanged<Wallet> onWalletSelected;
final ValueChanged<PaymentSource> onSourceSelected;
final PayoutDestination fallbackDestination;
final TextEditingController searchController;
final FocusNode searchFocusNode;
@@ -38,7 +37,7 @@ class PaymentPageBody extends StatelessWidget {
required this.searchQuery,
required this.filteredRecipients,
required this.methodsProvider,
required this.onWalletSelected,
required this.onSourceSelected,
required this.fallbackDestination,
required this.searchController,
required this.searchFocusNode,
@@ -58,7 +57,9 @@ class PaymentPageBody extends StatelessWidget {
if (methodsProvider.error != null) {
return PaymentMethodsErrorView(
message: loc.notificationError(methodsProvider.error ?? loc.noErrorInformation),
message: loc.notificationError(
methodsProvider.error ?? loc.noErrorInformation,
),
);
}
@@ -69,7 +70,7 @@ class PaymentPageBody extends StatelessWidget {
recipientProvider: recipientProvider,
searchQuery: searchQuery,
filteredRecipients: filteredRecipients,
onWalletSelected: onWalletSelected,
onSourceSelected: onSourceSelected,
fallbackDestination: fallbackDestination,
searchController: searchController,
searchFocusNode: searchFocusNode,

View File

@@ -1,134 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/recipient/provider.dart';
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
import 'package:pweb/pages/payment_methods/payment_page/header.dart';
import 'package:pweb/pages/payment_methods/payment_page/method_selector.dart';
import 'package:pweb/pages/payment_methods/payment_page/send_button.dart';
import 'package:pweb/pages/dashboard/payouts/form.dart';
import 'package:pweb/pages/payment_methods/widgets/payment_info_section.dart';
import 'package:pweb/pages/payment_methods/widgets/recipient_section.dart';
import 'package:pweb/pages/payment_methods/widgets/section_title.dart';
import 'package:pweb/utils/dimensions.dart';
import 'package:pweb/widgets/sidebar/destinations.dart';
import 'package:pweb/widgets/refresh_balance/wallet.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentPageContent extends StatelessWidget {
final ValueChanged<Recipient?>? onBack;
final Recipient? recipient;
final Recipient? previousRecipient;
final RecipientsProvider recipientProvider;
final String searchQuery;
final List<Recipient> filteredRecipients;
final ValueChanged<Wallet> onWalletSelected;
final PayoutDestination fallbackDestination;
final TextEditingController searchController;
final FocusNode searchFocusNode;
final ValueChanged<String> onSearchChanged;
final ValueChanged<Recipient> onRecipientSelected;
final VoidCallback onRecipientCleared;
final VoidCallback onSend;
const PaymentPageContent({
super.key,
required this.onBack,
required this.recipient,
required this.previousRecipient,
required this.recipientProvider,
required this.searchQuery,
required this.filteredRecipients,
required this.onWalletSelected,
required this.fallbackDestination,
required this.searchController,
required this.searchFocusNode,
required this.onSearchChanged,
required this.onRecipientSelected,
required this.onRecipientCleared,
required this.onSend,
});
@override
Widget build(BuildContext context) {
final dimensions = AppDimensions();
final loc = AppLocalizations.of(context)!;
return Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: dimensions.maxContentWidth),
child: Material(
elevation: dimensions.elevationSmall,
borderRadius: BorderRadius.circular(dimensions.borderRadiusMedium),
color: Theme.of(context).colorScheme.onSecondary,
child: Padding(
padding: EdgeInsets.all(dimensions.paddingLarge),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PaymentBackButton(
onBack: onBack,
recipient: recipient,
fallbackDestination: fallbackDestination,
),
SizedBox(height: dimensions.paddingSmall),
PaymentHeader(),
SizedBox(height: dimensions.paddingXXLarge),
Row(
children: [
Expanded(child: SectionTitle(loc.sourceOfFunds)),
Consumer<WalletsController>(
builder: (context, provider, _) {
final selectedWalletId = provider.selectedWallet?.id;
if (selectedWalletId == null) {
return const SizedBox.shrink();
}
return WalletBalanceRefreshButton(walletRef: selectedWalletId);
},
),
],
),
SizedBox(height: dimensions.paddingSmall),
PaymentMethodSelector(
onMethodChanged: onWalletSelected,
),
SizedBox(height: dimensions.paddingXLarge),
RecipientSection(
recipient: recipient,
previousRecipient: previousRecipient,
dimensions: dimensions,
recipientProvider: recipientProvider,
searchQuery: searchQuery,
filteredRecipients: filteredRecipients,
searchController: searchController,
searchFocusNode: searchFocusNode,
onSearchChanged: onSearchChanged,
onRecipientSelected: onRecipientSelected,
onRecipientCleared: onRecipientCleared,
),
SizedBox(height: dimensions.paddingXLarge),
PaymentInfoSection(dimensions: dimensions),
SizedBox(height: dimensions.paddingLarge),
const PaymentFormWidget(),
SizedBox(height: dimensions.paddingXXXLarge),
SendButton(onPressed: onSend),
SizedBox(height: dimensions.paddingLarge),
],
),
),
),
),
),
);
}
}

View File

@@ -2,26 +2,74 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pweb/utils/payment/dropdown.dart';
import 'package:pshared/controllers/payment/source.dart';
import 'package:pshared/models/payment/source.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentMethodSelector extends StatelessWidget {
final ValueChanged<Wallet> onMethodChanged;
final ValueChanged<PaymentSource> onMethodChanged;
const PaymentMethodSelector({
const PaymentMethodSelector({super.key, required this.onMethodChanged});
@override
Widget build(BuildContext context) => Consumer<PaymentSourceController>(
builder: (context, provider, _) => PaymentMethodDropdown(
methods: provider.sources,
selectedMethod: provider.selectedSource,
onChanged: onMethodChanged,
),
);
}
class PaymentMethodDropdown extends StatelessWidget {
final List<PaymentSource> methods;
final ValueChanged<PaymentSource> onChanged;
final PaymentSource? selectedMethod;
const PaymentMethodDropdown({
super.key,
required this.onMethodChanged,
required this.methods,
required this.onChanged,
this.selectedMethod,
});
@override
Widget build(BuildContext context) => Consumer<WalletsController>(
builder: (context, provider, _) => PaymentMethodDropdown(
methods: provider.wallets,
selectedMethod: provider.selectedWallet,
onChanged: onMethodChanged,
),
);
Widget build(BuildContext context) => DropdownButtonFormField<PaymentSource>(
dropdownColor: Theme.of(context).colorScheme.onSecondary,
initialValue: _getSelectedMethod(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.whereGetMoney,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
),
items: methods
.map(
(method) => DropdownMenuItem<PaymentSource>(
value: method,
child: Text(_labelForSource(context, method)),
),
)
.toList(),
onChanged: (value) {
if (value != null) {
onChanged(value);
}
},
);
PaymentSource? _getSelectedMethod() {
if (selectedMethod != null) return selectedMethod;
if (methods.isEmpty) return null;
return methods.first;
}
String _labelForSource(BuildContext context, PaymentSource source) {
final name = source.name.trim();
final loc = AppLocalizations.of(context)!;
if (name.isNotEmpty) return name;
return switch (source.type) {
PaymentSourceType.wallet => loc.paymentTypeManagedWallet,
PaymentSourceType.ledger => loc.paymentTypeLedger,
};
}
}

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/models/payment/source.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/recipient/provider.dart';
@@ -17,7 +17,6 @@ import 'package:pweb/widgets/sidebar/destinations.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentPageContent extends StatelessWidget {
final ValueChanged<Recipient?>? onBack;
final Recipient? recipient;
@@ -25,7 +24,7 @@ class PaymentPageContent extends StatelessWidget {
final RecipientsProvider recipientProvider;
final String searchQuery;
final List<Recipient> filteredRecipients;
final ValueChanged<Wallet> onWalletSelected;
final ValueChanged<PaymentSource> onSourceSelected;
final PayoutDestination fallbackDestination;
final TextEditingController searchController;
final FocusNode searchFocusNode;
@@ -42,7 +41,7 @@ class PaymentPageContent extends StatelessWidget {
required this.recipientProvider,
required this.searchQuery,
required this.filteredRecipients,
required this.onWalletSelected,
required this.onSourceSelected,
required this.fallbackDestination,
required this.searchController,
required this.searchFocusNode,
@@ -56,7 +55,7 @@ class PaymentPageContent extends StatelessWidget {
Widget build(BuildContext context) {
final dimensions = AppDimensions();
final loc = AppLocalizations.of(context)!;
return Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
@@ -82,9 +81,7 @@ class PaymentPageContent extends StatelessWidget {
SizedBox(height: dimensions.paddingXXLarge),
SectionTitle(loc.sourceOfFunds),
SizedBox(height: dimensions.paddingSmall),
PaymentMethodSelector(
onMethodChanged: onWalletSelected,
),
PaymentMethodSelector(onMethodChanged: onSourceSelected),
SizedBox(height: dimensions.paddingXLarge),
RecipientSection(
recipient: recipient,