Files
fuelstats-app/lib/screens/home_screen.dart
2025-09-16 21:48:33 +02:00

197 lines
7.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/refuel.dart';
import '../services/session_manager.dart';
import '../widgets/stat_card.dart';
import '../widgets/gas_price_chart.dart';
import '../widgets/consumption_chart.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
String _formatDouble(double value) {
var s = value.toStringAsFixed(2);
if (s.endsWith('.00')) {
s = s.substring(0, s.length - 3);
} else if (s.endsWith('0')) {
s = s.substring(0, s.length - 1);
}
return s;
}
double? _allTimeConsumption(List<Refuel> refuels) {
if (refuels.length < 2) return null;
final distance = refuels.last.mileage - refuels.first.mileage;
if (distance <= 0) return null;
final liters =
refuels.skip(1).fold<double>(0.0, (sum, r) => sum + r.liters);
return liters / distance * 100;
}
double? _lastConsumption(List<Refuel> refuels) {
if (refuels.length < 2) return null;
final last = refuels[refuels.length - 1];
final prev = refuels[refuels.length - 2];
final distance = last.mileage - prev.mileage;
if (distance <= 0) return null;
return last.liters / distance * 100;
}
int? _kmSinceLast(List<Refuel> refuels) {
if (refuels.length < 2) return null;
return refuels.last.mileage - refuels[refuels.length - 2].mileage;
}
int _kmForPeriod(List<Refuel> refuels, DateTime from) {
final list = refuels
.where((r) => r.createdAt != null && r.createdAt!.isAfter(from))
.toList();
if (list.length < 2) return 0;
return list.last.mileage - list.first.mileage;
}
int _kmAllTime(List<Refuel> refuels) {
if (refuels.length < 2) return 0;
return refuels.last.mileage - refuels.first.mileage;
}
@override
Widget build(BuildContext context) {
return Consumer<SessionManager>(
builder: (context, session, _) {
final vehicle = session.defaultVehicle;
if (vehicle == null) {
return const Scaffold(
body: Center(child: Text('No default vehicle selected')),
);
}
final refuels = session.refuels
.where((r) => r.vehicleId == vehicle.id)
.toList();
refuels.sort((a, b) => a.mileage.compareTo(b.mileage));
final allCons = _allTimeConsumption(refuels);
final lastCons = _lastConsumption(refuels);
final kmLast = _kmSinceLast(refuels);
final now = DateTime.now();
final km1m = _kmForPeriod(refuels, now.subtract(const Duration(days: 30)));
final km6m =
_kmForPeriod(refuels, now.subtract(const Duration(days: 182)));
final km1y =
_kmForPeriod(refuels, now.subtract(const Duration(days: 365)));
final kmAll = _kmAllTime(refuels);
final lastRefuels =
refuels.length > 14 ? refuels.sublist(refuels.length - 14) : refuels;
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
color: Theme.of(context).colorScheme.secondaryContainer,
child: ListTile(
leading: const Icon(Icons.directions_car),
title: Text(vehicle.name,
style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(vehicle.registrationPlate),
trailing:
const Icon(Icons.star, color: Colors.amber),
),
),
const SizedBox(height: 16),
const Text('Refuel stats',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 2,
children: [
StatCard(
title: 'Avg consumption (all time)',
value: allCons != null
? '${_formatDouble(allCons)} L/100km'
: '-',
),
StatCard(
title: 'Since last refuel',
value: lastCons != null
? '${_formatDouble(lastCons)} L/100km'
: '-',
),
],
),
const SizedBox(height: 24),
const Text('Kilometers driven',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Builder(builder: (context) {
final kmCards = <Widget>[
StatCard(
title: 'Since last refuel',
value: kmLast != null ? '$kmLast km' : '-',
),
StatCard(title: 'Past month', value: '$km1m km'),
StatCard(title: 'Past 6 months', value: '$km6m km'),
StatCard(title: 'Past year', value: '$km1y km'),
StatCard(title: 'All time', value: '$kmAll km'),
];
if (kmCards.length.isOdd) {
kmCards.add(const SizedBox.shrink());
}
return GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 2,
children: kmCards,
);
}),
if (lastRefuels.isNotEmpty) ...[
const SizedBox(height: 24),
Text('Gas price (last ${lastRefuels.length} refuels)',
style: const TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
SizedBox(
height: 220,
child: GasPriceChart(refuels: lastRefuels),
),
if (lastRefuels.length > 1) ...[
const SizedBox(height: 24),
const Text('Consumption trend',
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
SizedBox(
height: 220,
child: ConsumptionChart(refuels: lastRefuels),
),
],
],
const SizedBox(height: 8),
],
),
),
),
),
);
},
);
}
}