diff --git a/README.md b/README.md index 61d0e0c..52e4724 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ - - + + diff --git a/lib/db/entries.dart b/lib/db/entries.dart index 4d0787e..8d98be6 100644 --- a/lib/db/entries.dart +++ b/lib/db/entries.dart @@ -64,13 +64,39 @@ class EntryService { return null; } - Future> getAllEntries() async { + Future> getAllEntries({ + DateTime? startDate, + DateTime? endDate, + }) async { final dbClient = await _databaseHelper.db; - // Fetch all entries and all accounts in separate calls - final List> entriesData = - await dbClient.query('Entries'); - final List allAccounts = await AccountService().getAllAccounts(true); + String whereClause = ''; + List whereArguments = []; + + // If startDate is provided, add it to the where clause + if (startDate != null) { + whereClause += 'date >= ?'; + whereArguments.add(startDate.toIso8601String()); + } + + // If endDate is provided, add it to the where clause + if (endDate != null) { + if (whereClause.isNotEmpty) { + whereClause += ' AND '; + } + whereClause += 'date <= ?'; + whereArguments.add(endDate.toIso8601String()); + } + + // Fetch all entries according to the provided start and end dates + final List> entriesData = await dbClient.query( + 'Entries', + where: whereClause.isEmpty ? null : whereClause, + whereArgs: whereArguments.isEmpty ? null : whereArguments, + ); + + final List allAccounts = + await AccountService().getAllAccounts(true); // Create a map for quick account lookup by ID var accountsMap = {for (var account in allAccounts) account.id: account}; @@ -105,7 +131,8 @@ class EntryService { ); } - Future adjustFirstBalance(int toAccountId, int fromAccountId, double balance) async { + Future adjustFirstBalance( + int toAccountId, int fromAccountId, double balance) async { if (balance == 0) { return; } @@ -121,7 +148,8 @@ class EntryService { await dbClient.insert('Entries', entry.toJson()); } - Future adjustFirstForexBalance(int toAccountId, int fromAccountId, double balance) async { + Future adjustFirstForexBalance( + int toAccountId, int fromAccountId, double balance) async { if (balance == 0) { return; } diff --git a/lib/pages/export.dart b/lib/pages/export.dart index 53a2bef..14fc2f1 100644 --- a/lib/pages/export.dart +++ b/lib/pages/export.dart @@ -15,8 +15,8 @@ export "home/frame/destinations.dart"; export "home/frame/main.dart"; export "home/frame/mobile.dart"; export "home/frame/tablet.dart"; -export "home/months/main.dart"; -export "home/months/month_card.dart"; +export 'home/months/screen/main.dart'; +export 'home/months/screen/month_card.dart'; export 'home/summary/main.dart'; export 'home/summary/widgets.dart'; export "intro/intro_big.dart"; diff --git a/lib/pages/home/entries/main.dart b/lib/pages/home/entries/main.dart index 9ca22d2..666adc2 100644 --- a/lib/pages/home/entries/main.dart +++ b/lib/pages/home/entries/main.dart @@ -6,8 +6,14 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class EntriesPage extends StatefulWidget { + final DateTime? startDate; + final DateTime? endDate; + final int? accountID; const EntriesPage({ super.key, + this.accountID, + this.startDate, + this.endDate, }); @override @@ -25,7 +31,10 @@ class EntriesPageState extends State { } Future loadEntries() async { - List entriesList = await _entryService.getAllEntries(); + List entriesList = await _entryService.getAllEntries( + startDate: widget.startDate, + endDate: widget.endDate, + ); entriesList.sort((a, b) => (b.date!.compareTo(a.date!))); List mergedEntries = []; diff --git a/lib/pages/home/months/month_card.dart b/lib/pages/home/months/month_card.dart deleted file mode 100644 index b810cf2..0000000 --- a/lib/pages/home/months/month_card.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:finease/db/months.dart'; -import 'package:finease/parts/card.dart'; -import 'package:flutter/material.dart'; -import 'package:finease/core/export.dart'; -import 'package:intl/intl.dart'; - -DateFormat formatter = DateFormat('MMMM yyyy'); - -class MonthCards extends StatelessWidget { - final List months; - - const MonthCards({ - super.key, - required this.months, - }); - - @override - Widget build(BuildContext context) { - return ListView.builder( - itemCount: months.length, - itemBuilder: (context, index) => MonthCard( - month: months[index], - ), - ); - } -} - -class MonthCard extends StatelessWidget { - const MonthCard({ - super.key, - required this.month, - }); - - final Month month; - - @override - Widget build(BuildContext context) { - return AppCard( - elevation: 4, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Flex( - direction: Axis.horizontal, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Text( - formatter.format(month.date!), - style: context.titleSmall, - ) - ], - ), - const Divider(), - Row( - children: [ - Expanded( - child: MonthWidget( - title: "Net Worth", - content: month.networth!.toStringAsFixed(2), - ), - ), - const SizedBox(width: 8), - Expanded( - child: MonthWidget( - title: "Effect", - content: month.effect!.toStringAsFixed(2), - ), - ), - ], - ), - const SizedBox(height: 6), - Row( - children: [ - Expanded( - child: MonthWidget( - title: "Income", - content: month.income!.toStringAsFixed(2), - ), - ), - const SizedBox(width: 8), - Expanded( - child: MonthWidget( - title: "Expense", - content: month.expense!.toStringAsFixed(2), - ), - ), - ], - ), - ], - ), - ), - ); - } -} - -class MonthWidget extends StatelessWidget { - const MonthWidget({ - super.key, - required this.title, - required this.content, - }); - - final String content; - final String title; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(title), - Text( - content, - style: context.titleLarge, - ), - ], - ); - } -} diff --git a/lib/pages/home/months/main.dart b/lib/pages/home/months/screen/main.dart similarity index 100% rename from lib/pages/home/months/main.dart rename to lib/pages/home/months/screen/main.dart diff --git a/lib/pages/home/months/screen/month_card.dart b/lib/pages/home/months/screen/month_card.dart new file mode 100644 index 0000000..48bf2a4 --- /dev/null +++ b/lib/pages/home/months/screen/month_card.dart @@ -0,0 +1,138 @@ +import 'package:finease/db/months.dart'; +import 'package:finease/parts/card.dart'; +import 'package:finease/routes/routes_name.dart'; +import 'package:flutter/material.dart'; +import 'package:finease/core/export.dart'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; + +DateFormat formatter = DateFormat('MMMM yyyy'); + +class MonthCards extends StatelessWidget { + final List months; + + const MonthCards({ + super.key, + required this.months, + }); + + @override + Widget build(BuildContext context) { + return ListView.builder( + itemCount: months.length, + itemBuilder: (context, index) => MonthCard( + month: months[index], + ), + ); + } +} + +class MonthCard extends StatelessWidget { + const MonthCard({ + super.key, + required this.month, + }); + + final Month month; + + @override + Widget build(BuildContext context) { + DateTime startDate = month.date!; + DateTime endDate = DateTime(month.date!.year, month.date!.month + 1, 1) + .subtract(const Duration(seconds: 1)); + + return InkWell( + onTap: () { + context.pushNamed( + RoutesName.transactionsByDate.name, + extra: { + 'startDate': startDate.toIso8601String(), + 'endDate': endDate.toIso8601String(), + }, + ); + }, + child: AppCard( + elevation: 4, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flex( + direction: Axis.horizontal, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Text( + formatter.format(month.date!), + style: context.titleSmall, + ) + ], + ), + const Divider(), + Row( + children: [ + Expanded( + child: MonthWidget( + title: "Net Worth", + content: month.networth!.toStringAsFixed(2), + ), + ), + const SizedBox(width: 8), + Expanded( + child: MonthWidget( + title: "Effect", + content: month.effect!.toStringAsFixed(2), + ), + ), + ], + ), + const SizedBox(height: 6), + Row( + children: [ + Expanded( + child: MonthWidget( + title: "Income", + content: month.income!.toStringAsFixed(2), + ), + ), + const SizedBox(width: 8), + Expanded( + child: MonthWidget( + title: "Expense", + content: month.expense!.toStringAsFixed(2), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} + +class MonthWidget extends StatelessWidget { + const MonthWidget({ + super.key, + required this.title, + required this.content, + }); + + final String content; + final String title; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title), + Text( + content, + style: context.titleLarge, + ), + ], + ); + } +} diff --git a/lib/pages/settings/import_db.dart b/lib/pages/settings/import_db.dart index acbc963..94ee4de 100644 --- a/lib/pages/settings/import_db.dart +++ b/lib/pages/settings/import_db.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:finease/core/export.dart'; import 'package:finease/db/db.dart'; import 'package:finease/db/settings.dart'; @@ -32,7 +31,6 @@ class ImportDatabaseWidgetState extends State { bool importSuccessful = await _importDatabase(filePath); if (importSuccessful) { - await File(filePath).delete(); // ignore: use_build_context_synchronously context.pop(); widget.onImport(); diff --git a/lib/parts/app_top_bar.dart b/lib/parts/app_top_bar.dart index 2671423..2a1c0db 100644 --- a/lib/parts/app_top_bar.dart +++ b/lib/parts/app_top_bar.dart @@ -19,6 +19,13 @@ PreferredSize appBar( borderRadius: BorderRadius.circular(32), clipBehavior: Clip.antiAlias, child: AppBar( + leading: Navigator.of(context).canPop() + ? IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.of(context).pop(), + ) + : null, + automaticallyImplyLeading: true, backgroundColor: context.secondaryContainer.withOpacity(0.5), scrolledUnderElevation: 0, title: Text(title, style: context.titleMedium), diff --git a/lib/routes/routes.dart b/lib/routes/routes.dart index aa390f6..9bf9330 100644 --- a/lib/routes/routes.dart +++ b/lib/routes/routes.dart @@ -52,6 +52,16 @@ final GoRouter goRouter = GoRouter( return const EntriesPage(); }, ), + GoRoute( + name: RoutesName.transactionsByDate.name, + path: RoutesName.transactionsByDate.path, + builder: (BuildContext context, GoRouterState state) { + Map range = state.extra as Map; + final DateTime startDate = DateTime.parse(range['startDate']!); + final DateTime endDate = DateTime.parse(range['endDate']!); + return EntriesPage(startDate: startDate, endDate: endDate); + }, + ), GoRoute( name: RoutesName.setupAccounts.name, path: RoutesName.setupAccounts.path, @@ -75,8 +85,7 @@ final GoRouter goRouter = GoRouter( final int accountID = int.parse( state.pathParameters[RoutesName.editAccount.param]!, ); - dynamic Function() onFormSubmitted = - state.extra as dynamic Function(); + dynamic Function() onFormSubmitted = state.extra as dynamic Function(); return EditAccountScreen( accountID: accountID, onFormSubmitted: onFormSubmitted, diff --git a/lib/routes/routes_name.dart b/lib/routes/routes_name.dart index 9e07611..4263a22 100644 --- a/lib/routes/routes_name.dart +++ b/lib/routes/routes_name.dart @@ -10,6 +10,7 @@ enum RoutesName { settings, setupAccounts, transactions, + transactionsByDate, } extension RoutesNameHelper on RoutesName { diff --git a/pubspec.yaml b/pubspec.yaml index a20565b..b9bde9c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: finease description: "A full stack mobile app to keep track of financial transactions" publish_to: 'none' -version: 1.0.18 +version: 1.0.19 environment: sdk: '>=3.2.3 <4.0.0'