From 83160c716b1deec35c56e33ab2d801dca387dba6 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Sun, 13 Aug 2023 12:49:09 +0200 Subject: [PATCH 01/14] Create AccountPage to replace the account modal --- lib/custom_widgets/accounts_sum.dart | 69 ++++++++----------- lib/pages/account_page/account_page.dart | 84 ++++++++++++++++++++++++ lib/routes.dart | 18 +++-- 3 files changed, 124 insertions(+), 47 deletions(-) create mode 100644 lib/pages/account_page/account_page.dart diff --git a/lib/custom_widgets/accounts_sum.dart b/lib/custom_widgets/accounts_sum.dart index b5bb177..fc43f19 100644 --- a/lib/custom_widgets/accounts_sum.dart +++ b/lib/custom_widgets/accounts_sum.dart @@ -1,13 +1,15 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../constants/constants.dart'; import '../model/bank_account.dart'; import '../constants/functions.dart'; import '../constants/style.dart'; -import 'account_modal.dart'; +import '../../../providers/accounts_provider.dart'; /// This class shows account summaries in the dashboard -class AccountsSum extends StatelessWidget with Functions { +class AccountsSum extends ConsumerWidget with Functions { final BankAccount account; const AccountsSum({ @@ -16,7 +18,7 @@ class AccountsSum extends StatelessWidget with Functions { }) : super(key: key); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return Container( width: 160.0, margin: const EdgeInsets.fromLTRB(0, 4, 16, 6), @@ -34,35 +36,12 @@ class AccountsSum extends StatelessWidget with Functions { color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(8), - onTap: () { - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - isScrollControlled: true, - isDismissible: true, - builder: (BuildContext buildContext) { - return DraggableScrollableSheet( - builder: (_, controller) => Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - color: const Color(0xff356CA3), - ), - child: ListView( - controller: controller, - children: [ - AccountDialog( - accountName: account.name, - amount: account.startingValue, - ) - ], - ), - ), - initialChildSize: 0.7, - minChildSize: 0.5, - maxChildSize: 1, - ); - }, - ); + onTap: () async { + await ref + .read(accountsProvider.notifier) + .selectedAccount(account) + .whenComplete( + () => Navigator.of(context).pushNamed('/account')); }, child: Container( padding: const EdgeInsets.fromLTRB(12, 8, 12, 8), @@ -76,22 +55,25 @@ class AccountsSum extends StatelessWidget with Functions { ), child: Padding( padding: const EdgeInsets.all(6.0), - child: Icon(accountIconList[account.symbol], size: 20.0, color: white), + child: Icon(accountIconList[account.symbol], + size: 20.0, color: white), ), ), Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text(account.name, style: Theme.of(context).textTheme.bodyLarge), + Text(account.name, + style: Theme.of(context).textTheme.bodyLarge), FutureBuilder( future: BankAccountMethods().getAccountSum(account.id), builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { + if (snapshot.connectionState == + ConnectionState.waiting) { // Show a loading indicator while waiting for the future to complete return Transform.scale( scale: 0.5, - child: CircularProgressIndicator(), + child: const CircularProgressIndicator(), ); } else if (snapshot.hasError) { // Show an error message if the future encounters an error @@ -100,17 +82,24 @@ class AccountsSum extends StatelessWidget with Functions { // Display the result once the future completes successfully final accountSum = snapshot.data ?? 0; return RichText( - textScaleFactor: MediaQuery.of(context).textScaleFactor, + textScaleFactor: + MediaQuery.of(context).textScaleFactor, text: TextSpan( children: [ TextSpan( text: numToCurrency(accountSum), - style: Theme.of(context).textTheme.titleSmall, + style: + Theme.of(context).textTheme.titleSmall, ), TextSpan( text: "€", - style: Theme.of(context).textTheme.bodyMedium?.apply( - fontFeatures: [const FontFeature.subscripts()], + style: Theme.of(context) + .textTheme + .bodyMedium + ?.apply( + fontFeatures: [ + const FontFeature.subscripts() + ], ), ), ], diff --git a/lib/pages/account_page/account_page.dart b/lib/pages/account_page/account_page.dart new file mode 100644 index 0000000..4aca2a9 --- /dev/null +++ b/lib/pages/account_page/account_page.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:fl_chart/fl_chart.dart'; + +import '../../providers/accounts_provider.dart'; +import '../../custom_widgets/line_chart.dart'; +import '../../constants/functions.dart'; +import '../../constants/style.dart'; + +class AccountPage extends ConsumerStatefulWidget { + const AccountPage({Key? key}) : super(key: key); + + @override + ConsumerState createState() => _AccountPage(); +} + +class _AccountPage extends ConsumerState with Functions { + @override + Widget build(BuildContext context) { + final accountName = ref.read(accountNameProvider); + final accountAmount = ref.read(accountStartingValueProvider); + + return Scaffold( + appBar: AppBar( + title: Text(accountName ?? "", style: const TextStyle(color: white)), + backgroundColor: blue5, + elevation: 0, + ), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + padding: const EdgeInsets.symmetric(vertical: 12.0), + color: blue5, + child: Column( + children: [ + Text( + numToCurrency(accountAmount), + style: const TextStyle( + color: white, + fontSize: 32.0, + fontFamily: 'SF Pro Text', + fontWeight: FontWeight.bold, + ), + ), + const Padding(padding: EdgeInsets.all(8.0)), + const LineChartWidget( + line1Data: [ + FlSpot(0, 3), + FlSpot(1, 1.3), + FlSpot(2, -2), + FlSpot(3, -4.5), + FlSpot(4, -5), + FlSpot(5, -2.2), + FlSpot(6, -3.1), + FlSpot(7, -0.2), + FlSpot(8, -4), + FlSpot(9, -3), + FlSpot(10, -2), + FlSpot(11, -4), + FlSpot(12, 3), + FlSpot(13, 1.3), + FlSpot(14, -2), + FlSpot(15, -4.5), + FlSpot(16, 2.5), + ], + colorLine1Data: Color(0xffffffff), + line2Data: [], + colorLine2Data: Color(0xffffffff), + colorBackground: blue5, + maxY: 5.0, + minY: -5.0, + maxDays: 30.0, + ), + ], + ), + ), + // TODO: add list of transactions + ], + ), + ), + ); + } +} diff --git a/lib/routes.dart b/lib/routes.dart index bf1c16c..8d24eba 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,18 +1,20 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'pages/categories/category_list.dart'; -import 'pages/general_options/general_settings.dart'; -import 'pages/more_info_page/collaborators_page.dart'; -import 'pages/more_info_page/more_info.dart'; -import 'pages/more_info_page/privacy_policy.dart'; + +import 'pages/account_page/account_page.dart'; import 'pages/accounts/account_list.dart'; -import 'pages/categories/add_category.dart'; import 'pages/accounts/add_account.dart'; import 'pages/add_page/widgets/recurrence_selector.dart'; import 'pages/add_page/widgets/account_selector.dart'; import 'pages/add_page/widgets/category_selector.dart'; +import 'pages/categories/add_category.dart'; +import 'pages/categories/category_list.dart'; import 'pages/home_page.dart'; +import 'pages/general_options/general_settings.dart'; +import 'pages/more_info_page/collaborators_page.dart'; +import 'pages/more_info_page/more_info.dart'; +import 'pages/more_info_page/privacy_policy.dart'; import 'pages/planning_page/planning_page.dart'; import 'pages/settings_page.dart'; import 'pages/statistics_page.dart'; @@ -26,7 +28,7 @@ Route makeRoute(RouteSettings settings) { case '/dashboard': return _materialPageRoute(settings.name, const HomePage()); case '/transactions': - return _materialPageRoute(settings.name, TransactionsPage()); + return _materialPageRoute(settings.name, const TransactionsPage()); case '/categoryselect': return _cupertinoPageRoute(settings.name, const CategorySelector()); case '/category-list': @@ -39,6 +41,8 @@ Route makeRoute(RouteSettings settings) { return _cupertinoPageRoute(settings.name, const PrivacyPolicyPage()); case '/collaborators': return _cupertinoPageRoute(settings.name, const CollaboratorsPage()); + case '/account': + return _materialPageRoute(settings.name, const AccountPage()); case '/account-list': return _cupertinoPageRoute(settings.name, const AccountList()); case '/add-account': From 9d5062039ae02414843907175c45c0d6c1de5e07 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Tue, 15 Aug 2023 10:53:34 +0200 Subject: [PATCH 02/14] Improve ListTab and TransactionListTile Diplay icon background color based on category. Show amount in the correct color based on type. Totals of the day consider only income and expenses. --- .../transactions_page/widgets/list_tab.dart | 45 ++++++++++++++----- .../widgets/transaction_list_tile.dart | 14 +++--- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/lib/pages/transactions_page/widgets/list_tab.dart b/lib/pages/transactions_page/widgets/list_tab.dart index 4d2d46a..aae650a 100644 --- a/lib/pages/transactions_page/widgets/list_tab.dart +++ b/lib/pages/transactions_page/widgets/list_tab.dart @@ -34,9 +34,17 @@ class _ListTabState extends ConsumerState with Functions { for (var t in transactions.value!) { String date = t.date.toYMD(); if (totals.containsKey(date)) { - totals[date] = totals[date]! + t.amount.toDouble(); + if (t.type == Type.expense) { + totals[date] = totals[date]! - t.amount.toDouble(); + } else if (t.type == Type.income) { + totals[date] = totals[date]! + t.amount.toDouble(); + } } else { - totals.putIfAbsent(date, () => t.amount.toDouble()); + if (t.type == Type.expense) { + totals.putIfAbsent(date, () => -t.amount.toDouble()); + } else if (t.type == Type.income) { + totals.putIfAbsent(date, () => t.amount.toDouble()); + } } } } @@ -64,16 +72,33 @@ class _ListTabState extends ConsumerState with Functions { .where((e) => e.id == transaction.idCategory) : []; + String account = accounts.value! + .firstWhere((e) => e.id == transaction.idBankAccount) + .name; + + // account the money is moved to in a trasfer + String targetAccount = (transaction.type == Type.transfer) + ? accounts.value! + .firstWhere( + (element) => + element.id == transaction.idBankAccountTransfer, + ) + .name + : ""; + return TransactionListTile( - title: transaction.note ?? "Title", + title: transaction.note ?? "", + type: transaction.type, amount: transaction.amount.toDouble(), - account: accounts.value! - .firstWhere((e) => e.id == transaction.idBankAccount) - .name, + account: (transaction.type == Type.transfer) + ? "$account → $targetAccount" + : account, category: (tCategories.isNotEmpty) ? tCategories.first.name - : "not found", - color: Colors.red, + : "no category", + color: (tCategories.isNotEmpty) + ? categoryColorList[tCategories.first.color] + : blue3, icon: (tCategories.isNotEmpty) ? iconList[tCategories.first.symbol] ?? Icons.swap_horiz_rounded @@ -118,7 +143,7 @@ class _ListTabState extends ConsumerState with Functions { } } -class DateSeparator extends StatelessWidget { +class DateSeparator extends StatelessWidget with Functions { const DateSeparator({ Key? key, required this.transaction, @@ -141,7 +166,7 @@ class DateSeparator extends StatelessWidget { Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1), ), Text( - "${total.toStringAsFixed(2)} €", + "${numToCurrency(total)} €", style: Theme.of(context) .textTheme .bodyLarge diff --git a/lib/pages/transactions_page/widgets/transaction_list_tile.dart b/lib/pages/transactions_page/widgets/transaction_list_tile.dart index 5552eb2..ea26c86 100644 --- a/lib/pages/transactions_page/widgets/transaction_list_tile.dart +++ b/lib/pages/transactions_page/widgets/transaction_list_tile.dart @@ -1,11 +1,14 @@ import "package:flutter/material.dart"; import '../../../constants/style.dart'; +import '../../../constants/functions.dart'; +import '../../../model/transaction.dart'; -class TransactionListTile extends StatelessWidget { +class TransactionListTile extends StatelessWidget with Functions { const TransactionListTile({ Key? key, required this.title, + required this.type, required this.amount, required this.color, required this.category, @@ -14,6 +17,7 @@ class TransactionListTile extends StatelessWidget { }) : super(key: key); final String title; + final Type type; final double amount; final Color color; final String category; @@ -23,7 +27,7 @@ class TransactionListTile extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - color: Colors.white, + color: white, padding: const EdgeInsets.symmetric( horizontal: 8.0, vertical: 12.0, @@ -37,7 +41,7 @@ class TransactionListTile extends StatelessWidget { shape: BoxShape.circle, color: color, ), - child: Icon(icon), + child: Icon(icon, color: white), ), const SizedBox(width: 8.0), Expanded( @@ -51,11 +55,11 @@ class TransactionListTile extends StatelessWidget { style: Theme.of(context).textTheme.titleMedium, ), Text( - "${amount.toStringAsFixed(2)} €", + "${type == Type.expense ? '-' : ''}${numToCurrency(amount)} €", style: Theme.of(context) .textTheme .bodyLarge - ?.copyWith(color: (amount > 0) ? green : red), + ?.copyWith(color: typeToColor(type)), ), ], ), From db634c87b87e6042b0eefdd1d5f33c7b618be6d8 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Thu, 17 Aug 2023 10:41:19 +0200 Subject: [PATCH 03/14] Turn modal for adding transaction into a page --- lib/pages/add_page/add_page.dart | 102 +++++++++++++------------------ lib/pages/structure.dart | 67 ++++++++------------ lib/routes.dart | 3 + 3 files changed, 72 insertions(+), 100 deletions(-) diff --git a/lib/pages/add_page/add_page.dart b/lib/pages/add_page/add_page.dart index 5d2dcf8..9bf809c 100644 --- a/lib/pages/add_page/add_page.dart +++ b/lib/pages/add_page/add_page.dart @@ -2,13 +2,14 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../utils/decimal_text_input_formatter.dart'; + +import '../../constants/style.dart'; +import '../../constants/functions.dart'; import '../../model/transaction.dart'; +import '../../providers/transactions_provider.dart'; +import '../../utils/decimal_text_input_formatter.dart'; import 'widgets/details_tile.dart'; import 'widgets/type_tab.dart'; -import '../../providers/transactions_provider.dart'; -import '../../constants/style.dart'; -import '../../constants/functions.dart'; class AddPage extends ConsumerStatefulWidget { const AddPage({super.key}); @@ -61,10 +62,43 @@ class _AddPageState extends ConsumerState with Functions { ref.listen(amountProvider, (_, __) {}); ref.listen(noteProvider, (_, __) {}); - return GestureDetector( - // Serve a togliere il focus se si preme su altro - onTap: () => FocusManager.instance.primaryFocus?.unfocus(), - child: SingleChildScrollView( + return Scaffold( + appBar: AppBar( + title: Text( + (selectedTransaction != null) + ? "Editing transaction" + : "New transaction", + ), + leadingWidth: 100, + leading: TextButton( + onPressed: () => Navigator.pop(context), + child: Text( + 'Cancel', + style: + Theme.of(context).textTheme.titleMedium!.copyWith(color: blue5), + ), + ), + actions: [ + selectedTransaction != null + ? Container( + alignment: Alignment.centerRight, + child: IconButton( + icon: Icon( + Icons.delete_outline, + color: Theme.of(context).colorScheme.error, + ), + onPressed: () async { + ref + .read(transactionsProvider.notifier) + .deleteTransaction(selectedTransaction.id!) + .whenComplete(() => Navigator.of(context).pop()); + }, + ), + ) + : const SizedBox(), + ], + ), + body: SingleChildScrollView( child: Column( children: [ Container( @@ -74,55 +108,6 @@ class _AddPageState extends ConsumerState with Functions { ), child: Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - flex: 1, - child: TextButton( - onPressed: () => Navigator.pop(context), - child: Text( - 'Cancel', - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(color: blue5), - ), - ), - ), - Expanded( - flex: 2, - child: Center( - child: Text( - "New Transaction", - style: Theme.of(context).textTheme.titleLarge, - ), - ), - ), - Expanded( - flex: 1, - child: selectedTransaction != null - ? Container( - alignment: Alignment.centerRight, - child: IconButton( - icon: Icon( - Icons.delete_outline, - color: Theme.of(context).colorScheme.error, - ), - onPressed: () async { - ref - .read(transactionsProvider.notifier) - .deleteTransaction( - selectedTransaction.id!) - .whenComplete( - () => Navigator.of(context).pop()); - }, - ), - ) - : const SizedBox(), - ), - ], - ), const SizedBox(height: 34), Container( height: 30, @@ -338,7 +323,8 @@ class _AddPageState extends ConsumerState with Functions { color: typeToColor(selectedType), ), ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), + keyboardType: + const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ DecimalTextInputFormatter(decimalDigits: 2) ], diff --git a/lib/pages/structure.dart b/lib/pages/structure.dart index 216f8fc..843f322 100644 --- a/lib/pages/structure.dart +++ b/lib/pages/structure.dart @@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../constants/style.dart'; -import 'add_page/add_page.dart'; -import '../pages/home_page.dart'; -import '../pages/transactions_page/transactions_page.dart'; -import '../pages/statistics_page.dart'; -import '../pages/planning_page/planning_page.dart'; +import 'home_page.dart'; +import 'planning_page/planning_page.dart'; +import 'statistics_page.dart'; +import 'transactions_page/transactions_page.dart'; final StateProvider selectedIndexProvider = StateProvider((ref) => 0); @@ -29,10 +29,10 @@ class _StructureState extends ConsumerState { ]; final List _pages = [ const HomePage(), - TransactionsPage(), + const TransactionsPage(), const SizedBox(), - PlanningPage(), - StatsPage(), + const PlanningPage(), + const StatsPage(), ]; @override @@ -40,10 +40,13 @@ class _StructureState extends ConsumerState { final selectedIndex = ref.watch(selectedIndexProvider); return Scaffold( backgroundColor: blue7, - resizeToAvoidBottomInset: false, // Prevent the fab moving up when the keyboard is opened + // Prevent the fab moving up when the keyboard is opened + resizeToAvoidBottomInset: false, appBar: AppBar( // Sulla dashboard (0) setto il background blue - backgroundColor: selectedIndex == 0 ? blue7 : Theme.of(context).colorScheme.background, + backgroundColor: selectedIndex == 0 + ? blue7 + : Theme.of(context).colorScheme.background, elevation: 0, centerTitle: true, title: Text( @@ -99,8 +102,9 @@ class _StructureState extends ConsumerState { unselectedFontSize: 8, backgroundColor: const Color(0xFFF6F6F6), currentIndex: selectedIndex, - onTap: (index) => - index != 2 ? ref.read(selectedIndexProvider.notifier).state = index : null, + onTap: (index) => index != 2 + ? ref.read(selectedIndexProvider.notifier).state = index + : null, items: [ BottomNavigationBarItem( icon: Icon(selectedIndex == 0 ? Icons.home : Icons.home_outlined), @@ -114,12 +118,15 @@ class _StructureState extends ConsumerState { ), const BottomNavigationBarItem(icon: Text(""), label: ""), BottomNavigationBarItem( - icon: Icon(selectedIndex == 3 ? Icons.calendar_today : Icons.calendar_today_outlined), + icon: Icon(selectedIndex == 3 + ? Icons.calendar_today + : Icons.calendar_today_outlined), label: "PLANNING", ), BottomNavigationBarItem( - icon: - Icon(selectedIndex == 4 ? Icons.data_exploration : Icons.data_exploration_outlined), + icon: Icon(selectedIndex == 4 + ? Icons.data_exploration + : Icons.data_exploration_outlined), label: "GRAPHS", ), ], @@ -133,34 +140,10 @@ class _StructureState extends ConsumerState { size: 55, color: Theme.of(context).colorScheme.background, ), - onPressed: () async { - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - isScrollControlled: true, - isDismissible: true, - builder: (BuildContext buildContext) { - return DraggableScrollableSheet( - builder: (_, controller) => Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - color: Theme.of(context).colorScheme.background, - ), - child: ListView( - controller: controller, - shrinkWrap: true, - children: const [AddPage()], - ), - ), - initialChildSize: 0.92, - minChildSize: 0.75, - maxChildSize: 0.92, - ); - }, - ); - }, + onPressed: () => Navigator.of(context).pushNamed("/add-page"), ), - floatingActionButtonLocation: FloatingActionButtonLocation.miniCenterDocked, + floatingActionButtonLocation: + FloatingActionButtonLocation.miniCenterDocked, ); } } diff --git a/lib/routes.dart b/lib/routes.dart index 8d24eba..b57d7f8 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'pages/account_page/account_page.dart'; import 'pages/accounts/account_list.dart'; import 'pages/accounts/add_account.dart'; +import 'pages/add_page/add_page.dart'; import 'pages/add_page/widgets/recurrence_selector.dart'; import 'pages/add_page/widgets/account_selector.dart'; import 'pages/add_page/widgets/category_selector.dart'; @@ -27,6 +28,8 @@ Route makeRoute(RouteSettings settings) { return _materialPageRoute(settings.name, const Structure()); case '/dashboard': return _materialPageRoute(settings.name, const HomePage()); + case '/add-page': + return _materialPageRoute(settings.name, const AddPage()); case '/transactions': return _materialPageRoute(settings.name, const TransactionsPage()); case '/categoryselect': From cf9db64c6e816b5834c8f477f00a26988a726080 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Thu, 17 Aug 2023 10:42:05 +0200 Subject: [PATCH 04/14] Open page to edit transaction on tap --- .../transactions_page/widgets/list_tab.dart | 3 +- .../widgets/transaction_list_tile.dart | 121 ++++++++++-------- 2 files changed, 69 insertions(+), 55 deletions(-) diff --git a/lib/pages/transactions_page/widgets/list_tab.dart b/lib/pages/transactions_page/widgets/list_tab.dart index aae650a..16438e5 100644 --- a/lib/pages/transactions_page/widgets/list_tab.dart +++ b/lib/pages/transactions_page/widgets/list_tab.dart @@ -6,11 +6,11 @@ import '../../../constants/style.dart'; import '../../../constants/functions.dart'; import '../../../model/category_transaction.dart'; import '../../../model/transaction.dart'; -import '../../../pages/transactions_page/widgets/transaction_list_tile.dart'; import '../../../providers/accounts_provider.dart'; import '../../../providers/transactions_provider.dart'; import '../../../providers/categories_provider.dart'; import '../../../utils/date_helper.dart'; +import '../../transactions_page/widgets/transaction_list_tile.dart'; class ListTab extends ConsumerStatefulWidget { const ListTab({ @@ -87,6 +87,7 @@ class _ListTabState extends ConsumerState with Functions { : ""; return TransactionListTile( + transaction: transaction, title: transaction.note ?? "", type: transaction.type, amount: transaction.amount.toDouble(), diff --git a/lib/pages/transactions_page/widgets/transaction_list_tile.dart b/lib/pages/transactions_page/widgets/transaction_list_tile.dart index ea26c86..f4f319e 100644 --- a/lib/pages/transactions_page/widgets/transaction_list_tile.dart +++ b/lib/pages/transactions_page/widgets/transaction_list_tile.dart @@ -1,10 +1,12 @@ import "package:flutter/material.dart"; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../constants/style.dart'; import '../../../constants/functions.dart'; import '../../../model/transaction.dart'; +import '../../../providers/transactions_provider.dart'; -class TransactionListTile extends StatelessWidget with Functions { +class TransactionListTile extends ConsumerWidget with Functions { const TransactionListTile({ Key? key, required this.title, @@ -14,6 +16,7 @@ class TransactionListTile extends StatelessWidget with Functions { required this.category, required this.icon, required this.account, + required this.transaction, }) : super(key: key); final String title; @@ -23,63 +26,73 @@ class TransactionListTile extends StatelessWidget with Functions { final String category; final IconData icon; final String account; + final Transaction transaction; @override - Widget build(BuildContext context) { - return Container( - color: white, - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 12.0, - ), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, + Widget build(BuildContext context, WidgetRef ref) { + return InkWell( + onTap: () { + ref.read(selectedTransactionUpdateProvider.notifier).state = + transaction; + ref.read(transactionsProvider.notifier).transactionUpdateState(); + + Navigator.of(context).pushNamed('/add-page'); + }, + child: Container( + color: white, + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 12.0, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + ), + child: Icon(icon, color: white), ), - child: Icon(icon, color: white), - ), - const SizedBox(width: 8.0), - Expanded( - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: Theme.of(context).textTheme.titleMedium, - ), - Text( - "${type == Type.expense ? '-' : ''}${numToCurrency(amount)} €", - style: Theme.of(context) - .textTheme - .bodyLarge - ?.copyWith(color: typeToColor(type)), - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - category.toUpperCase(), - style: Theme.of(context).textTheme.labelMedium, - ), - Text( - account.toUpperCase(), - style: Theme.of(context).textTheme.labelMedium, - ), - ], - ), - ], + const SizedBox(width: 8.0), + Expanded( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + title, + style: Theme.of(context).textTheme.titleMedium, + ), + Text( + "${type == Type.expense ? '-' : ''}${numToCurrency(amount)} €", + style: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: typeToColor(type)), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + category.toUpperCase(), + style: Theme.of(context).textTheme.labelMedium, + ), + Text( + account.toUpperCase(), + style: Theme.of(context).textTheme.labelMedium, + ), + ], + ), + ], + ), ), - ), - ], + ], + ), ), ); } From d1bebfc7941d4645668f35a195f09ba55e61bc03 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Sat, 26 Aug 2023 09:59:15 +0200 Subject: [PATCH 05/14] Refactor DetailsTile Rename to DetailsListTile. Remove redundant InkWell. Use named instead of positional arguments. --- .../add_page/widgets/details_list_tile.dart | 59 +++++++++++++++++++ lib/pages/add_page/widgets/details_tile.dart | 56 ------------------ 2 files changed, 59 insertions(+), 56 deletions(-) create mode 100644 lib/pages/add_page/widgets/details_list_tile.dart delete mode 100644 lib/pages/add_page/widgets/details_tile.dart diff --git a/lib/pages/add_page/widgets/details_list_tile.dart b/lib/pages/add_page/widgets/details_list_tile.dart new file mode 100644 index 0000000..9ef2beb --- /dev/null +++ b/lib/pages/add_page/widgets/details_list_tile.dart @@ -0,0 +1,59 @@ +import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +import "../../../constants/style.dart"; + +class DetailsListTile extends ConsumerWidget { + const DetailsListTile({ + required this.title, + required this.icon, + required this.value, + required this.callback, + Key? key, + }) : super(key: key); + + final String title; + final IconData icon; + final String? value; + final VoidCallback callback; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return ListTile( + contentPadding: const EdgeInsets.all(16.0), + tileColor: Theme.of(context).colorScheme.surface, + onTap: callback, + leading: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.secondary, + ), + padding: const EdgeInsets.all(10.0), + child: Icon( + icon, + size: 24.0, + color: Theme.of(context).colorScheme.background, + ), + ), + title: Text( + title, + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + value ?? '', + style: + Theme.of(context).textTheme.bodySmall!.copyWith(color: grey1), + ), + const SizedBox(width: 6.0), + const Icon(Icons.chevron_right, color: grey1), + ], + ), + ); + } +} diff --git a/lib/pages/add_page/widgets/details_tile.dart b/lib/pages/add_page/widgets/details_tile.dart deleted file mode 100644 index 244b184..0000000 --- a/lib/pages/add_page/widgets/details_tile.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../../constants/style.dart'; - -class DetailsTile extends ConsumerWidget { - const DetailsTile(this.title, this.icon, this.func, {Key? key, this.value}) - : super(key: key); - - final String? value; - final String title; - final IconData icon; - final VoidCallback func; - - @override - Widget build(BuildContext context, WidgetRef ref) { - return Material( - color: Theme.of(context).colorScheme.surface, - child: InkWell( - onTap: func, - child: ListTile( - contentPadding: const EdgeInsets.all(16), - leading: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.secondary, - ), - padding: const EdgeInsets.all(10.0), - child: Icon( - icon, - size: 24.0, - color: Theme.of(context).colorScheme.background, - ), - ), - title: Text( - title, - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - value ?? '', - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: grey1), - ), - const SizedBox(width: 6), - const Icon(Icons.chevron_right, color: grey1), - ], - ), - ), - ), - ); - } -} From a5ac0b154bb73b021fbfe9908037b90a4b0a3bf2 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Mon, 28 Aug 2023 09:49:35 +0200 Subject: [PATCH 06/14] Refactor AddPage Break it down into separate widgets for legibility. Display the correct switch for recurring payments based on the platform. Rename "Notes" to "Label" and move it to the top (fixes #98). --- lib/pages/add_page/add_page.dart | 513 ++---------------- .../add_page/widgets/account_selector.dart | 262 +++++---- .../add_page/widgets/amount_section.dart | 267 +++++++++ .../add_page/widgets/label_list_tile.dart | 60 ++ .../widgets/recurrence_list_tile.dart | 137 +++++ 5 files changed, 650 insertions(+), 589 deletions(-) create mode 100644 lib/pages/add_page/widgets/amount_section.dart create mode 100644 lib/pages/add_page/widgets/label_list_tile.dart create mode 100644 lib/pages/add_page/widgets/recurrence_list_tile.dart diff --git a/lib/pages/add_page/add_page.dart b/lib/pages/add_page/add_page.dart index 9bf809c..328a0dd 100644 --- a/lib/pages/add_page/add_page.dart +++ b/lib/pages/add_page/add_page.dart @@ -1,15 +1,17 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../constants/style.dart'; import '../../constants/functions.dart'; import '../../model/transaction.dart'; import '../../providers/transactions_provider.dart'; -import '../../utils/decimal_text_input_formatter.dart'; -import 'widgets/details_tile.dart'; -import 'widgets/type_tab.dart'; +import "widgets/account_selector.dart"; +import 'widgets/amount_section.dart'; +import "widgets/category_selector.dart"; +import 'widgets/details_list_tile.dart'; +import 'widgets/label_list_tile.dart'; +import 'widgets/recurrence_list_tile.dart'; class AddPage extends ConsumerStatefulWidget { const AddPage({super.key}); @@ -22,8 +24,6 @@ class _AddPageState extends ConsumerState with Functions { final TextEditingController amountController = TextEditingController(); final TextEditingController noteController = TextEditingController(); - final List _titleList = ['Income', 'Expense', 'Transfer']; - @override void initState() { amountController.text = @@ -101,248 +101,8 @@ class _AddPageState extends ConsumerState with Functions { body: SingleChildScrollView( child: Column( children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - color: Theme.of(context).colorScheme.surface, - ), - child: Column( - children: [ - const SizedBox(height: 34), - Container( - height: 30, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: const BorderRadius.all(Radius.circular(4)), - ), - padding: const EdgeInsets.symmetric(horizontal: 2), - child: ToggleButtons( - direction: Axis.horizontal, - onPressed: (int index) { - List list = trnscTypes; - for (int i = 0; i < 3; i++) { - list[i] = i == index; - } - ref.read(transactionTypesProvider.notifier).state = [ - ...list - ]; - }, - borderRadius: const BorderRadius.all(Radius.circular(4)), - renderBorder: false, - selectedColor: Colors.transparent, - fillColor: Colors.transparent, - constraints: BoxConstraints( - minHeight: 26, - maxHeight: 26, - minWidth: (MediaQuery.of(context).size.width - 36) / 3, - maxWidth: (MediaQuery.of(context).size.width - 36) / 3, - ), - isSelected: trnscTypes, - children: List.generate( - trnscTypes.length, - (index) => TypeTab( - trnscTypes[index], - _titleList[index], - typeToColor(trsncTypeList[index]), - ), - ), - ), - ), - if (selectedType == Type.transfer) - Padding( - padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), - child: SizedBox( - height: 64, - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 8), - Text( - "FROM:", - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith( - color: grey1, - ), - ), - const SizedBox(height: 2), - Material( - child: InkWell( - onTap: () => Navigator.of(context) - .pushNamed('/accountselect', - arguments: bankAccountProvider), - child: Container( - decoration: BoxDecoration( - color: white, - borderRadius: - BorderRadius.circular(4), - boxShadow: [defaultShadow], - ), - padding: const EdgeInsets.all(4), - child: Row( - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context) - .colorScheme - .secondary, - ), - padding: - const EdgeInsets.all(4.0), - child: const Icon( - Icons.account_balance, - color: white, - size: 16, - ), - ), - const Spacer(), - Text( - ref - .watch(bankAccountProvider)! - .name, - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: grey1, - ), - ), - const Spacer(), - ], - ), - ), - ), - ) - ], - ), - ), - GestureDetector( - onTap: () => ref - .read(transactionsProvider.notifier) - .switchAccount(), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Expanded( - child: VerticalDivider( - width: 1, color: grey2)), - Padding( - padding: EdgeInsets.symmetric( - vertical: 2, horizontal: 20), - child: Icon( - Icons.change_circle, - size: 32, - color: grey2, - ), - ), - Expanded( - child: VerticalDivider( - width: 1, color: grey2)), - ], - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 8), - Text( - "TO:", - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith( - color: grey1, - ), - ), - const SizedBox(height: 2), - Material( - child: InkWell( - onTap: () => - Navigator.of(context).pushNamed( - '/accountselect', - arguments: bankAccountTransferProvider, - ), - child: Container( - decoration: BoxDecoration( - color: white, - borderRadius: - BorderRadius.circular(4), - boxShadow: [defaultShadow], - ), - padding: const EdgeInsets.all(4), - child: Row( - children: [ - const Icon(Icons.sort, - color: grey2), - const Spacer(), - Text( - ref - .watch( - bankAccountTransferProvider) - ?.name ?? - "Select account", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: grey1, - ), - ), - const Spacer(), - ], - ), - ), - ), - ), - ], - ), - ) - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, vertical: 24), - child: TextField( - controller: amountController, - decoration: InputDecoration( - border: InputBorder.none, - prefixText: ' ', // set to center the amount - suffixText: '€', - suffixStyle: Theme.of(context) - .textTheme - .headlineMedium! - .copyWith( - color: typeToColor(selectedType), - ), - ), - keyboardType: - const TextInputType.numberWithOptions(decimal: true), - inputFormatters: [ - DecimalTextInputFormatter(decimalDigits: 2) - ], - autofocus: true, - textAlign: TextAlign.center, - cursorColor: grey1, - style: TextStyle( - color: typeToColor(selectedType), - fontSize: 58, - fontWeight: FontWeight.bold, - ), - onChanged: (value) => ref - .read(amountProvider.notifier) - .state = currencyToNum(value), - ), - ), - ], - ), + AmountSection( + amountController: amountController, ), Container( alignment: Alignment.centerLeft, @@ -361,225 +121,68 @@ class _AddPageState extends ConsumerState with Functions { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), children: [ - if (selectedType != Type.transfer) - DetailsTile( - "Account", - Icons.account_balance_wallet, - () { + LabelListTile( + labelController: noteController, + labelProvider: noteProvider, + ), + const Divider(height: 1, color: grey1), + if (selectedType != Type.transfer) ...[ + DetailsListTile( + title: "Account", + icon: Icons.account_balance_wallet, + value: ref.watch(bankAccountProvider)?.name, + callback: () { FocusManager.instance.primaryFocus?.unfocus(); - Navigator.of(context).pushNamed('/accountselect', - arguments: bankAccountProvider); + showModalBottomSheet( + context: context, + builder: (_) => AccountSelector(bankAccountProvider), + ); }, - value: ref.watch(bankAccountProvider)?.name, ), - if (selectedType != Type.transfer) const Divider(height: 1, color: grey1), - if (selectedType != Type.transfer) - DetailsTile( - "Category", - Icons.list_alt, - () { + DetailsListTile( + title: "Category", + icon: Icons.list_alt, + value: ref.watch(categoryProvider)?.name, + callback: () { FocusManager.instance.primaryFocus?.unfocus(); - Navigator.of(context).pushNamed('/categoryselect'); + showModalBottomSheet( + context: context, + builder: (_) => const CategorySelector(), + ); }, - value: ref.watch(categoryProvider)?.name, ), - if (selectedType != Type.transfer) - const Divider(height: 1, color: grey1), - Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 32, 16), - child: Row( - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.secondary, - ), - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Icon( - Icons.description, - size: 24.0, - color: Theme.of(context).colorScheme.background, - ), - ), - ), - const SizedBox(width: 16), - Text( - "Notes", - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith( - color: Theme.of(context).colorScheme.primary), - ), - const SizedBox(width: 16), - Expanded( - child: TextField( - controller: noteController, - decoration: - const InputDecoration(border: InputBorder.none), - textAlign: TextAlign.end, - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: grey1), - onChanged: (value) => - ref.read(noteProvider.notifier).state = value, - ), - ), - ], - ), - ), + ], const Divider(height: 1, color: grey1), - DetailsTile( - "Date", - Icons.calendar_month, - () => showCupertinoModalPopup( - context: context, - builder: (_) => Container( - height: 300, - color: white, - child: Column( - children: [ - SizedBox( - height: 300, - child: CupertinoDatePicker( - initialDateTime: ref.watch(dateProvider), - use24hFormat: true, - onDateTimeChanged: (date) => ref - .read(dateProvider.notifier) - .state = date, - ), - ), - ], - ), - ), - ), + DetailsListTile( + title: "Date", + icon: Icons.calendar_month, value: dateToString(ref.watch(dateProvider)), - ), - if (selectedType == Type.expense) - const Divider(height: 1, color: grey1), - if (selectedType == Type.expense) - ListTile( - contentPadding: const EdgeInsets.all(16), - leading: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.secondary, - ), - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Icon( - Icons.autorenew, - size: 24.0, - color: Theme.of(context).colorScheme.background, + callback: () { + FocusManager.instance.primaryFocus?.unfocus(); + showCupertinoModalPopup( + context: context, + builder: (_) => Container( + height: 300, + color: white, + child: CupertinoDatePicker( + initialDateTime: ref.watch(dateProvider), + mode: CupertinoDatePickerMode.date, + use24hFormat: true, + onDateTimeChanged: (date) => + ref.read(dateProvider.notifier).state = date, ), ), - ), - title: Text( - "Recurring payment", - style: Theme.of(context).textTheme.titleLarge!.copyWith( - color: Theme.of(context).colorScheme.primary), - ), - trailing: CupertinoSwitch( - value: selectedRecurringPay, - onChanged: (select) => ref - .read(selectedRecurringPayProvider.notifier) - .state = select, - ), - ), - if (selectedRecurringPay && selectedType == Type.expense) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.background, - padding: const EdgeInsets.all(16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4)), - ), - onPressed: () => Navigator.of(context) - .pushNamed('/recurrenceselect'), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Interval", - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .primary), - ), - const Spacer(), - Text( - recurrenceMap[ref.watch(intervalProvider)]!, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .secondary), - ), - const SizedBox(width: 6), - Icon( - Icons.chevron_right, - color: Theme.of(context).colorScheme.secondary, - ), - ], - ), - ), - ), - if (selectedRecurringPay && selectedType == Type.expense) - Padding( - padding: const EdgeInsets.all(16), - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.background, - padding: const EdgeInsets.all(16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4)), - ), - onPressed: () => null, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "End repetition", - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .primary), - ), - const Spacer(), - Text( - "Never", - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .secondary), - ), - const SizedBox(width: 6), - Icon( - Icons.chevron_right, - color: Theme.of(context).colorScheme.secondary, - ), - ], - ), - ), + ); + }, + ), + if (selectedType == Type.expense) ...[ + RecurrenceListTile( + isRecurring: selectedRecurringPay, + recurringProvider: selectedRecurringPayProvider, + intervalProvider: intervalProvider, ), + ], ], ), ), diff --git a/lib/pages/add_page/widgets/account_selector.dart b/lib/pages/add_page/widgets/account_selector.dart index 4c0c9c7..9e23310 100644 --- a/lib/pages/add_page/widgets/account_selector.dart +++ b/lib/pages/add_page/widgets/account_selector.dart @@ -15,148 +15,142 @@ class AccountSelector extends ConsumerStatefulWidget { ConsumerState createState() => _AccountSelectorState(); } -class _AccountSelectorState extends ConsumerState with Functions { +class _AccountSelectorState extends ConsumerState + with Functions { @override Widget build(BuildContext context) { final accountsList = ref.watch(accountsProvider); - return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - appBar: AppBar( - title: const Text("Account"), - actions: [ - IconButton( - onPressed: () => Navigator.of(context).pushNamed('/add-account'), - icon: const Icon(Icons.add_circle), - splashRadius: 28, - ), - ], - ), - body: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Column( - children: [ - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), - child: Text( - "MORE FREQUENT", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), + return SingleChildScrollView( child: Column( + children: [ + AppBar( + title: const Text("Account"), + actions: [ + IconButton( + onPressed: () => Navigator.of(context).pushNamed('/add-account'), + icon: const Icon(Icons.add_circle), + splashRadius: 28, ), - Container( - color: Theme.of(context).colorScheme.surface, - height: 74, - width: double.infinity, - child: accountsList.when( - data: (accounts) => ListView.builder( - itemCount: accounts.length > 4 ? 4 : accounts.length, - scrollDirection: Axis.horizontal, - shrinkWrap: true, - itemBuilder: (context, i) { - BankAccount account = accounts[i]; - IconData? icon = accountIconList[account.symbol]; - Color? color = accountColorList[account.color]; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - ), - padding: const EdgeInsets.all(10.0), - child: icon != null - ? Icon( - icon, - size: 24.0, - color: Theme.of(context).colorScheme.background, - ) - : const SizedBox(), - ), - Text( - account.name, - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - ], + ], + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), + child: Text( + "MORE FREQUENT", + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + height: 74, + width: double.infinity, + child: accountsList.when( + data: (accounts) => ListView.builder( + itemCount: accounts.length > 4 ? 4 : accounts.length, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemBuilder: (context, i) { + BankAccount account = accounts[i]; + IconData? icon = accountIconList[account.symbol]; + Color? color = accountColorList[account.color]; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + ), + padding: const EdgeInsets.all(10.0), + child: icon != null + ? Icon( + icon, + size: 24.0, + color: Theme.of(context).colorScheme.background, + ) + : const SizedBox(), ), - ); - }, - ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (err, stack) => Text('Error: $err'), - ), - ), - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), - child: Text( - "ALL ACCOUNTS", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), + Text( + account.name, + style: Theme.of(context).textTheme.labelLarge!.copyWith( + color: Theme.of(context).colorScheme.primary), + ), + ], + ), + ); + }, ), - accountsList.when( - data: (accounts) => ListView.separated( - itemCount: accounts.length, - scrollDirection: Axis.vertical, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) => const Divider(height: 1, color: grey1), - itemBuilder: (context, i) { - BankAccount account = accounts[i]; - IconData? icon = accountIconList[account.symbol]; - Color? color = accountColorList[account.color]; - return Material( - color: Theme.of(context).colorScheme.surface, - child: InkWell( - onTap: () => ref.read(widget.provider.notifier).state = account, - child: ListTile( - contentPadding: const EdgeInsets.all(16), - leading: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - ), - padding: const EdgeInsets.all(10.0), - child: icon != null - ? Icon( - icon, - size: 24.0, - color: Theme.of(context).colorScheme.background, - ) - : const SizedBox(), - ), - title: Text( - account.name, - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - trailing: ref.watch(widget.provider)?.id == account.id - ? Icon(Icons.done, color: Theme.of(context).colorScheme.secondary) - : null, + loading: () => const Center(child: CircularProgressIndicator()), + error: (err, stack) => Text('Error: $err'), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), + child: Text( + "ALL ACCOUNTS", + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + ), + accountsList.when( + data: (accounts) => ListView.separated( + itemCount: accounts.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) => + const Divider(height: 1, color: grey1), + itemBuilder: (context, i) { + BankAccount account = accounts[i]; + IconData? icon = accountIconList[account.symbol]; + Color? color = accountColorList[account.color]; + return Material( + color: Theme.of(context).colorScheme.surface, + child: InkWell( + onTap: () => + ref.read(widget.provider.notifier).state = account, + child: ListTile( + contentPadding: const EdgeInsets.all(16), + leading: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, ), + padding: const EdgeInsets.all(10.0), + child: icon != null + ? Icon( + icon, + size: 24.0, + color: Theme.of(context).colorScheme.background, + ) + : const SizedBox(), ), - ); - }, - ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (err, stack) => Text('Error: $err'), - ), - ], + title: Text( + account.name, + style: Theme.of(context).textTheme.titleLarge!.copyWith( + color: Theme.of(context).colorScheme.primary), + ), + trailing: ref.watch(widget.provider)?.id == account.id + ? Icon(Icons.done, + color: Theme.of(context).colorScheme.secondary) + : null, + ), + ), + ); + }, + ), + loading: () => const Center(child: CircularProgressIndicator()), + error: (err, stack) => Text('Error: $err'), ), - ), - ); + ], + ),); } } diff --git a/lib/pages/add_page/widgets/amount_section.dart b/lib/pages/add_page/widgets/amount_section.dart new file mode 100644 index 0000000..30b7f3e --- /dev/null +++ b/lib/pages/add_page/widgets/amount_section.dart @@ -0,0 +1,267 @@ +import 'package:flutter/material.dart'; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import 'package:flutter/services.dart'; + +import "../../../constants/style.dart"; +import "../../../constants/functions.dart"; +import '../../../model/transaction.dart'; +import '../../../providers/transactions_provider.dart'; +import '../../../utils/decimal_text_input_formatter.dart'; +import 'account_selector.dart'; +import 'type_tab.dart'; + +class AmountSection extends ConsumerWidget with Functions { + const AmountSection({ + required this.amountController, + Key? key, + }) : super(key: key); + + final TextEditingController amountController; + + static const List _titleList = ['Income', 'Expense', 'Transfer']; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final trsncTypeList = ref.watch(transactionTypeList); + final trnscTypes = ref.watch(transactionTypesProvider); + final selectedType = trsncTypeList[trnscTypes.indexOf(true)]; + + return Container( + color: Theme.of(context).colorScheme.surface, + child: Column( + children: [ + const SizedBox(height: 34), + Container( + height: 30, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + borderRadius: const BorderRadius.all(Radius.circular(4)), + ), + padding: const EdgeInsets.symmetric(horizontal: 2), + child: ToggleButtons( + direction: Axis.horizontal, + onPressed: (int index) { + List list = trnscTypes; + for (int i = 0; i < 3; i++) { + list[i] = i == index; + } + ref.read(transactionTypesProvider.notifier).state = [...list]; + }, + borderRadius: const BorderRadius.all(Radius.circular(4)), + renderBorder: false, + selectedColor: Colors.transparent, + fillColor: Colors.transparent, + constraints: BoxConstraints( + minHeight: 26, + maxHeight: 26, + minWidth: (MediaQuery.of(context).size.width - 36) / 3, + maxWidth: (MediaQuery.of(context).size.width - 36) / 3, + ), + isSelected: trnscTypes, + children: List.generate( + trnscTypes.length, + (index) => TypeTab( + trnscTypes[index], + _titleList[index], + typeToColor(trsncTypeList[index]), + ), + ), + ), + ), + if (selectedType == Type.transfer) + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), + child: SizedBox( + height: 64, + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + Text( + "FROM:", + style: Theme.of(context) + .textTheme + .labelMedium! + .copyWith( + color: grey1, + ), + ), + const SizedBox(height: 2), + Material( + child: InkWell( + onTap: () { + FocusManager.instance.primaryFocus?.unfocus(); + showModalBottomSheet( + context: context, + builder: (_) => AccountSelector( + bankAccountProvider, // from + ), + ); + }, + child: Container( + decoration: BoxDecoration( + color: white, + borderRadius: BorderRadius.circular(4), + boxShadow: [defaultShadow], + ), + padding: const EdgeInsets.all(4), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context) + .colorScheme + .secondary, + ), + padding: const EdgeInsets.all(4.0), + child: const Icon( + Icons.account_balance, + color: white, + size: 16, + ), + ), + const Spacer(), + Text( + ref.watch(bankAccountProvider)!.name, + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: grey1, + ), + ), + const Spacer(), + ], + ), + ), + ), + ) + ], + ), + ), + GestureDetector( + onTap: () => ref + .read(transactionsProvider.notifier) + .switchAccount(), + child: const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: VerticalDivider(width: 1, color: grey2)), + Padding( + padding: EdgeInsets.symmetric( + vertical: 2, horizontal: 20), + child: Icon( + Icons.change_circle, + size: 32, + color: grey2, + ), + ), + Expanded( + child: VerticalDivider(width: 1, color: grey2), + ), + ], + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + Text( + "TO:", + style: Theme.of(context) + .textTheme + .labelMedium! + .copyWith( + color: grey1, + ), + ), + const SizedBox(height: 2), + Material( + child: InkWell( + onTap: () { + FocusManager.instance.primaryFocus?.unfocus(); + showModalBottomSheet( + context: context, + builder: (_) => AccountSelector( + bankAccountTransferProvider, // to + ), + ); + }, + child: Container( + decoration: BoxDecoration( + color: white, + borderRadius: BorderRadius.circular(4), + boxShadow: [defaultShadow], + ), + padding: const EdgeInsets.all(4), + child: Row( + children: [ + const Icon(Icons.sort, color: grey2), + const Spacer(), + Text( + ref + .watch( + bankAccountTransferProvider) + ?.name ?? + "Select account", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: grey1, + ), + ), + const Spacer(), + ], + ), + ), + ), + ), + ], + ), + ) + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), + child: TextField( + controller: amountController, + decoration: InputDecoration( + border: InputBorder.none, + prefixText: ' ', // set to center the amount + suffixText: '€', + suffixStyle: Theme.of(context) + .textTheme + .headlineMedium! + .copyWith(color: typeToColor(selectedType)), + ), + keyboardType: + const TextInputType.numberWithOptions(decimal: true), + inputFormatters: [ + DecimalTextInputFormatter(decimalDigits: 2) + ], + autofocus: false, + textAlign: TextAlign.center, + cursorColor: grey1, + style: TextStyle( + color: typeToColor(selectedType), + fontSize: 58, + fontWeight: FontWeight.bold, + ), + onChanged: (value) => ref.read(amountProvider.notifier).state = + currencyToNum(value), + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/add_page/widgets/label_list_tile.dart b/lib/pages/add_page/widgets/label_list_tile.dart new file mode 100644 index 0000000..0967fbf --- /dev/null +++ b/lib/pages/add_page/widgets/label_list_tile.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +import "../../../constants/style.dart"; + +class LabelListTile extends ConsumerWidget { + const LabelListTile({ + required this.labelController, + required this.labelProvider, + Key? key, + }) : super(key: key); + + final TextEditingController labelController; + final StateProvider labelProvider; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 32, 16), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.secondary, + ), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Icon( + Icons.description, + size: 24.0, + color: Theme.of(context).colorScheme.background, + ), + ), + ), + const SizedBox(width: 16), + Text( + "Label", + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + const SizedBox(width: 16), + Expanded( + child: TextField( + controller: labelController, + decoration: const InputDecoration(border: InputBorder.none), + textAlign: TextAlign.end, + style: + Theme.of(context).textTheme.bodySmall!.copyWith(color: grey1), + onChanged: (value) => + ref.read(labelProvider.notifier).state = value, + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/add_page/widgets/recurrence_list_tile.dart b/lib/pages/add_page/widgets/recurrence_list_tile.dart new file mode 100644 index 0000000..a3b0104 --- /dev/null +++ b/lib/pages/add_page/widgets/recurrence_list_tile.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import 'dart:io' show Platform; + +import "../../../constants/style.dart"; +import '../../../model/transaction.dart'; + +class RecurrenceListTile extends ConsumerWidget { + const RecurrenceListTile({ + required this.isRecurring, + required this.recurringProvider, + required this.intervalProvider, + Key? key, + }) : super(key: key); + + final bool isRecurring; + final StateProvider recurringProvider; + final StateProvider intervalProvider; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Column( + children: [ + const Divider(height: 1, color: grey1), + ListTile( + contentPadding: const EdgeInsets.all(16), + leading: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.secondary, + ), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Icon( + Icons.autorenew, + size: 24.0, + color: Theme.of(context).colorScheme.background, + ), + ), + ), + title: Text( + "Recurring payment", + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + trailing: (Platform.isIOS) + ? CupertinoSwitch( + value: isRecurring, + onChanged: (select) => + ref.read(recurringProvider.notifier).state = select, + ) + : Switch( + value: isRecurring, + onChanged: (select) => + ref.read(recurringProvider.notifier).state = select, + ), + ), + if (isRecurring) ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: TextButton( + style: TextButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.background, + padding: const EdgeInsets.all(16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4)), + ), + onPressed: () => + Navigator.of(context).pushNamed('/recurrenceselect'), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Interval", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + const Spacer(), + Text( + recurrenceMap[ref.watch(intervalProvider)]!, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: Theme.of(context).colorScheme.secondary), + ), + const SizedBox(width: 6), + Icon( + Icons.chevron_right, + color: Theme.of(context).colorScheme.secondary, + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.all(16), + child: TextButton( + style: TextButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.background, + padding: const EdgeInsets.all(16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4)), + ), + onPressed: () {}, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "End repetition", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + const Spacer(), + Text( + "Never", + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: Theme.of(context).colorScheme.secondary), + ), + const SizedBox(width: 6), + Icon( + Icons.chevron_right, + color: Theme.of(context).colorScheme.secondary, + ), + ], + ), + ), + ), + ] + ], + ); + } +} From eae3ea0b3c70e87f140fead0391bad72f6d73683 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Tue, 29 Aug 2023 09:25:26 +0200 Subject: [PATCH 07/14] Show iOS/Android date picker based on platform --- lib/pages/add_page/add_page.dart | 42 +++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/pages/add_page/add_page.dart b/lib/pages/add_page/add_page.dart index 328a0dd..0d940ca 100644 --- a/lib/pages/add_page/add_page.dart +++ b/lib/pages/add_page/add_page.dart @@ -1,3 +1,4 @@ +import 'dart:io' show Platform; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -158,22 +159,35 @@ class _AddPageState extends ConsumerState with Functions { title: "Date", icon: Icons.calendar_month, value: dateToString(ref.watch(dateProvider)), - callback: () { + callback: () async { FocusManager.instance.primaryFocus?.unfocus(); - showCupertinoModalPopup( - context: context, - builder: (_) => Container( - height: 300, - color: white, - child: CupertinoDatePicker( - initialDateTime: ref.watch(dateProvider), - mode: CupertinoDatePickerMode.date, - use24hFormat: true, - onDateTimeChanged: (date) => - ref.read(dateProvider.notifier).state = date, + if (Platform.isIOS) { + showCupertinoModalPopup( + context: context, + builder: (_) => Container( + height: 300, + color: white, + child: CupertinoDatePicker( + initialDateTime: ref.watch(dateProvider), + minimumYear: 2015, + maximumYear: 2050, + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (date) => + ref.read(dateProvider.notifier).state = date, + ), ), - ), - ); + ); + } else if (Platform.isAndroid) { + final DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: ref.watch(dateProvider), + firstDate: DateTime(2015), + lastDate: DateTime(2050), + ); + if (pickedDate != null) { + ref.read(dateProvider.notifier).state = pickedDate; + } + } }, ), if (selectedType == Type.expense) ...[ From 44d72847f1c8282504e824650626153c83029834 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Tue, 29 Aug 2023 09:26:06 +0200 Subject: [PATCH 08/14] Format date in English --- lib/constants/functions.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/constants/functions.dart b/lib/constants/functions.dart index 80435a9..d824795 100644 --- a/lib/constants/functions.dart +++ b/lib/constants/functions.dart @@ -5,7 +5,7 @@ import '../model/transaction.dart'; mixin Functions { String numToCurrency(num? value) { - if(value == null) return ''; + if (value == null) return ''; return value.toStringAsFixed(2).replaceAll(".", ","); } @@ -17,7 +17,7 @@ mixin Functions { } String dateToString(DateTime date) { - final format = DateFormat('E d MMMM', 'it_IT'); + final format = DateFormat('E, d MMMM y'); return format.format(date); } From 06968b7092ae05c72b94e2978f2fbaab8550f126 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Tue, 29 Aug 2023 10:26:56 +0200 Subject: [PATCH 09/14] Import providers directly from RecurrenceListTile --- lib/pages/add_page/add_page.dart | 7 +---- .../widgets/recurrence_list_tile.dart | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/pages/add_page/add_page.dart b/lib/pages/add_page/add_page.dart index 0d940ca..2ac1dc5 100644 --- a/lib/pages/add_page/add_page.dart +++ b/lib/pages/add_page/add_page.dart @@ -58,7 +58,6 @@ class _AddPageState extends ConsumerState with Functions { final trnscTypes = ref.watch(transactionTypesProvider); final selectedTransaction = ref.watch(selectedTransactionUpdateProvider); final selectedType = trsncTypeList[trnscTypes.indexOf(true)]; - final selectedRecurringPay = ref.watch(selectedRecurringPayProvider); // I listen servono a evitare che il provider faccia il dispose subito dopo essere stato aggiornato ref.listen(amountProvider, (_, __) {}); ref.listen(noteProvider, (_, __) {}); @@ -191,11 +190,7 @@ class _AddPageState extends ConsumerState with Functions { }, ), if (selectedType == Type.expense) ...[ - RecurrenceListTile( - isRecurring: selectedRecurringPay, - recurringProvider: selectedRecurringPayProvider, - intervalProvider: intervalProvider, - ), + const RecurrenceListTile(), ], ], ), diff --git a/lib/pages/add_page/widgets/recurrence_list_tile.dart b/lib/pages/add_page/widgets/recurrence_list_tile.dart index a3b0104..987f4e7 100644 --- a/lib/pages/add_page/widgets/recurrence_list_tile.dart +++ b/lib/pages/add_page/widgets/recurrence_list_tile.dart @@ -4,22 +4,19 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import 'dart:io' show Platform; import "../../../constants/style.dart"; +import '../../../providers/transactions_provider.dart'; import '../../../model/transaction.dart'; +import 'recurrence_selector.dart'; class RecurrenceListTile extends ConsumerWidget { const RecurrenceListTile({ - required this.isRecurring, - required this.recurringProvider, - required this.intervalProvider, Key? key, }) : super(key: key); - final bool isRecurring; - final StateProvider recurringProvider; - final StateProvider intervalProvider; - @override Widget build(BuildContext context, WidgetRef ref) { + final isRecurring = ref.watch(selectedRecurringPayProvider); + return Column( children: [ const Divider(height: 1, color: grey1), @@ -49,13 +46,14 @@ class RecurrenceListTile extends ConsumerWidget { trailing: (Platform.isIOS) ? CupertinoSwitch( value: isRecurring, - onChanged: (select) => - ref.read(recurringProvider.notifier).state = select, + onChanged: (select) => ref + .read(selectedRecurringPayProvider.notifier) + .state = select, ) : Switch( value: isRecurring, onChanged: (select) => - ref.read(recurringProvider.notifier).state = select, + ref.read(selectedRecurringPayProvider.notifier).state = select, ), ), if (isRecurring) ...[ @@ -68,8 +66,13 @@ class RecurrenceListTile extends ConsumerWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4)), ), - onPressed: () => - Navigator.of(context).pushNamed('/recurrenceselect'), + onPressed: () { + FocusManager.instance.primaryFocus?.unfocus(); + showModalBottomSheet( + context: context, + builder: (_) => const RecurrenceSelector(), + ); + }, child: Row( mainAxisSize: MainAxisSize.min, children: [ From 4f007d3cc97a58474e481214f79e55efd0e39765 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Wed, 30 Aug 2023 09:21:31 +0200 Subject: [PATCH 10/14] Remove routes for ex pages turned modals --- lib/routes.dart | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/routes.dart b/lib/routes.dart index b57d7f8..f674eab 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,14 +1,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'pages/account_page/account_page.dart'; import 'pages/accounts/account_list.dart'; import 'pages/accounts/add_account.dart'; import 'pages/add_page/add_page.dart'; -import 'pages/add_page/widgets/recurrence_selector.dart'; -import 'pages/add_page/widgets/account_selector.dart'; -import 'pages/add_page/widgets/category_selector.dart'; import 'pages/categories/add_category.dart'; import 'pages/categories/category_list.dart'; import 'pages/home_page.dart'; @@ -32,8 +28,6 @@ Route makeRoute(RouteSettings settings) { return _materialPageRoute(settings.name, const AddPage()); case '/transactions': return _materialPageRoute(settings.name, const TransactionsPage()); - case '/categoryselect': - return _cupertinoPageRoute(settings.name, const CategorySelector()); case '/category-list': return _cupertinoPageRoute(settings.name, const CategoryList()); case '/add-category': @@ -50,11 +44,6 @@ Route makeRoute(RouteSettings settings) { return _cupertinoPageRoute(settings.name, const AccountList()); case '/add-account': return _cupertinoPageRoute(settings.name, const AddAccount()); - case '/accountselect': - return _cupertinoPageRoute( - settings.name, AccountSelector(settings.arguments as StateProvider)); - case '/recurrenceselect': - return _cupertinoPageRoute(settings.name, const RecurrenceSelector()); case '/planning': return _materialPageRoute(settings.name, const PlanningPage()); case '/graphs': From 88d3b521432383c62c40512ce5b070f64a57573f Mon Sep 17 00:00:00 2001 From: GBergatto Date: Fri, 8 Sep 2023 18:51:58 +0200 Subject: [PATCH 11/14] Improve modals for picking account and category --- lib/pages/add_page/add_page.dart | 39 ++- .../add_page/widgets/account_selector.dart | 257 ++++++++++-------- .../add_page/widgets/amount_section.dart | 43 ++- .../add_page/widgets/category_selector.dart | 248 +++++++++-------- 4 files changed, 354 insertions(+), 233 deletions(-) diff --git a/lib/pages/add_page/add_page.dart b/lib/pages/add_page/add_page.dart index 2ac1dc5..3440645 100644 --- a/lib/pages/add_page/add_page.dart +++ b/lib/pages/add_page/add_page.dart @@ -135,7 +135,25 @@ class _AddPageState extends ConsumerState with Functions { FocusManager.instance.primaryFocus?.unfocus(); showModalBottomSheet( context: context, - builder: (_) => AccountSelector(bankAccountProvider), + clipBehavior: Clip.antiAliasWithSaveLayer, + isScrollControlled: true, + useSafeArea: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), + topRight: Radius.circular(10.0), + ), + ), + builder: (_) => DraggableScrollableSheet( + expand: false, + minChildSize: 0.5, + initialChildSize: 0.7, + maxChildSize: 0.9, + builder: (_, controller) => AccountSelector( + provider: bankAccountProvider, + scrollController: controller, + ), + ), ); }, ), @@ -148,7 +166,24 @@ class _AddPageState extends ConsumerState with Functions { FocusManager.instance.primaryFocus?.unfocus(); showModalBottomSheet( context: context, - builder: (_) => const CategorySelector(), + clipBehavior: Clip.antiAliasWithSaveLayer, + isScrollControlled: true, + useSafeArea: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), + topRight: Radius.circular(10.0), + ), + ), + builder: (_) => DraggableScrollableSheet( + expand: false, + minChildSize: 0.5, + initialChildSize: 0.7, + maxChildSize: 0.9, + builder: (_, controller) => CategorySelector( + scrollController: controller, + ), + ), ); }, ), diff --git a/lib/pages/add_page/widgets/account_selector.dart b/lib/pages/add_page/widgets/account_selector.dart index 9e23310..af2b38c 100644 --- a/lib/pages/add_page/widgets/account_selector.dart +++ b/lib/pages/add_page/widgets/account_selector.dart @@ -7,9 +7,14 @@ import '../../../model/bank_account.dart'; import '../../../providers/accounts_provider.dart'; class AccountSelector extends ConsumerStatefulWidget { - const AccountSelector(this.provider, {Key? key}) : super(key: key); + const AccountSelector({ + required this.provider, + required this.scrollController, + Key? key, + }) : super(key: key); final StateProvider provider; + final ScrollController scrollController; @override ConsumerState createState() => _AccountSelectorState(); @@ -20,7 +25,9 @@ class _AccountSelectorState extends ConsumerState @override Widget build(BuildContext context) { final accountsList = ref.watch(accountsProvider); - return SingleChildScrollView( child: Column( + + return Column( + mainAxisSize: MainAxisSize.min, children: [ AppBar( title: const Text("Account"), @@ -32,125 +39,147 @@ class _AccountSelectorState extends ConsumerState ), ], ), - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), - child: Text( - "MORE FREQUENT", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - ), - Container( - color: Theme.of(context).colorScheme.surface, - height: 74, - width: double.infinity, - child: accountsList.when( - data: (accounts) => ListView.builder( - itemCount: accounts.length > 4 ? 4 : accounts.length, - scrollDirection: Axis.horizontal, - shrinkWrap: true, - itemBuilder: (context, i) { - BankAccount account = accounts[i]; - IconData? icon = accountIconList[account.symbol]; - Color? color = accountColorList[account.color]; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, + Expanded( + child: SingleChildScrollView( + controller: widget.scrollController, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), + child: Text( + "MORE FREQUENT", + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + height: 74, + width: double.infinity, + child: accountsList.when( + data: (accounts) => ListView.builder( + itemCount: (accounts.length > 4) ? 4 : accounts.length, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemBuilder: (context, i) { + BankAccount account = accounts[i]; + IconData? icon = accountIconList[account.symbol]; + Color? color = accountColorList[account.color]; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + ), + padding: const EdgeInsets.all(10.0), + child: icon != null + ? Icon( + icon, + size: 24.0, + color: Theme.of(context) + .colorScheme + .background, + ) + : const SizedBox(), + ), + Text( + account.name, + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith( + color: Theme.of(context) + .colorScheme + .primary), + ), + ], + ), + ); + }, + ), + loading: () => + const Center(child: CircularProgressIndicator()), + error: (err, stack) => Text('Error: $err'), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), + child: Text( + "ALL ACCOUNTS", + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + ), + accountsList.when( + data: (accounts) => ListView.separated( + itemCount: accounts.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) => + const Divider(height: 1, color: grey1), + itemBuilder: (context, i) { + BankAccount account = accounts[i]; + IconData? icon = accountIconList[account.symbol]; + Color? color = accountColorList[account.color]; + return ListTile( + tileColor: Theme.of(context).colorScheme.surface, + onTap: () => + ref.read(widget.provider.notifier).state = account, + contentPadding: const EdgeInsets.all(12.0), + leading: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + ), + padding: const EdgeInsets.all(10.0), + child: icon != null + ? Icon( + icon, + size: 24.0, + color: + Theme.of(context).colorScheme.background, + ) + : const SizedBox(), ), - padding: const EdgeInsets.all(10.0), - child: icon != null + title: Text( + account.name, + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith( + color: Theme.of(context).colorScheme.primary, + ), + ), + trailing: (ref.watch(widget.provider)?.id == account.id) ? Icon( - icon, - size: 24.0, - color: Theme.of(context).colorScheme.background, + Icons.done, + color: Theme.of(context).colorScheme.secondary, ) - : const SizedBox(), - ), - Text( - account.name, - style: Theme.of(context).textTheme.labelLarge!.copyWith( - color: Theme.of(context).colorScheme.primary), - ), - ], - ), - ); - }, - ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (err, stack) => Text('Error: $err'), - ), - ), - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), - child: Text( - "ALL ACCOUNTS", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - ), - accountsList.when( - data: (accounts) => ListView.separated( - itemCount: accounts.length, - scrollDirection: Axis.vertical, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) => - const Divider(height: 1, color: grey1), - itemBuilder: (context, i) { - BankAccount account = accounts[i]; - IconData? icon = accountIconList[account.symbol]; - Color? color = accountColorList[account.color]; - return Material( - color: Theme.of(context).colorScheme.surface, - child: InkWell( - onTap: () => - ref.read(widget.provider.notifier).state = account, - child: ListTile( - contentPadding: const EdgeInsets.all(16), - leading: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - ), - padding: const EdgeInsets.all(10.0), - child: icon != null - ? Icon( - icon, - size: 24.0, - color: Theme.of(context).colorScheme.background, - ) - : const SizedBox(), - ), - title: Text( - account.name, - style: Theme.of(context).textTheme.titleLarge!.copyWith( - color: Theme.of(context).colorScheme.primary), - ), - trailing: ref.watch(widget.provider)?.id == account.id - ? Icon(Icons.done, - color: Theme.of(context).colorScheme.secondary) - : null, + : null, + ); + }, ), + loading: () => + const Center(child: CircularProgressIndicator()), + error: (err, stack) => Text('Error: $err'), ), - ); - }, + ], + ), ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (err, stack) => Text('Error: $err'), ), ], - ),); + ); } } diff --git a/lib/pages/add_page/widgets/amount_section.dart b/lib/pages/add_page/widgets/amount_section.dart index 30b7f3e..357157f 100644 --- a/lib/pages/add_page/widgets/amount_section.dart +++ b/lib/pages/add_page/widgets/amount_section.dart @@ -96,8 +96,25 @@ class AmountSection extends ConsumerWidget with Functions { FocusManager.instance.primaryFocus?.unfocus(); showModalBottomSheet( context: context, - builder: (_) => AccountSelector( - bankAccountProvider, // from + clipBehavior: Clip.antiAliasWithSaveLayer, + isScrollControlled: true, + useSafeArea: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), + topRight: Radius.circular(10.0), + ), + ), + builder: (_) => DraggableScrollableSheet( + expand: false, + minChildSize: 0.5, + initialChildSize: 0.7, + maxChildSize: 0.9, + builder: (_, controller) => AccountSelector( + // from + provider: bankAccountProvider, + scrollController: controller, + ), ), ); }, @@ -185,11 +202,29 @@ class AmountSection extends ConsumerWidget with Functions { Material( child: InkWell( onTap: () { + FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus(); showModalBottomSheet( context: context, - builder: (_) => AccountSelector( - bankAccountTransferProvider, // to + clipBehavior: Clip.antiAliasWithSaveLayer, + isScrollControlled: true, + useSafeArea: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), + topRight: Radius.circular(10.0), + ), + ), + builder: (_) => DraggableScrollableSheet( + expand: false, + minChildSize: 0.5, + initialChildSize: 0.7, + maxChildSize: 0.9, + builder: (_, controller) => AccountSelector( + // to + provider: bankAccountTransferProvider, + scrollController: controller, + ), ), ); }, diff --git a/lib/pages/add_page/widgets/category_selector.dart b/lib/pages/add_page/widgets/category_selector.dart index 024195c..7fd8de8 100644 --- a/lib/pages/add_page/widgets/category_selector.dart +++ b/lib/pages/add_page/widgets/category_selector.dart @@ -8,118 +8,133 @@ import '../../../providers/categories_provider.dart'; import '../../../providers/transactions_provider.dart'; class CategorySelector extends ConsumerStatefulWidget { - const CategorySelector({Key? key}) : super(key: key); + const CategorySelector({ + required this.scrollController, + Key? key, + }) : super(key: key); + + final ScrollController scrollController; @override ConsumerState createState() => _CategorySelectorState(); } -class _CategorySelectorState extends ConsumerState with Functions { +class _CategorySelectorState extends ConsumerState + with Functions { @override Widget build(BuildContext context) { final categoriesList = ref.watch(categoriesProvider); - return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - appBar: AppBar( - title: const Text("Category"), - actions: [ - IconButton( - onPressed: () => Navigator.of(context).pushNamed('/add-category'), - icon: const Icon(Icons.add_circle), - splashRadius: 28, - ), - ], - ), - body: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Column( - children: [ - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), - child: Text( - "MORE FREQUENT", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + AppBar( + title: const Text("Category"), + actions: [ + IconButton( + onPressed: () => Navigator.of(context).pushNamed('/add-category'), + icon: const Icon(Icons.add_circle), + splashRadius: 28, ), - Container( - color: Theme.of(context).colorScheme.surface, - height: 74, - width: double.infinity, - child: categoriesList.when( - data: (categories) => ListView.builder( - itemCount: 4, - scrollDirection: Axis.horizontal, - shrinkWrap: true, - itemBuilder: (context, i) { - CategoryTransaction category = categories[i]; - IconData? icon = iconList[category.symbol]; - Color? color = categoryColorList[category.color]; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - ), - padding: const EdgeInsets.all(10.0), - child: icon != null - ? Icon( - icon, - size: 24.0, - color: Theme.of(context).colorScheme.background, - ) - : const SizedBox(), - ), - Text( - category.name, - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), + ], + ), + Expanded( + child: SingleChildScrollView( + controller: widget.scrollController, + child: Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), + child: Text( + "MORE FREQUENT", + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + height: 74, + width: double.infinity, + child: categoriesList.when( + data: (categories) => ListView.builder( + itemCount: 4, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemBuilder: (context, i) { + CategoryTransaction category = categories[i]; + IconData? icon = iconList[category.symbol]; + Color? color = categoryColorList[category.color]; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + ), + padding: const EdgeInsets.all(10.0), + child: icon != null + ? Icon( + icon, + size: 24.0, + color: Theme.of(context) + .colorScheme + .background, + ) + : const SizedBox(), + ), + Text( + category.name, + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith( + color: Theme.of(context) + .colorScheme + .primary), + ), + ], ), - ], - ), - ); - }, + ); + }, + ), + loading: () => + const Center(child: CircularProgressIndicator()), + error: (err, stack) => Text('Error: $err'), + ), ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (err, stack) => Text('Error: $err'), - ), - ), - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), - child: Text( - "ALL CATEGORIES", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - ), - categoriesList.when( - data: (categories) => ListView.separated( - itemCount: categories.length, - scrollDirection: Axis.vertical, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) => const Divider(height: 1, color: grey1), - itemBuilder: (context, i) { - CategoryTransaction category = categories[i]; - IconData? icon = iconList[category.symbol]; - Color? color = categoryColorList[category.color]; - return Material( - color: Theme.of(context).colorScheme.surface, - child: InkWell( - onTap: () => ref.read(categoryProvider.notifier).state = category, - child: ListTile( + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 16, top: 32, bottom: 8), + child: Text( + "ALL CATEGORIES", + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + ), + categoriesList.when( + data: (categories) => ListView.separated( + itemCount: categories.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) => + const Divider(height: 1, color: grey1), + itemBuilder: (context, i) { + CategoryTransaction category = categories[i]; + IconData? icon = iconList[category.symbol]; + Color? color = categoryColorList[category.color]; + return ListTile( + tileColor: Theme.of(context).colorScheme.surface, + onTap: () => ref.read(categoryProvider.notifier).state = + category, contentPadding: const EdgeInsets.all(16), leading: Container( decoration: BoxDecoration( @@ -131,7 +146,8 @@ class _CategorySelectorState extends ConsumerState with Functi ? Icon( icon, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: + Theme.of(context).colorScheme.background, ) : const SizedBox(), ), @@ -140,22 +156,28 @@ class _CategorySelectorState extends ConsumerState with Functi style: Theme.of(context) .textTheme .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), + .copyWith( + color: Theme.of(context).colorScheme.primary, + ), ), trailing: ref.watch(categoryProvider)?.id == category.id - ? Icon(Icons.done, color: Theme.of(context).colorScheme.secondary) + ? Icon( + Icons.done, + color: Theme.of(context).colorScheme.secondary, + ) : null, - ), - ), - ); - }, - ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (err, stack) => Text('Error: $err'), + ); + }, + ), + loading: () => + const Center(child: CircularProgressIndicator()), + error: (err, stack) => Text('Error: $err'), + ), + ], ), - ], + ), ), - ), + ], ); } } From 92e076b1bd6ea594fde3095ded9ce521296e2c4e Mon Sep 17 00:00:00 2001 From: GBergatto Date: Fri, 8 Sep 2023 19:40:13 +0200 Subject: [PATCH 12/14] Add hint text to price --- lib/pages/add_page/widgets/amount_section.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pages/add_page/widgets/amount_section.dart b/lib/pages/add_page/widgets/amount_section.dart index 357157f..5da09e4 100644 --- a/lib/pages/add_page/widgets/amount_section.dart +++ b/lib/pages/add_page/widgets/amount_section.dart @@ -270,6 +270,7 @@ class AmountSection extends ConsumerWidget with Functions { child: TextField( controller: amountController, decoration: InputDecoration( + hintText: "0", border: InputBorder.none, prefixText: ' ', // set to center the amount suffixText: '€', From 0e558ec6c8698b908a43ea8537d42ff08e57c379 Mon Sep 17 00:00:00 2001 From: GBergatto Date: Thu, 9 Nov 2023 07:36:59 +0100 Subject: [PATCH 13/14] Use adaptive Switch --- .../widgets/recurrence_list_tile.dart | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/lib/pages/add_page/widgets/recurrence_list_tile.dart b/lib/pages/add_page/widgets/recurrence_list_tile.dart index 987f4e7..7a702f8 100644 --- a/lib/pages/add_page/widgets/recurrence_list_tile.dart +++ b/lib/pages/add_page/widgets/recurrence_list_tile.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import "package:flutter_riverpod/flutter_riverpod.dart"; -import 'dart:io' show Platform; import "../../../constants/style.dart"; import '../../../providers/transactions_provider.dart'; @@ -43,18 +41,11 @@ class RecurrenceListTile extends ConsumerWidget { .titleLarge! .copyWith(color: Theme.of(context).colorScheme.primary), ), - trailing: (Platform.isIOS) - ? CupertinoSwitch( - value: isRecurring, - onChanged: (select) => ref - .read(selectedRecurringPayProvider.notifier) - .state = select, - ) - : Switch( - value: isRecurring, - onChanged: (select) => - ref.read(selectedRecurringPayProvider.notifier).state = select, - ), + trailing: Switch.adaptive( + value: isRecurring, + onChanged: (select) => + ref.read(selectedRecurringPayProvider.notifier).state = select, + ), ), if (isRecurring) ...[ Padding( From c81fe2b1fd846b11206076d1a9e889eaf016f1cd Mon Sep 17 00:00:00 2001 From: GBergatto Date: Thu, 9 Nov 2023 07:47:29 +0100 Subject: [PATCH 14/14] Open transaction page from homepage --- lib/custom_widgets/transactions_list.dart | 36 +++++++---------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/lib/custom_widgets/transactions_list.dart b/lib/custom_widgets/transactions_list.dart index c45a1b2..8720265 100644 --- a/lib/custom_widgets/transactions_list.dart +++ b/lib/custom_widgets/transactions_list.dart @@ -3,7 +3,6 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../constants/constants.dart'; -import '../pages/add_page/add_page.dart'; import '../providers/transactions_provider.dart'; import '../constants/functions.dart'; import '../model/bank_account.dart'; @@ -184,32 +183,17 @@ class TransactionRow extends ConsumerWidget with Functions { color: Theme.of(context).colorScheme.background, child: InkWell( onTap: () { - ref.read(selectedTransactionUpdateProvider.notifier).state = transaction; - ref.read(transactionsProvider.notifier).transactionUpdateState(); - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - isScrollControlled: true, - isDismissible: true, - builder: (BuildContext buildContext) { - return DraggableScrollableSheet( - builder: (_, controller) => Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - color: Theme.of(context).colorScheme.background, - ), - child: ListView( - controller: controller, - shrinkWrap: true, - children: const [AddPage()], - ), - ), - initialChildSize: 0.92, - minChildSize: 0.75, - maxChildSize: 0.92, + ref.read(selectedTransactionUpdateProvider.notifier).state = + transaction; + ref + .read(transactionsProvider.notifier) + .transactionUpdateState(); + ref + .read(transactionsProvider.notifier) + .transactionUpdateState() + .whenComplete( + () => Navigator.of(context).pushNamed("/add-page"), ); - }, - ); }, borderRadius: BorderRadius.vertical( top: i == 0 ? const Radius.circular(8) : Radius.zero,