Release version 1.0.0

This commit is contained in:
2025-09-16 21:48:33 +02:00
commit a6d27c5f21
165 changed files with 8385 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import '../models/refuel.dart';
class ConsumptionChart extends StatelessWidget {
final List<Refuel> refuels;
const ConsumptionChart({super.key, required this.refuels});
@override
Widget build(BuildContext context) {
final spots = <FlSpot>[];
final labels = <String>[];
for (var i = 1; i < refuels.length; i++) {
final prev = refuels[i - 1];
final curr = refuels[i];
final distance = curr.mileage - prev.mileage;
if (distance <= 0) continue;
final consumption =
double.parse((curr.liters / distance * 100).toStringAsFixed(2));
spots.add(FlSpot(spots.length.toDouble(), consumption));
final date = curr.createdAt;
labels.add(date != null ? '${date.month}/${date.day}' : '');
}
return LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: spots,
isCurved: true,
barWidth: 3,
color: Theme.of(context).colorScheme.secondary,
dotData: const FlDotData(show: true),
)
],
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.black87,
tooltipMargin: 40,
fitInsideHorizontally: true,
fitInsideVertically: true,
getTooltipItems: (spots) => spots
.map((s) => LineTooltipItem(
'${s.y.toStringAsFixed(2)} L/100km',
const TextStyle(color: Colors.white)))
.toList(),
),
),
titlesData: FlTitlesData(
leftTitles: AxisTitles(
axisNameSize: 28,
axisNameWidget: const Padding(
padding: EdgeInsets.only(right: 8),
child: Text('L/100km'),
),
sideTitles: SideTitles(
showTitles: true,
reservedSize: 50,
getTitlesWidget: (value, meta) => Padding(
padding: const EdgeInsets.only(right: 4),
child: Text(value.toStringAsFixed(1),
style: const TextStyle(fontSize: 10)),
),
),
),
bottomTitles: AxisTitles(
axisNameSize: 24,
axisNameWidget: const Padding(
padding: EdgeInsets.only(top: 8),
child: Text('Date'),
),
sideTitles: SideTitles(
showTitles: true,
reservedSize: 36,
getTitlesWidget: (value, meta) {
final index = value.toInt();
if (index < 0 || index >= labels.length) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(labels[index],
style: const TextStyle(fontSize: 10)),
);
},
),
),
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
gridData: const FlGridData(show: false),
borderData: FlBorderData(show: false),
),
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class DataSection extends StatelessWidget {
final String title;
const DataSection({required this.title});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(16),
child: Container(
height: 200,
padding: EdgeInsets.all(16),
child: Center(child: Text(title, style: TextStyle(fontSize: 18))),
),
);
}
}

View File

@@ -0,0 +1,93 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import '../models/refuel.dart';
class GasPriceChart extends StatelessWidget {
final List<Refuel> refuels;
const GasPriceChart({super.key, required this.refuels});
@override
Widget build(BuildContext context) {
final spots = <FlSpot>[];
final labels = <String>[];
for (var i = 0; i < refuels.length; i++) {
final refuel = refuels[i];
spots.add(FlSpot(spots.length.toDouble(), refuel.pricePerLiter));
final date = refuel.createdAt;
labels.add(date != null ? '${date.month}/${date.day}' : '');
}
return LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: spots,
isCurved: true,
barWidth: 3,
color: Theme.of(context).colorScheme.primary,
dotData: const FlDotData(show: true),
)
],
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.black87,
tooltipMargin: 40,
fitInsideHorizontally: true,
fitInsideVertically: true,
getTooltipItems: (spots) => spots
.map((s) => LineTooltipItem(
s.y.toStringAsFixed(2),
const TextStyle(color: Colors.white)))
.toList(),
),
),
titlesData: FlTitlesData(
leftTitles: AxisTitles(
axisNameSize: 28,
axisNameWidget: const Padding(
padding: EdgeInsets.only(right: 8),
child: Text('Price/L'),
),
sideTitles: SideTitles(
showTitles: true,
reservedSize: 50,
getTitlesWidget: (value, meta) => Padding(
padding: const EdgeInsets.only(right: 4),
child: Text(value.toStringAsFixed(1),
style: const TextStyle(fontSize: 10)),
),
),
),
bottomTitles: AxisTitles(
axisNameSize: 24,
axisNameWidget: const Padding(
padding: EdgeInsets.only(top: 8),
child: Text('Date'),
),
sideTitles: SideTitles(
showTitles: true,
reservedSize: 36,
getTitlesWidget: (value, meta) {
final index = value.toInt();
if (index < 0 || index >= labels.length) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(labels[index],
style: const TextStyle(fontSize: 10)),
);
},
),
),
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
gridData: const FlGridData(show: false),
borderData: FlBorderData(show: false),
),
);
}
}

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
class StatCard extends StatelessWidget {
final String title;
final String value;
const StatCard({super.key, required this.title, required this.value});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
value,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 2),
Text(title, textAlign: TextAlign.center),
],
),
),
);
}
}