Make the loan details work on mobile

This commit is contained in:
PapaTutuWawa 2025-05-12 22:01:53 +02:00
parent c5aa165424
commit 88c9991e0d
4 changed files with 156 additions and 77 deletions

View File

@ -14,6 +14,8 @@ import 'package:okane/ui/pages/transaction_details.dart';
import 'package:okane/ui/state/core.dart'; import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/state/settings.dart'; import 'package:okane/ui/state/settings.dart';
import 'ui/pages/loans/loan_details.dart';
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
LocaleSettings.useDeviceLocale(); LocaleSettings.useDeviceLocale();
@ -66,6 +68,7 @@ class MyApp extends StatelessWidget {
"/transactions/details" => "/transactions/details" =>
TransactionDetailsPage.mobileRoute, TransactionDetailsPage.mobileRoute,
"/budgets/details" => BudgetDetailsPage.mobileRoute, "/budgets/details" => BudgetDetailsPage.mobileRoute,
"/loans/details" => LoanDetailsPage.mobileRoute,
_ => MaterialPageRoute<void>( _ => MaterialPageRoute<void>(
builder: (_) => Text("Unknown!!"), builder: (_) => Text("Unknown!!"),
), ),

View File

@ -112,7 +112,7 @@ final _pages = <OkanePageItem>[
Icons.money_outlined, Icons.money_outlined,
"Loans", "Loans",
LoanListPage(), LoanListPage(),
(_) => LoanDetailsPage(), (_) => LoanDetailsPage(isPage: false),
false, false,
), ),
OkanePageItem( OkanePageItem(

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/database/database.dart';
import 'package:okane/ui/pages/loans/add_loan_change.dart'; import 'package:okane/ui/pages/loans/add_loan_change.dart';
import 'package:okane/ui/state/core.dart'; import 'package:okane/ui/state/core.dart';
@ -7,22 +9,46 @@ import 'package:okane/ui/utils.dart';
import 'package:okane/ui/widgets/image_wrapper.dart'; import 'package:okane/ui/widgets/image_wrapper.dart';
class LoanDetailsPage extends StatelessWidget { class LoanDetailsPage extends StatelessWidget {
const LoanDetailsPage({super.key}); final bool isPage;
const LoanDetailsPage({super.key, required this.isPage});
static MaterialPageRoute<void> get mobileRoute =>
MaterialPageRoute(builder: (_) => LoanDetailsPage(isPage: true));
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Scaffold(
body: Column(
children: [ children: [
BlocBuilder<CoreCubit, CoreState>( if (isPage)
SizedBox(
height: 50,
child: Row(
children: [
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
),
Expanded(
child: BlocBuilder<CoreCubit, CoreState>(
builder: (context, state) { builder: (context, state) {
if (state.activeLoan == null) { if (state.activeLoan == null) {
return Text("No loan selected"); return Text("No loan selected");
} }
final loans = state.activeLoan!.changes.toList(); final loanChanges = state.activeLoan!.changes.toList();
final loanSum = loans final loanSum =
loanChanges.isNotEmpty
? loanChanges
.map((c) => c.amount) .map((c) => c.amount)
.reduce((acc, val) => acc + val); .reduce((acc, val) => acc + val)
: 0.0;
return CustomScrollView( return CustomScrollView(
slivers: [ slivers: [
SliverToBoxAdapter( SliverToBoxAdapter(
@ -30,7 +56,8 @@ class LoanDetailsPage extends StatelessWidget {
children: [ children: [
ImageWrapper( ImageWrapper(
title: state.activeLoan!.beneficiary.value!.name, title: state.activeLoan!.beneficiary.value!.name,
path: state.activeLoan!.beneficiary.value!.imagePath, path:
state.activeLoan!.beneficiary.value!.imagePath,
), ),
Text(state.activeLoan!.beneficiary.value!.name), Text(state.activeLoan!.beneficiary.value!.name),
], ],
@ -65,33 +92,77 @@ class LoanDetailsPage extends StatelessWidget {
), ),
), ),
SliverList.builder( SliverToBoxAdapter(
itemCount: loans.length, child:
itemBuilder: (context, index) { loanChanges.isNotEmpty
final item = loans[index]; ? GroupedListView(
elements: loanChanges,
return ListTile( 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: leading:
item.amount > 0 item.amount > 0
? Icon(Icons.add, color: Colors.green) ? Icon(
: Icon(Icons.remove, color: Colors.red), Icons.add,
color: Colors.green,
)
: Icon(
Icons.remove,
color: Colors.red,
),
title: Text(formatCurrency(item.amount)), title: Text(formatCurrency(item.amount)),
trailing: IconButton( trailing: IconButton(
icon: Icon(Icons.delete, color: Colors.red), icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () async { onPressed: () async {
state.activeLoan!.changes.remove(item); state.activeLoan!.changes.remove(
item,
);
await deleteLoanChange(item); await deleteLoanChange(item);
await upsertLoan(state.activeLoan!); await upsertLoan(state.activeLoan!);
}, },
), ),
); ),
}, )
: Text("No transactions available"),
), ),
], ],
); );
}, },
), ),
),
], ],
),
); );
} }
} }

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:okane/database/database.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/pages/loans/add_loan.dart';
import 'package:okane/ui/state/core.dart'; import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/utils.dart'; import 'package:okane/ui/utils.dart';
@ -28,6 +29,10 @@ class LoanListPage extends StatelessWidget {
), ),
onTap: () { onTap: () {
GetIt.I.get<CoreCubit>().setActiveLoan(item); GetIt.I.get<CoreCubit>().setActiveLoan(item);
if (getScreenSize(context) == ScreenSize.small) {
Navigator.of(context).pushNamed("/loans/details");
}
}, },
trailing: IconButton( trailing: IconButton(
onPressed: () async { onPressed: () async {