From 42db4814be7962177c892984bf908868bda44840 Mon Sep 17 00:00:00 2001 From: kolo Date: Fri, 20 Mar 2026 17:38:04 +0300 Subject: [PATCH] update --- lib/features/add_transaction/provider.dart | 14 ++++ lib/features/add_transaction/screen.dart | 93 ++++++++++++++++++++-- lib/features/dashboard/screen.dart | 18 +++++ 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/lib/features/add_transaction/provider.dart b/lib/features/add_transaction/provider.dart index 90e5736..df9bcab 100644 --- a/lib/features/add_transaction/provider.dart +++ b/lib/features/add_transaction/provider.dart @@ -10,6 +10,8 @@ class AddTransactionState { final String note; final bool isSubmitting; final String? editingId; + final String overrideCurrency; + final String overrideCurrencyCode; const AddTransactionState({ this.amount, @@ -19,6 +21,8 @@ class AddTransactionState { this.note = '', this.isSubmitting = false, this.editingId, + this.overrideCurrency = '\$', + this.overrideCurrencyCode = 'USD', }); factory AddTransactionState.fromTransaction(Transaction tx) { @@ -29,6 +33,8 @@ class AddTransactionState { date: tx.date, note: tx.note ?? '', editingId: tx.id, + overrideCurrency: tx.currency, + overrideCurrencyCode: tx.currencyCode, ); } @@ -44,6 +50,8 @@ class AddTransactionState { String? note, bool? isSubmitting, String? editingId, + String? overrideCurrency, + String? overrideCurrencyCode, }) => AddTransactionState( amount: amount ?? this.amount, @@ -53,6 +61,8 @@ class AddTransactionState { note: note ?? this.note, isSubmitting: isSubmitting ?? this.isSubmitting, editingId: editingId ?? this.editingId, + overrideCurrency: overrideCurrency ?? this.overrideCurrency, + overrideCurrencyCode: overrideCurrencyCode ?? this.overrideCurrencyCode, ); bool get isEditing => editingId != null; @@ -80,6 +90,10 @@ class AddTransactionNotifier extends StateNotifier { void setSubmitting(bool v) => state = state.copyWith(isSubmitting: v); + void setCurrency(String symbol, String code) { + state = state.copyWith(overrideCurrency: symbol, overrideCurrencyCode: code); + } + void reset() => state = AddTransactionState.empty(); } diff --git a/lib/features/add_transaction/screen.dart b/lib/features/add_transaction/screen.dart index ddc9cf6..0bdb5fe 100644 --- a/lib/features/add_transaction/screen.dart +++ b/lib/features/add_transaction/screen.dart @@ -39,6 +39,12 @@ class _AddTransactionScreenState extends ConsumerState { if (widget.initial != null) { _amountController.text = widget.initial!.amount.toString(); _noteController.text = widget.initial!.note ?? ''; + } else { + // Set default currency from global provider after first frame + WidgetsBinding.instance.addPostFrameCallback((_) { + final curr = ref.read(currencyProvider); + ref.read(addTransactionProvider(null).notifier).setCurrency(curr.symbol, curr.code); + }); } } @@ -53,7 +59,6 @@ class _AddTransactionScreenState extends ConsumerState { Future _submit() async { if (!_formKey.currentState!.validate()) return; final state = ref.read(addTransactionProvider(widget.initial)); - final currencyInfo = ref.read(currencyProvider); ref.read(addTransactionProvider(widget.initial).notifier).setSubmitting(true); final note = _noteController.text.trim(); @@ -65,8 +70,8 @@ class _AddTransactionScreenState extends ConsumerState { type: state.type, date: state.date, note: note.isEmpty ? null : note, - currency: currencyInfo.symbol, - currencyCode: currencyInfo.code, + currency: state.overrideCurrency, + currencyCode: state.overrideCurrencyCode, ); if (state.isEditing) { @@ -105,7 +110,7 @@ class _AddTransactionScreenState extends ConsumerState { Widget build(BuildContext context) { final state = ref.watch(addTransactionProvider(widget.initial)); final categories = ref.watch(availableCategoriesProvider(widget.initial)); - final currencyInfo = ref.watch(currencyProvider); + final overrideCurrency = state.overrideCurrency; final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( @@ -181,7 +186,7 @@ class _AddTransactionScreenState extends ConsumerState { Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Text( - currencyInfo.symbol, + overrideCurrency, style: TextStyle( fontSize: 20, fontWeight: FontWeight.w600, @@ -226,6 +231,22 @@ class _AddTransactionScreenState extends ConsumerState { ), const SizedBox(height: 20), + // Currency + Text( + 'Currency', + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6), + ), + ), + const SizedBox(height: 8), + _CurrencyPicker( + selected: state.overrideCurrencyCode, + onChanged: (symbol, code) => + ref.read(addTransactionProvider(widget.initial).notifier).setCurrency(symbol, code), + ), + const SizedBox(height: 20), + // Category _SectionLabel('Category'), const SizedBox(height: 8), @@ -484,3 +505,65 @@ class _CategoryPicker extends StatelessWidget { ); } } + +class _CurrencyPicker extends StatelessWidget { + final String selected; + final void Function(String symbol, String code) onChanged; + const _CurrencyPicker({ + required this.selected, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + final currencies = [ + ('USD', '\$'), + ('EUR', '€'), + ('BYN', 'Br'), + ('RUB', '₽'), + ]; + final colorScheme = Theme.of(context).colorScheme; + + return Row( + children: currencies.map((c) { + final isSelected = c.$1 == selected; + return Expanded( + child: GestureDetector( + onTap: () => onChanged(c.$2, c.$1), + child: Container( + margin: EdgeInsets.only(right: c.$1 == currencies.last.$1 ? 0 : 8), + padding: const EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFF7C6DED).withOpacity(0.15) : Theme.of(context).cardColor, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: isSelected ? const Color(0xFF7C6DED) : Colors.transparent, + width: 1.5, + ), + ), + child: Column( + children: [ + Text( + c.$2, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: isSelected ? const Color(0xFF7C6DED) : colorScheme.onSurface, + ), + ), + Text( + c.$1, + style: TextStyle( + fontSize: 10, + color: colorScheme.onSurface.withOpacity(0.5), + ), + ), + ], + ), + ), + ), + ); + }).toList(), + ); + } +} diff --git a/lib/features/dashboard/screen.dart b/lib/features/dashboard/screen.dart index 1ee1da6..e658b40 100644 --- a/lib/features/dashboard/screen.dart +++ b/lib/features/dashboard/screen.dart @@ -195,6 +195,7 @@ class _SearchBar extends StatelessWidget { @override Widget build(BuildContext context) { + final isDark = Theme.of(context).brightness == Brightness.dark; return TextField( controller: controller, focusNode: focusNode, @@ -212,6 +213,23 @@ class _SearchBar extends StatelessWidget { }, ) : null, + filled: true, + fillColor: Theme.of(context).inputDecorationTheme.fillColor, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: isDark ? Colors.transparent : const Color(0xFFCCCCDD), + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: const BorderSide(color: Color(0xFF7C6DED), width: 1.5), + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide.none, + ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), onChanged: (v) => ref.read(searchQueryProvider.notifier).state = v,