few fixes and made sure ledger widget displays the name of ledger wallet
This commit is contained in:
@@ -1,172 +0,0 @@
|
||||
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<Wallet>? 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<Wallet> wallets,
|
||||
required List<LedgerAccount> 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 = <DropdownMenuItem<_SourceOptionKey>>[
|
||||
...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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:pshared/models/ledger/account.dart';
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
import 'package:pshared/utils/currency.dart';
|
||||
import 'package:pshared/utils/money.dart';
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import 'package:pshared/models/ledger/account.dart';
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
String walletDisplayName(Wallet wallet, AppLocalizations l10n) {
|
||||
return sourceDisplayName(name: wallet.name, fallback: l10n.paymentTypeWallet);
|
||||
}
|
||||
|
||||
String ledgerDisplayName(LedgerAccount ledger, AppLocalizations l10n) {
|
||||
return sourceDisplayName(name: ledger.name, fallback: l10n.paymentTypeLedger);
|
||||
}
|
||||
|
||||
String sourceDisplayName({required String name, required String fallback}) {
|
||||
final normalized = name.trim();
|
||||
if (normalized.isNotEmpty) return normalized;
|
||||
return fallback;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/ledger/account.dart';
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/balance_formatter.dart';
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/display_name.dart';
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/options.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
List<DropdownMenuItem<SourceOptionKey>> buildSourceSelectorItems({
|
||||
required List<Wallet> wallets,
|
||||
required List<LedgerAccount> ledgerAccounts,
|
||||
required AppLocalizations l10n,
|
||||
}) {
|
||||
return <DropdownMenuItem<SourceOptionKey>>[
|
||||
...wallets.map((wallet) {
|
||||
return DropdownMenuItem<SourceOptionKey>(
|
||||
value: walletOptionKey(wallet.id),
|
||||
child: Text(
|
||||
'${walletDisplayName(wallet, l10n)} - ${walletBalance(wallet)}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}),
|
||||
...ledgerAccounts.map((ledger) {
|
||||
return DropdownMenuItem<SourceOptionKey>(
|
||||
value: ledgerOptionKey(ledger.ledgerAccountRef),
|
||||
child: Text(
|
||||
'${ledgerDisplayName(ledger, l10n)} - ${ledgerBalance(ledger)}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}),
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:pshared/controllers/payment/source.dart';
|
||||
import 'package:pshared/models/payment/source_type.dart';
|
||||
|
||||
|
||||
typedef SourceOptionKey = ({PaymentSourceType type, String ref});
|
||||
|
||||
SourceOptionKey walletOptionKey(String walletRef) =>
|
||||
(type: PaymentSourceType.wallet, ref: walletRef);
|
||||
|
||||
SourceOptionKey ledgerOptionKey(String ledgerAccountRef) =>
|
||||
(type: PaymentSourceType.ledger, ref: ledgerAccountRef);
|
||||
|
||||
SourceOptionKey? resolveSelectedSourceOption(PaymentSourceController source) {
|
||||
final selectedWallet = source.selectedWallet;
|
||||
final selectedLedger = source.selectedLedgerAccount;
|
||||
return switch (source.selectedType) {
|
||||
PaymentSourceType.wallet =>
|
||||
selectedWallet == null ? null : walletOptionKey(selectedWallet.id),
|
||||
PaymentSourceType.ledger =>
|
||||
selectedLedger == null
|
||||
? null
|
||||
: ledgerOptionKey(selectedLedger.ledgerAccountRef),
|
||||
null => null,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/ledger/account.dart';
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/dropdown_items.dart';
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/options.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
Widget buildSourceSelectorField({
|
||||
required BuildContext context,
|
||||
required List<Wallet> wallets,
|
||||
required List<LedgerAccount> ledgerAccounts,
|
||||
required SourceOptionKey? selectedValue,
|
||||
required ValueChanged<SourceOptionKey> onChanged,
|
||||
required bool isBusy,
|
||||
}) {
|
||||
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 = buildSourceSelectorItems(
|
||||
wallets: wallets,
|
||||
ledgerAccounts: ledgerAccounts,
|
||||
l10n: l10n,
|
||||
);
|
||||
|
||||
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);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/controllers/payment/source.dart';
|
||||
import 'package:pshared/models/payment/source_type.dart';
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/options.dart';
|
||||
import 'package:pweb/widgets/payment/source_wallet_selector/selector_field.dart';
|
||||
|
||||
|
||||
class SourceWalletSelector extends StatelessWidget {
|
||||
const SourceWalletSelector({
|
||||
super.key,
|
||||
required this.sourceController,
|
||||
this.isBusy = false,
|
||||
this.onChanged,
|
||||
});
|
||||
|
||||
final PaymentSourceController sourceController;
|
||||
final bool isBusy;
|
||||
final ValueChanged<Wallet>? onChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final source = sourceController;
|
||||
|
||||
return buildSourceSelectorField(
|
||||
context: context,
|
||||
wallets: source.wallets,
|
||||
ledgerAccounts: source.ledgerAccounts,
|
||||
selectedValue: resolveSelectedSourceOption(source),
|
||||
onChanged: (value) => _onSourceChanged(source, value),
|
||||
isBusy: isBusy,
|
||||
);
|
||||
}
|
||||
|
||||
void _onSourceChanged(PaymentSourceController source, SourceOptionKey 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user