import 'package:flutter/material.dart'; import 'package:pshared/controllers/payment/source.dart'; import 'package:pshared/models/ledger/account.dart'; import 'package:pshared/models/payment/source_type.dart'; import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/utils/currency.dart'; import 'package:pshared/utils/money.dart'; import 'package:pweb/generated/i18n/app_localizations.dart'; typedef _SourceOptionKey = ({PaymentSourceType type, String ref}); class SourceWalletSelector extends StatelessWidget { const SourceWalletSelector({ super.key, required this.sourceController, this.isBusy = false, this.onChanged, }); final PaymentSourceController sourceController; final bool isBusy; final ValueChanged? onChanged; @override Widget build(BuildContext context) { final source = sourceController; final selectedWallet = source.selectedWallet; final selectedLedger = source.selectedLedgerAccount; final selectedValue = switch (source.selectedType) { PaymentSourceType.wallet => selectedWallet == null ? null : _walletKey(selectedWallet.id), PaymentSourceType.ledger => selectedLedger == null ? null : _ledgerKey(selectedLedger.ledgerAccountRef), null => null, }; return _buildSourceSelector( context: context, wallets: source.wallets, ledgerAccounts: source.ledgerAccounts, selectedValue: selectedValue, onChanged: (value) { if (value.type == PaymentSourceType.wallet) { source.selectWalletByRef(value.ref); final selected = source.selectedWallet; if (selected != null) { onChanged?.call(selected); } return; } if (value.type == PaymentSourceType.ledger) { source.selectLedgerByRef(value.ref); } }, ); } Widget _buildSourceSelector({ required BuildContext context, required List wallets, required List ledgerAccounts, required _SourceOptionKey? selectedValue, required ValueChanged<_SourceOptionKey> onChanged, }) { final theme = Theme.of(context); final l10n = AppLocalizations.of(context)!; if (wallets.isEmpty && ledgerAccounts.isEmpty) { return Text(l10n.noWalletsAvailable, style: theme.textTheme.bodySmall); } final items = >[ ...wallets.map((wallet) { return DropdownMenuItem<_SourceOptionKey>( value: _walletKey(wallet.id), child: Text( '${_walletDisplayName(wallet, l10n)} - ${_walletBalance(wallet)}', overflow: TextOverflow.ellipsis, ), ); }), ...ledgerAccounts.map((ledger) { return DropdownMenuItem<_SourceOptionKey>( value: _ledgerKey(ledger.ledgerAccountRef), child: Text( '${_ledgerDisplayName(ledger, l10n)} - ${_ledgerBalance(ledger)}', overflow: TextOverflow.ellipsis, ), ); }), ]; final knownValues = items .map((item) => item.value) .whereType<_SourceOptionKey>() .toSet(); final effectiveValue = knownValues.contains(selectedValue) ? selectedValue : null; return DropdownButtonFormField<_SourceOptionKey>( initialValue: effectiveValue, isExpanded: true, decoration: InputDecoration( labelText: l10n.whereGetMoney, border: const OutlineInputBorder(), contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10, ), ), items: items, onChanged: isBusy ? null : (value) { if (value == null) return; onChanged(value); }, ); } _SourceOptionKey _walletKey(String walletRef) => (type: PaymentSourceType.wallet, ref: walletRef); _SourceOptionKey _ledgerKey(String ledgerAccountRef) => (type: PaymentSourceType.ledger, ref: ledgerAccountRef); String _walletDisplayName(Wallet wallet, AppLocalizations l10n) { final name = wallet.name.trim(); if (name.isNotEmpty) return name; return l10n.paymentTypeWallet; } String _ledgerDisplayName(LedgerAccount ledger, AppLocalizations l10n) { final name = ledger.name.trim(); if (name.isNotEmpty) return name; return l10n.paymentTypeLedger; } String _walletBalance(Wallet wallet) { final symbol = currencyCodeToSymbol(wallet.currency); return '$symbol ${amountToString(wallet.balance)}'; } String _ledgerBalance(LedgerAccount account) { final money = account.balance?.balance; final rawAmount = money?.amount.trim(); final amount = parseMoneyAmount(rawAmount, fallback: double.nan); final amountText = amount.isNaN ? (rawAmount == null || rawAmount.isEmpty ? '--' : rawAmount) : amountToString(amount); final currencyCode = (money?.currency ?? account.currency) .trim() .toUpperCase(); final symbol = currencySymbolFromCode(currencyCode); if (symbol != null && symbol.trim().isNotEmpty) { return '$symbol $amountText'; } if (currencyCode.isNotEmpty) { return '$amountText $currencyCode'; } return amountText; } }