Enhance AppSettings and RentController to manage not-occupied months, add lifetime summary to SettingsScreen, and update tests for compatibility

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-20 10:57:57 +01:00
parent 67af59bd0d
commit 9c4e275ff7
6 changed files with 228 additions and 31 deletions
+16 -20
View File
@@ -34,6 +34,12 @@ class HomeScreen extends StatelessWidget {
selected: current == PaymentStatus.notPaid,
onTap: () => Navigator.of(context).pop(PaymentStatus.notPaid),
),
ListTile(
title: const Text('Not occupied'),
selected: current == PaymentStatus.notOccupied,
onTap: () =>
Navigator.of(context).pop(PaymentStatus.notOccupied),
),
ListTile(
title: const Text('Pending'),
selected: current == PaymentStatus.pending,
@@ -91,20 +97,6 @@ class HomeScreen extends StatelessWidget {
RentController controller,
RentTableRow row,
) async {
if (row.status == PaymentStatus.notOccupied) {
if (!context.mounted) {
return;
}
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Use Settings -> Unit occupied to manage not-occupied months.',
),
),
);
return;
}
final nextStatus = await _showStatusPicker(context, row.status);
if (!context.mounted) {
return;
@@ -114,8 +106,9 @@ class HomeScreen extends StatelessWidget {
}
double? paidUsd;
if (nextStatus == PaymentStatus.onTime ||
nextStatus == PaymentStatus.late) {
if (nextStatus == PaymentStatus.onTime) {
paidUsd = controller.settings.rentUsd;
} else if (nextStatus == PaymentStatus.late) {
paidUsd = await _showPaidUsdDialog(
context,
initialValue: row.usdAmount ?? controller.settings.rentUsd,
@@ -186,8 +179,11 @@ class HomeScreen extends StatelessWidget {
children: <Widget>[
_YearSwitcher(
year: controller.selectedYear,
onPrevious: () =>
controller.selectYear(controller.selectedYear - 1),
onPrevious: controller.canSelectPreviousYear
? () => controller.selectYear(
controller.selectedYear - 1,
)
: null,
onNext: controller.selectedYear < DateTime.now().year
? () => controller.selectYear(
controller.selectedYear + 1,
@@ -282,7 +278,7 @@ class HomeScreen extends StatelessWidget {
'Total: ${usdCurrency.format(totalUsd)} | ${sekCurrency.format(totalSek)}',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 12),
FilledButton.icon(
onPressed: () async {
await controller.markCurrentMonthPaidManually();
@@ -337,7 +333,7 @@ class _YearSwitcher extends StatelessWidget {
});
final int year;
final VoidCallback onPrevious;
final VoidCallback? onPrevious;
final VoidCallback? onNext;
@override
+35
View File
@@ -1,5 +1,6 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:rental_income_tracker/state/rent_controller.dart';
@@ -56,11 +57,45 @@ class _SettingsScreenState extends State<SettingsScreen> {
Widget build(BuildContext context) {
return Consumer<RentController>(
builder: (context, controller, _) {
final summary = controller.buildLifetimeSummary();
final usdCurrency = NumberFormat.currency(
symbol: r'$',
decimalDigits: 2,
);
final sekCurrency = NumberFormat.currency(
symbol: 'SEK ',
decimalDigits: 2,
);
return Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'All-time totals (since May 2024)',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Text(
'${usdCurrency.format(summary.totalUsd)} | ${sekCurrency.format(summary.totalSek)}',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 4),
Text(
'Occupancy: ${summary.occupancyPercent.toStringAsFixed(1)}% (${summary.occupiedMonths}/${summary.totalTrackedMonths} months)',
),
],
),
),
),
const SizedBox(height: 12),
TextField(
controller: _rentController,
keyboardType: const TextInputType.numberWithOptions(