mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 02:15:29 +03:00
stableee
This commit is contained in:
Binary file not shown.
@@ -388,6 +388,7 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
||||
AmountInput(
|
||||
controller: _amountController,
|
||||
currencySymbol: overrideCurrency,
|
||||
currencyCode: state.overrideCurrencyCode,
|
||||
showError: _showError,
|
||||
borderColorAnimation: _borderColorAnimation,
|
||||
isDark: isDark,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
|
||||
class AmountInput extends StatelessWidget {
|
||||
final TextEditingController controller;
|
||||
final String currencySymbol;
|
||||
final String currencyCode;
|
||||
final bool showError;
|
||||
final Animation<Color?> borderColorAnimation;
|
||||
final bool isDark;
|
||||
@@ -12,6 +14,7 @@ class AmountInput extends StatelessWidget {
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.currencySymbol,
|
||||
required this.currencyCode,
|
||||
required this.showError,
|
||||
required this.borderColorAnimation,
|
||||
required this.isDark,
|
||||
@@ -41,15 +44,22 @@ class AmountInput extends StatelessWidget {
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: Text(
|
||||
currencySymbol,
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.7),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
child: currencyCode == 'BYN'
|
||||
? BynSign(
|
||||
fontSize: 18,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.7),
|
||||
)
|
||||
: Text(
|
||||
currencySymbol,
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.7),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
|
||||
class CurrencyPicker extends StatelessWidget {
|
||||
final String selected;
|
||||
@@ -45,16 +46,23 @@ class CurrencyPicker extends StatelessWidget {
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
c.$2,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected
|
||||
? const Color(0xFF7C6DED)
|
||||
: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
c.$1 == 'BYN'
|
||||
? BynSign(
|
||||
fontSize: 16,
|
||||
color: isSelected
|
||||
? const Color(0xFF7C6DED)
|
||||
: colorScheme.onSurface,
|
||||
)
|
||||
: Text(
|
||||
c.$2,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected
|
||||
? const Color(0xFF7C6DED)
|
||||
: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
c.$1,
|
||||
style: TextStyle(
|
||||
|
||||
@@ -6,6 +6,7 @@ import '../../core/constants.dart';
|
||||
import '../../core/l10n/locale_provider.dart';
|
||||
import '../../shared/utils/currency_utils.dart';
|
||||
import '../../shared/providers/amount_format_provider.dart';
|
||||
import '../../shared/widgets/byn_sign.dart';
|
||||
import '../settings/provider.dart';
|
||||
import 'provider.dart';
|
||||
|
||||
@@ -42,9 +43,9 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
title: Text(
|
||||
s.categories,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
_ChartToggle(
|
||||
@@ -78,7 +79,9 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
border: Border.all(
|
||||
color: !_showIncome
|
||||
? AppColors.accent
|
||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.2),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
@@ -90,7 +93,9 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
fontWeight: FontWeight.w600,
|
||||
color: !_showIncome
|
||||
? Colors.white
|
||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -113,7 +118,9 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
border: Border.all(
|
||||
color: _showIncome
|
||||
? AppColors.accent
|
||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.2),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
@@ -125,7 +132,9 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _showIncome
|
||||
? Colors.white
|
||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -149,11 +158,15 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
currency: currencyInfo.symbol,
|
||||
)
|
||||
else
|
||||
_BarChartCard(monthlyData: monthlyData, currency: currencyInfo.symbol),
|
||||
_BarChartCard(
|
||||
monthlyData: monthlyData,
|
||||
currency: currencyInfo.symbol,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
s.rankedByAmount,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
style: Theme.of(context).textTheme.titleMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
@@ -235,12 +248,16 @@ class _ToggleButton extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AppColors.accent.withOpacity(0.15) : Colors.transparent,
|
||||
color: isSelected
|
||||
? AppColors.accent.withOpacity(0.15)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: isSelected ? AppColors.accent : Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
color: isSelected
|
||||
? AppColors.accent
|
||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
@@ -301,7 +318,8 @@ class _PieChartCard extends ConsumerWidget {
|
||||
final isTouched = i == touchedIndex;
|
||||
final cat = entries[i].key;
|
||||
final val = entries[i].value;
|
||||
final color = AppCategories.colors[cat] ?? AppColors.accent;
|
||||
final color =
|
||||
AppCategories.colors[cat] ?? AppColors.accent;
|
||||
return PieChartSectionData(
|
||||
color: color,
|
||||
value: val,
|
||||
@@ -324,15 +342,17 @@ class _PieChartCard extends ConsumerWidget {
|
||||
Text(
|
||||
s.total,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatAmount(currency, total, fmt),
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -354,7 +374,9 @@ class _BarChartCard extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final s = ref.watch(stringsProvider);
|
||||
final fmt = ref.watch(amountFormatProvider);
|
||||
final maxY = monthlyData.map((e) => e.amount).reduce((a, b) => a > b ? a : b);
|
||||
final maxY = monthlyData
|
||||
.map((e) => e.amount)
|
||||
.reduce((a, b) => a > b ? a : b);
|
||||
final adjustedMaxY = maxY * 1.2;
|
||||
|
||||
return Container(
|
||||
@@ -369,9 +391,9 @@ class _BarChartCard extends ConsumerWidget {
|
||||
Text(
|
||||
s.lastSixMonths,
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SizedBox(
|
||||
@@ -400,14 +422,17 @@ class _BarChartCard extends ConsumerWidget {
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
if (value.toInt() >= 0 && value.toInt() < monthlyData.length) {
|
||||
if (value.toInt() >= 0 &&
|
||||
value.toInt() < monthlyData.length) {
|
||||
final month = monthlyData[value.toInt()].month;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
DateFormat('MMM').format(month),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
@@ -501,15 +526,21 @@ class _CategoryRow extends ConsumerWidget {
|
||||
height: 28,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: rank <= 3 ? color.withOpacity(0.2) : Theme.of(context).dividerColor,
|
||||
color: rank <= 3
|
||||
? color.withOpacity(0.2)
|
||||
: Theme.of(context).dividerColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text(
|
||||
'$rank',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: rank <= 3 ? color : Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
color: rank <= 3
|
||||
? color
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
@@ -526,9 +557,9 @@ class _CategoryRow extends ConsumerWidget {
|
||||
child: Text(
|
||||
s.categoryLabel(category),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
@@ -537,15 +568,17 @@ class _CategoryRow extends ConsumerWidget {
|
||||
Text(
|
||||
formatAmount(currency, amount, fmt),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: isIncome ? AppColors.income : AppColors.expense,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
color: isIncome ? AppColors.income : AppColors.expense,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${(pct * 100).toStringAsFixed(1)}%',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -594,16 +627,16 @@ class _EmptyState extends ConsumerWidget {
|
||||
Text(
|
||||
isIncome ? s.noIncomeData : s.noExpenseData,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
isIncome ? s.addIncomeToSeeBreakdown : s.addExpensesToSeeBreakdown,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../../../shared/models/account.dart';
|
||||
import '../../../../shared/models/transaction.dart';
|
||||
import '../../../../shared/widgets/byn_sign.dart';
|
||||
import '../../../settings/provider.dart';
|
||||
import '../../provider.dart';
|
||||
import '../balance_card.dart';
|
||||
@@ -308,16 +309,25 @@ class _AccountEditorOverlayState extends State<AccountEditorOverlay> {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
entry.$2,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected
|
||||
? const Color(0xFF7C6DED)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
entry.$1 == 'BYN'
|
||||
? BynSign(
|
||||
fontSize: 14,
|
||||
color: isSelected
|
||||
? const Color(0xFF7C6DED)
|
||||
: Theme.of(
|
||||
widget.context,
|
||||
).colorScheme.onSurface,
|
||||
)
|
||||
: Text(
|
||||
entry.$2,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected
|
||||
? const Color(0xFF7C6DED)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
child: Text(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../../../shared/widgets/byn_sign.dart';
|
||||
|
||||
class AccountEditorPanel extends ConsumerWidget {
|
||||
final TextEditingController nameController;
|
||||
@@ -160,18 +161,29 @@ class AccountEditorPanel extends ConsumerWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
[
|
||||
('USD', '\$'),
|
||||
('EUR', '€'),
|
||||
('BYN', 'Br'),
|
||||
('RUB', '₽'),
|
||||
].firstWhere((c) => c.$1 == selectedCurrency).$2,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
selectedCurrency == 'BYN'
|
||||
? BynSign(
|
||||
fontSize: 15,
|
||||
color: Theme.of(
|
||||
dashboardContext,
|
||||
).colorScheme.onSurface,
|
||||
)
|
||||
: Text(
|
||||
[
|
||||
('USD', '\$'),
|
||||
('EUR', '€'),
|
||||
('BYN', 'Br'),
|
||||
('RUB', '₽'),
|
||||
]
|
||||
.firstWhere(
|
||||
(c) => c.$1 == selectedCurrency,
|
||||
)
|
||||
.$2,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
showCurrencyDropdown
|
||||
|
||||
@@ -7,12 +7,13 @@ import '../../../core/l10n/locale_provider.dart';
|
||||
import '../../../core/services/card_color_service.dart';
|
||||
import '../../../core/services/haptic_service.dart';
|
||||
import '../../../shared/providers/amount_format_provider.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
import '../../settings/provider.dart';
|
||||
import '../provider.dart';
|
||||
|
||||
String _smartBalance(double amount, AmountFormat fmt, String symbol) {
|
||||
const spaceAfter = {'Br'};
|
||||
final sep = spaceAfter.contains(symbol) ? ' ' : '';
|
||||
final sep = spaceAfter.contains(symbol) || symbol.isEmpty ? ' ' : '';
|
||||
final isWhole = amount == amount.floorToDouble();
|
||||
|
||||
String formatted;
|
||||
@@ -24,7 +25,7 @@ String _smartBalance(double amount, AmountFormat fmt, String symbol) {
|
||||
} else {
|
||||
formatted = fmt.format(amount);
|
||||
}
|
||||
return '$symbol$sep$formatted';
|
||||
return symbol.isEmpty ? formatted : '$symbol$sep$formatted';
|
||||
}
|
||||
|
||||
class BalanceCard extends ConsumerStatefulWidget {
|
||||
@@ -242,19 +243,45 @@ class BalanceCardState extends ConsumerState<BalanceCard>
|
||||
FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
_smartBalance(
|
||||
widget.balance,
|
||||
fmt,
|
||||
widget.currencyInfo.symbol,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: onCard,
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
child: widget.currencyInfo.code == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: [
|
||||
BynSign(
|
||||
fontSize: 48,
|
||||
color: onCard,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_smartBalance(
|
||||
widget.balance,
|
||||
fmt,
|
||||
'',
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: onCard,
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
_smartBalance(
|
||||
widget.balance,
|
||||
fmt,
|
||||
widget.currencyInfo.symbol,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: onCard,
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -285,15 +312,49 @@ class BalanceCardState extends ConsumerState<BalanceCard>
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
_smartBalance(converted, fmt, c.$2),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: onCard.withOpacity(0.65),
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
child: c.$1 == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: [
|
||||
BynSign(
|
||||
fontSize: 14,
|
||||
color: onCard.withOpacity(
|
||||
0.65,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
_smartBalance(
|
||||
converted,
|
||||
fmt,
|
||||
'',
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: onCard.withOpacity(
|
||||
0.65,
|
||||
),
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
_smartBalance(
|
||||
converted,
|
||||
fmt,
|
||||
c.$2,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: onCard.withOpacity(0.65),
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../../core/l10n/app_strings.dart';
|
||||
import '../../../shared/providers/amount_format_provider.dart';
|
||||
import '../../../shared/utils/currency_utils.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
import '../../settings/provider.dart';
|
||||
|
||||
class BudgetProgress extends ConsumerWidget {
|
||||
@@ -96,22 +97,86 @@ class BudgetProgress extends ConsumerWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${strings.spent}: ${formatAmount(currencyInfo.symbol, spent, fmt)}',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${strings.limit}: ${formatAmount(currencyInfo.symbol, budget, fmt)}',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
currencyInfo.code == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'${strings.spent}: ',
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
BynSign(
|
||||
fontSize: 12,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
formatAmount('', spent, fmt),
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
'${strings.spent}: ${formatAmount(currencyInfo.symbol, spent, fmt)}',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
currencyInfo.code == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'${strings.limit}: ',
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
BynSign(
|
||||
fontSize: 12,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
formatAmount('', budget, fmt),
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
'${strings.limit}: ${formatAmount(currencyInfo.symbol, budget, fmt)}',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -4,6 +4,7 @@ import '../../../core/constants.dart';
|
||||
import '../../../core/l10n/app_strings.dart';
|
||||
import '../../../shared/providers/amount_format_provider.dart';
|
||||
import '../../../shared/utils/currency_utils.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
import '../../settings/provider.dart';
|
||||
|
||||
class SummaryRow extends StatelessWidget {
|
||||
@@ -104,14 +105,34 @@ class SummaryCard extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
formatAmount(currencyInfo.symbol, amount, fmt),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
currencyInfo.code == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
BynSign(fontSize: 14, color: color),
|
||||
const SizedBox(width: 2),
|
||||
Flexible(
|
||||
child: Text(
|
||||
formatAmount('', amount, fmt),
|
||||
style: Theme.of(context).textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
formatAmount(currencyInfo.symbol, amount, fmt),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -9,6 +9,7 @@ import '../../../core/l10n/locale_provider.dart';
|
||||
import '../../../shared/models/transaction.dart';
|
||||
import '../../../shared/providers/amount_format_provider.dart';
|
||||
import '../../../shared/utils/currency_utils.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
import '../provider.dart';
|
||||
|
||||
class TransactionTile extends ConsumerWidget {
|
||||
@@ -117,13 +118,36 @@ class TransactionTile extends ConsumerWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${isIncome ? '+ ' : '- '}${formatAmount(transaction.currency, transaction.amount, fmt)}',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
transaction.currencyCode == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
isIncome ? '+ ' : '- ',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
BynSign(fontSize: 14, color: color),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
formatAmount('', transaction.amount, fmt),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
'${isIncome ? '+ ' : '- '}${formatAmount(transaction.currency, transaction.amount, fmt)}',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -46,7 +46,7 @@ class CurrencyInfo {
|
||||
const Map<String, CurrencyInfo> currencyMap = {
|
||||
'USD': CurrencyInfo('\$', 'USD'),
|
||||
'EUR': CurrencyInfo('€', 'EUR'),
|
||||
'BYN': CurrencyInfo('Br', 'BYN'),
|
||||
'BYN': CurrencyInfo('', 'BYN'),
|
||||
'RUB': CurrencyInfo('₽', 'RUB'),
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ class AmountFormatSection extends ConsumerWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||
border: isDark
|
||||
? null
|
||||
: Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -44,9 +46,9 @@ class AmountFormatSection extends ConsumerWidget {
|
||||
child: Text(
|
||||
s.amountFormat,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -57,9 +59,13 @@ class AmountFormatSection extends ConsumerWidget {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: GestureDetector(
|
||||
onTap: () => ref.read(amountFormatProvider.notifier).set(format),
|
||||
onTap: () =>
|
||||
ref.read(amountFormatProvider.notifier).set(format),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? AppColors.accent.withOpacity(0.2)
|
||||
@@ -67,7 +73,12 @@ class AmountFormatSection extends ConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: isSelected
|
||||
? Border.all(color: AppColors.accent, width: 1.5)
|
||||
: (isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1)),
|
||||
: (isDark
|
||||
? null
|
||||
: Border.all(
|
||||
color: const Color(0xFFDDDDEE),
|
||||
width: 1,
|
||||
)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -75,14 +86,25 @@ class AmountFormatSection extends ConsumerWidget {
|
||||
Text(
|
||||
format.label,
|
||||
style: TextStyle(
|
||||
color: isSelected ? AppColors.accent : Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
|
||||
color: isSelected
|
||||
? AppColors.accent
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w600
|
||||
: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
format.example.replaceFirst('SYM', currencyInfo.symbol),
|
||||
format.example.replaceFirst(
|
||||
'SYM',
|
||||
currencyInfo.symbol.isEmpty
|
||||
? 'Br'
|
||||
: currencyInfo.symbol,
|
||||
),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,6 +5,7 @@ import '../../../core/constants.dart';
|
||||
import '../../../core/l10n/locale_provider.dart';
|
||||
import '../../../shared/providers/amount_format_provider.dart';
|
||||
import '../../../shared/utils/currency_utils.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
import '../provider.dart';
|
||||
|
||||
class BudgetSection extends ConsumerStatefulWidget {
|
||||
@@ -59,7 +60,9 @@ class _BudgetSectionState extends ConsumerState<BudgetSection> {
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||
border: isDark
|
||||
? null
|
||||
: Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -83,15 +86,17 @@ class _BudgetSectionState extends ConsumerState<BudgetSection> {
|
||||
child: Text(
|
||||
s.monthlyBudgetSetting,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!_isEditing)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit_rounded, size: 20),
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
onPressed: () => setState(() => _isEditing = true),
|
||||
),
|
||||
],
|
||||
@@ -103,14 +108,32 @@ class _BudgetSectionState extends ConsumerState<BudgetSection> {
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _budgetController,
|
||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true,
|
||||
),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
|
||||
FilteringTextInputFormatter.allow(
|
||||
RegExp(r'^\d+\.?\d{0,2}'),
|
||||
),
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
prefixText: currencyInfo.symbol == 'Br' || currencyInfo.symbol == '₽'
|
||||
? '${currencyInfo.symbol} '
|
||||
: currencyInfo.symbol,
|
||||
prefix: currencyInfo.code == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
BynSign(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
prefixText: currencyInfo.code != 'BYN'
|
||||
? (currencyInfo.symbol == '₽'
|
||||
? '${currencyInfo.symbol} '
|
||||
: currencyInfo.symbol)
|
||||
: null,
|
||||
hintText: '0.00',
|
||||
helperText: s.leaveEmptyToRemove,
|
||||
),
|
||||
@@ -123,7 +146,8 @@ class _BudgetSectionState extends ConsumerState<BudgetSection> {
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
final budget = ref.read(budgetProvider);
|
||||
_budgetController.text = budget?.toStringAsFixed(2) ?? '';
|
||||
_budgetController.text =
|
||||
budget?.toStringAsFixed(2) ?? '';
|
||||
setState(() => _isEditing = false);
|
||||
},
|
||||
child: Text(s.cancel),
|
||||
@@ -144,23 +168,47 @@ class _BudgetSectionState extends ConsumerState<BudgetSection> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
budget != null
|
||||
? formatAmount(currencyInfo.symbol, budget, fmt)
|
||||
: s.budgetNone,
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
color: budget != null ? AppColors.accent : Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w700,
|
||||
budget != null && currencyInfo.code == 'BYN'
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
BynSign(fontSize: 24, color: AppColors.accent),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
formatAmount('', budget, fmt),
|
||||
style: Theme.of(context).textTheme.headlineSmall
|
||||
?.copyWith(
|
||||
color: AppColors.accent,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
budget != null
|
||||
? formatAmount(currencyInfo.symbol, budget, fmt)
|
||||
: s.budgetNone,
|
||||
style: Theme.of(context).textTheme.headlineSmall
|
||||
?.copyWith(
|
||||
color: budget != null
|
||||
? AppColors.accent
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
budget != null
|
||||
? s.yourMonthlySpendingLimit
|
||||
: s.setMonthlySpendingLimit,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../../core/constants.dart';
|
||||
import '../../../core/l10n/locale_provider.dart';
|
||||
import '../../../shared/widgets/byn_sign.dart';
|
||||
import '../provider.dart';
|
||||
|
||||
class CurrencySection extends ConsumerWidget {
|
||||
@@ -18,7 +19,9 @@ class CurrencySection extends ConsumerWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||
border: isDark
|
||||
? null
|
||||
: Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -42,9 +45,9 @@ class CurrencySection extends ConsumerWidget {
|
||||
child: Text(
|
||||
s.currency,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -61,7 +64,9 @@ class CurrencySection extends ConsumerWidget {
|
||||
onTap: () {
|
||||
final oldCode = ref.read(currencyProvider).code;
|
||||
final rates = ref.read(exchangeRateServiceProvider);
|
||||
ref.read(budgetProvider.notifier).onCurrencyChanged(oldCode, code, rates);
|
||||
ref
|
||||
.read(budgetProvider.notifier)
|
||||
.onCurrencyChanged(oldCode, code, rates);
|
||||
ref.read(currencyProvider.notifier).setCurrency(code);
|
||||
},
|
||||
child: Container(
|
||||
@@ -71,25 +76,52 @@ class CurrencySection extends ConsumerWidget {
|
||||
? AppColors.accent.withOpacity(0.2)
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: isSelected
|
||||
border: isSelected
|
||||
? Border.all(color: AppColors.accent, width: 1.5)
|
||||
: (isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1)),
|
||||
: (isDark
|
||||
? null
|
||||
: Border.all(
|
||||
color: const Color(0xFFDDDDEE),
|
||||
width: 1,
|
||||
)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
info.symbol,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: isSelected ? AppColors.accent : Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: isSelected ? FontWeight.w700 : FontWeight.normal,
|
||||
code == 'BYN'
|
||||
? BynSign(
|
||||
fontSize: 28,
|
||||
color: isSelected
|
||||
? AppColors.accent
|
||||
: Theme.of(context).colorScheme.onSurface
|
||||
.withOpacity(0.6),
|
||||
)
|
||||
: Text(
|
||||
info.symbol,
|
||||
style: Theme.of(context).textTheme.titleLarge
|
||||
?.copyWith(
|
||||
color: isSelected
|
||||
? AppColors.accent
|
||||
: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.6),
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w700
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
code,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: isSelected ? AppColors.accent : Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: isSelected
|
||||
? AppColors.accent
|
||||
: Theme.of(context).colorScheme.onSurface
|
||||
.withOpacity(0.6),
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w600
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -3,6 +3,8 @@ import '../../core/constants.dart';
|
||||
String formatAmount(String symbol, double amount, AmountFormat fmt) {
|
||||
const spaceAfter = {'Br'};
|
||||
final formatted = fmt.format(amount);
|
||||
final sep = spaceAfter.contains(symbol) ? ' ' : '';
|
||||
return '$symbol$sep$formatted';
|
||||
// For BYN, symbol is empty string, so we use 'Br' for text-only contexts like CSV
|
||||
final displaySymbol = symbol.isEmpty ? 'Br' : symbol;
|
||||
final sep = spaceAfter.contains(displaySymbol) ? ' ' : '';
|
||||
return '$displaySymbol$sep$formatted';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BynSign extends StatelessWidget {
|
||||
final double fontSize;
|
||||
final Color color;
|
||||
|
||||
const BynSign({super.key, required this.fontSize, required this.color});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Transform.translate(
|
||||
offset: Offset(0, fontSize * -0.12),
|
||||
child: Text(
|
||||
'\uE901',
|
||||
style: TextStyle(
|
||||
fontFamily: 'BynSymbol',
|
||||
fontSize: fontSize,
|
||||
color: color,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,9 @@ dev_dependencies:
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
fonts:
|
||||
- family: BynSymbol
|
||||
fonts:
|
||||
- asset: assets/fonts/nbrb.ttf
|
||||
- family: NunitoCyrillic
|
||||
fonts:
|
||||
- asset: assets/fonts/nunito/Nunito-Medium.ttf
|
||||
|
||||
Reference in New Issue
Block a user