From 88c9991e0da24feba254c380df322db7c18089c4 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Mon, 12 May 2025 22:01:53 +0200 Subject: [PATCH] Make the loan details work on mobile --- lib/main.dart | 3 + lib/ui/navigation.dart | 2 +- lib/ui/pages/loans/loan_details.dart | 223 ++++++++++++++++++--------- lib/ui/pages/loans/loan_list.dart | 5 + 4 files changed, 156 insertions(+), 77 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 7f4d818..f586db9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,6 +14,8 @@ import 'package:okane/ui/pages/transaction_details.dart'; import 'package:okane/ui/state/core.dart'; import 'package:okane/ui/state/settings.dart'; +import 'ui/pages/loans/loan_details.dart'; + Future main() async { WidgetsFlutterBinding.ensureInitialized(); LocaleSettings.useDeviceLocale(); @@ -66,6 +68,7 @@ class MyApp extends StatelessWidget { "/transactions/details" => TransactionDetailsPage.mobileRoute, "/budgets/details" => BudgetDetailsPage.mobileRoute, + "/loans/details" => LoanDetailsPage.mobileRoute, _ => MaterialPageRoute( builder: (_) => Text("Unknown!!"), ), diff --git a/lib/ui/navigation.dart b/lib/ui/navigation.dart index 3801744..bc0e7c8 100644 --- a/lib/ui/navigation.dart +++ b/lib/ui/navigation.dart @@ -112,7 +112,7 @@ final _pages = [ Icons.money_outlined, "Loans", LoanListPage(), - (_) => LoanDetailsPage(), + (_) => LoanDetailsPage(isPage: false), false, ), OkanePageItem( diff --git a/lib/ui/pages/loans/loan_details.dart b/lib/ui/pages/loans/loan_details.dart index 38d2df2..9a48a6a 100644 --- a/lib/ui/pages/loans/loan_details.dart +++ b/lib/ui/pages/loans/loan_details.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:grouped_list/grouped_list.dart'; +import 'package:okane/database/collections/loan.dart'; import 'package:okane/database/database.dart'; import 'package:okane/ui/pages/loans/add_loan_change.dart'; import 'package:okane/ui/state/core.dart'; @@ -7,91 +9,160 @@ import 'package:okane/ui/utils.dart'; import 'package:okane/ui/widgets/image_wrapper.dart'; class LoanDetailsPage extends StatelessWidget { - const LoanDetailsPage({super.key}); + final bool isPage; + + const LoanDetailsPage({super.key, required this.isPage}); + + static MaterialPageRoute get mobileRoute => + MaterialPageRoute(builder: (_) => LoanDetailsPage(isPage: true)); @override Widget build(BuildContext context) { - return Stack( - children: [ - BlocBuilder( - builder: (context, state) { - if (state.activeLoan == null) { - return Text("No loan selected"); - } - - final loans = state.activeLoan!.changes.toList(); - final loanSum = loans - .map((c) => c.amount) - .reduce((acc, val) => acc + val); - return CustomScrollView( - slivers: [ - SliverToBoxAdapter( - child: Row( - children: [ - ImageWrapper( - title: state.activeLoan!.beneficiary.value!.name, - path: state.activeLoan!.beneficiary.value!.imagePath, - ), - Text(state.activeLoan!.beneficiary.value!.name), - ], + return Scaffold( + body: Column( + children: [ + if (isPage) + SizedBox( + height: 50, + child: Row( + children: [ + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.of(context).pop(); + }, ), - ), + ], + ), + ), + Expanded( + child: BlocBuilder( + builder: (context, state) { + if (state.activeLoan == null) { + return Text("No loan selected"); + } - SliverToBoxAdapter( - child: Text("Total: ${formatCurrency(loanSum)}"), - ), - - SliverToBoxAdapter( - child: Row( - children: [ - Text("Loan Transactions"), - - IconButton( - onPressed: () { - showDialogOrModal( - context: context, - builder: - (_) => AddLoanChangePopup( - loan: state.activeLoan!, - onDone: () { - Navigator.of(context).pop(); - }, - ), - ); - }, - icon: Icon(Icons.add), + final loanChanges = state.activeLoan!.changes.toList(); + final loanSum = + loanChanges.isNotEmpty + ? loanChanges + .map((c) => c.amount) + .reduce((acc, val) => acc + val) + : 0.0; + return CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: Row( + children: [ + ImageWrapper( + title: state.activeLoan!.beneficiary.value!.name, + path: + state.activeLoan!.beneficiary.value!.imagePath, + ), + Text(state.activeLoan!.beneficiary.value!.name), + ], ), - ], - ), - ), + ), - SliverList.builder( - itemCount: loans.length, - itemBuilder: (context, index) { - final item = loans[index]; + SliverToBoxAdapter( + child: Text("Total: ${formatCurrency(loanSum)}"), + ), - return ListTile( - leading: - item.amount > 0 - ? Icon(Icons.add, color: Colors.green) - : Icon(Icons.remove, color: Colors.red), - title: Text(formatCurrency(item.amount)), - trailing: IconButton( - icon: Icon(Icons.delete, color: Colors.red), - onPressed: () async { - state.activeLoan!.changes.remove(item); - await deleteLoanChange(item); - await upsertLoan(state.activeLoan!); - }, + SliverToBoxAdapter( + child: Row( + children: [ + Text("Loan Transactions"), + + IconButton( + onPressed: () { + showDialogOrModal( + context: context, + builder: + (_) => AddLoanChangePopup( + loan: state.activeLoan!, + onDone: () { + Navigator.of(context).pop(); + }, + ), + ); + }, + icon: Icon(Icons.add), + ), + ], ), - ); - }, - ), - ], - ); - }, - ), - ], + ), + + SliverToBoxAdapter( + child: + loanChanges.isNotEmpty + ? GroupedListView( + elements: loanChanges, + shrinkWrap: true, + reverse: true, + groupBy: + (LoanChange loanChange) => + formatDateTime(loanChange.date), + groupHeaderBuilder: + (item) => Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + DecoratedBox( + decoration: BoxDecoration( + color: Colors.black.withAlpha(170), + borderRadius: BorderRadius.circular( + 8, + ), + ), + child: Padding( + padding: EdgeInsets.all(4), + child: Text( + formatDateTime(item.date), + style: TextStyle( + color: Colors.white, + ), + ), + ), + ), + ], + ), + indexedItemBuilder: + (ctx, item, idx) => ListTile( + leading: + item.amount > 0 + ? Icon( + Icons.add, + color: Colors.green, + ) + : Icon( + Icons.remove, + color: Colors.red, + ), + title: Text(formatCurrency(item.amount)), + trailing: IconButton( + icon: Icon( + Icons.delete, + color: Colors.red, + ), + onPressed: () async { + state.activeLoan!.changes.remove( + item, + ); + await deleteLoanChange(item); + await upsertLoan(state.activeLoan!); + }, + ), + ), + ) + : Text("No transactions available"), + ), + ], + ); + }, + ), + ), + ], + ), ); } } diff --git a/lib/ui/pages/loans/loan_list.dart b/lib/ui/pages/loans/loan_list.dart index 3723d6e..dba0467 100644 --- a/lib/ui/pages/loans/loan_list.dart +++ b/lib/ui/pages/loans/loan_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import 'package:okane/database/database.dart'; +import 'package:okane/screen.dart'; import 'package:okane/ui/pages/loans/add_loan.dart'; import 'package:okane/ui/state/core.dart'; import 'package:okane/ui/utils.dart'; @@ -28,6 +29,10 @@ class LoanListPage extends StatelessWidget { ), onTap: () { GetIt.I.get().setActiveLoan(item); + + if (getScreenSize(context) == ScreenSize.small) { + Navigator.of(context).pushNamed("/loans/details"); + } }, trailing: IconButton( onPressed: () async {