This commit is contained in:
2026-03-26 00:57:25 +03:00
parent 71de991587
commit 8ba9ae0b9f
9 changed files with 64 additions and 54 deletions
+9 -1
View File
@@ -127,7 +127,7 @@ class AppCurrencies {
CurrencyOption(symbol: '\$', name: 'US Dollar', code: 'USD'), CurrencyOption(symbol: '\$', name: 'US Dollar', code: 'USD'),
CurrencyOption(symbol: '', name: 'Euro', code: 'EUR'), CurrencyOption(symbol: '', name: 'Euro', code: 'EUR'),
CurrencyOption(symbol: '£', name: 'British Pound', code: 'GBP'), CurrencyOption(symbol: '£', name: 'British Pound', code: 'GBP'),
CurrencyOption(symbol: 'Br', name: 'Belarusian Ruble', code: 'BYN'), CurrencyOption(symbol: '', name: 'Belarusian Ruble', code: 'BYN'),
CurrencyOption(symbol: '', name: 'Russian Ruble', code: 'RUB'), CurrencyOption(symbol: '', name: 'Russian Ruble', code: 'RUB'),
CurrencyOption(symbol: '', name: 'Ukrainian Hryvnia', code: 'UAH'), CurrencyOption(symbol: '', name: 'Ukrainian Hryvnia', code: 'UAH'),
]; ];
@@ -139,3 +139,11 @@ class AppCurrencies {
); );
} }
} }
/// `(code, textSymbol)` for pickers and conversion rows. BYN uses `''` — use BynSign in UI.
const List<(String, String)> kDisplayCurrencies = [
('USD', r'$'),
('EUR', ''),
('BYN', ''),
('RUB', ''),
];
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../core/constants.dart';
import '../../../shared/widgets/byn_sign.dart'; import '../../../shared/widgets/byn_sign.dart';
class CurrencyPicker extends StatelessWidget { class CurrencyPicker extends StatelessWidget {
@@ -13,12 +14,7 @@ class CurrencyPicker extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final currencies = [ final currencies = kDisplayCurrencies;
('USD', '\$'),
('EUR', ''),
('BYN', 'Br'),
('RUB', ''),
];
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
return Row( return Row(
@@ -1,6 +1,7 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../core/constants.dart';
import '../../../../shared/models/account.dart'; import '../../../../shared/models/account.dart';
import '../../../../shared/models/transaction.dart'; import '../../../../shared/models/transaction.dart';
import '../../../../shared/widgets/byn_sign.dart'; import '../../../../shared/widgets/byn_sign.dart';
@@ -281,13 +282,7 @@ class _AccountEditorOverlayState extends State<AccountEditorOverlay> {
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: children: kDisplayCurrencies.map((entry) {
[
('USD', '\$'),
('EUR', ''),
('BYN', 'Br'),
('RUB', ''),
].map((entry) {
final isSelected = entry.$1 == _selectedCurrency; final isSelected = entry.$1 == _selectedCurrency;
return InkWell( return InkWell(
onTap: () { onTap: () {
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../core/constants.dart';
import '../../../../shared/widgets/byn_sign.dart'; import '../../../../shared/widgets/byn_sign.dart';
class AccountEditorPanel extends ConsumerWidget { class AccountEditorPanel extends ConsumerWidget {
@@ -169,12 +170,7 @@ class AccountEditorPanel extends ConsumerWidget {
).colorScheme.onSurface, ).colorScheme.onSurface,
) )
: Text( : Text(
[ kDisplayCurrencies
('USD', '\$'),
('EUR', ''),
('BYN', 'Br'),
('RUB', ''),
]
.firstWhere( .firstWhere(
(c) => c.$1 == selectedCurrency, (c) => c.$1 == selectedCurrency,
) )
@@ -12,8 +12,6 @@ import '../../settings/provider.dart';
import '../provider.dart'; import '../provider.dart';
String _smartBalance(double amount, AmountFormat fmt, String symbol) { String _smartBalance(double amount, AmountFormat fmt, String symbol) {
const spaceAfter = {'Br'};
final sep = spaceAfter.contains(symbol) || symbol.isEmpty ? ' ' : '';
final isWhole = amount == amount.floorToDouble(); final isWhole = amount == amount.floorToDouble();
String formatted; String formatted;
@@ -25,7 +23,7 @@ String _smartBalance(double amount, AmountFormat fmt, String symbol) {
} else { } else {
formatted = fmt.format(amount); formatted = fmt.format(amount);
} }
return symbol.isEmpty ? formatted : '$symbol$sep$formatted'; return symbol.isEmpty ? formatted : '$symbol$formatted';
} }
class BalanceCard extends ConsumerStatefulWidget { class BalanceCard extends ConsumerStatefulWidget {
@@ -139,13 +137,7 @@ class BalanceCardState extends ConsumerState<BalanceCard>
final secondary = widget.previewSecondary ?? savedColors.secondary; final secondary = widget.previewSecondary ?? savedColors.secondary;
final gradientType = widget.previewGradientType ?? savedColors.gradientType; final gradientType = widget.previewGradientType ?? savedColors.gradientType;
final allCurrencies = [ final others = kDisplayCurrencies
('USD', r'$'),
('EUR', ''),
('BYN', 'Br'),
('RUB', ''),
];
final others = allCurrencies
.where((c) => c.$1 != widget.currencyInfo.code) .where((c) => c.$1 != widget.currencyInfo.code)
.toList(); .toList();
@@ -253,7 +245,7 @@ class BalanceCardState extends ConsumerState<BalanceCard>
fontSize: 48, fontSize: 48,
color: onCard, color: onCard,
), ),
const SizedBox(width: 4), const SizedBox(width: 2),
Text( Text(
_smartBalance( _smartBalance(
widget.balance, widget.balance,
+2 -2
View File
@@ -199,7 +199,6 @@ class ExportService {
Future<String> exportToCSV() async { Future<String> exportToCSV() async {
final transactionsAsync = _ref.read(transactionsProvider); final transactionsAsync = _ref.read(transactionsProvider);
final transactions = transactionsAsync.valueOrNull ?? []; final transactions = transactionsAsync.valueOrNull ?? [];
final currency = _ref.read(currencyProvider);
final fmt = _ref.read(amountFormatProvider); final fmt = _ref.read(amountFormatProvider);
final buffer = StringBuffer(); final buffer = StringBuffer();
@@ -209,7 +208,8 @@ class ExportService {
final date = DateFormat('yyyy-MM-dd').format(tx.date); final date = DateFormat('yyyy-MM-dd').format(tx.date);
final type = tx.type.name; final type = tx.type.name;
final category = tx.category; final category = tx.category;
final amount = formatAmount(tx.currency, tx.amount, fmt); final sym = currencyMap[tx.currencyCode]?.symbol ?? '';
final amount = formatAmount(sym, tx.amount, fmt);
final note = tx.note?.replaceAll(',', ';') ?? ''; final note = tx.note?.replaceAll(',', ';') ?? '';
buffer.writeln('$date,$type,$category,$amount,${tx.currencyCode},$note'); buffer.writeln('$date,$type,$category,$amount,${tx.currencyCode},$note');
} }
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/constants.dart'; import '../../../core/constants.dart';
import '../../../core/l10n/locale_provider.dart'; import '../../../core/l10n/locale_provider.dart';
import '../../../shared/providers/amount_format_provider.dart'; import '../../../shared/providers/amount_format_provider.dart';
import '../../../shared/widgets/byn_sign.dart';
import '../provider.dart'; import '../provider.dart';
class AmountFormatSection extends ConsumerWidget { class AmountFormatSection extends ConsumerWidget {
@@ -94,20 +95,45 @@ class AmountFormatSection extends ConsumerWidget {
: FontWeight.w500, : FontWeight.w500,
), ),
), ),
Text( currencyInfo.code == 'BYN'
format.example.replaceFirst( ? Row(
'SYM', mainAxisSize: MainAxisSize.min,
currencyInfo.symbol.isEmpty crossAxisAlignment: CrossAxisAlignment.center,
? 'Br' children: [
: currencyInfo.symbol, BynSign(
), fontSize: 12,
style: TextStyle( color: Theme.of(context)
color: Theme.of( .colorScheme
context, .onSurface
).colorScheme.onSurface.withOpacity(0.6), .withOpacity(0.6),
fontSize: 12, ),
), Text(
), format.example.replaceFirst(
RegExp(r'SYM\s*'),
'',
),
style: TextStyle(
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.6),
fontSize: 12,
),
),
],
)
: Text(
format.example.replaceFirst(
'SYM',
currencyInfo.symbol,
),
style: TextStyle(
color: Theme.of(
context,
).colorScheme.onSurface.withOpacity(0.6),
fontSize: 12,
),
),
], ],
), ),
), ),
+2 -5
View File
@@ -1,10 +1,7 @@
import '../../core/constants.dart'; import '../../core/constants.dart';
String formatAmount(String symbol, double amount, AmountFormat fmt) { String formatAmount(String symbol, double amount, AmountFormat fmt) {
const spaceAfter = {'Br'};
final formatted = fmt.format(amount); final formatted = fmt.format(amount);
// For BYN, symbol is empty string, so we use 'Br' for text-only contexts like CSV if (symbol.isEmpty) return formatted;
final displaySymbol = symbol.isEmpty ? 'Br' : symbol; return '$symbol$formatted';
final sep = spaceAfter.contains(displaySymbol) ? ' ' : '';
return '$displaySymbol$sep$formatted';
} }
+2 -2
View File
@@ -14,9 +14,9 @@ class BynSign extends StatelessWidget {
'\uE901', '\uE901',
style: TextStyle( style: TextStyle(
fontFamily: 'BynSymbol', fontFamily: 'BynSymbol',
fontSize: fontSize, fontSize: fontSize * 1.1,
color: color, color: color,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w900,
height: 1.0, height: 1.0,
), ),
), ),