import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart' as intl; import 'dart:math'; import '../model/reading.dart'; class ReadingGraph extends StatelessWidget { const ReadingGraph({super.key, required List readings}) : _readings = readings; final List _readings; @override Widget build(BuildContext context) { final spots = _readings .map( (e) => FlSpot( e.dateTime.millisecondsSinceEpoch.toDouble() / 1000 / 60, e.value), ) .toList(); return LineChart( LineChartData( maxY: _readings.map((e) => e.value).reduce(max) + 0.05, minY: _readings.map((e) => e.value).reduce(min) - 0.05, lineBarsData: [ LineChartBarData( isCurved: true, color: Theme.of(context).colorScheme.primary, barWidth: 2, isStrokeCapRound: true, dotData: const FlDotData(show: false), spots: _readings .map( (e) => FlSpot( e.dateTime.millisecondsSinceEpoch.toDouble() / 1000 / 60, e.value), ) .toList(), ) ], titlesData: FlTitlesData( bottomTitles: _getBottomTitles(spots), leftTitles: _getLeftTitles(spots), topTitles: const AxisTitles(sideTitles: SideTitles()), rightTitles: const AxisTitles(sideTitles: SideTitles()), ), lineTouchData: LineTouchData( touchTooltipData: LineTouchTooltipData( getTooltipItems: (touchedSpots) { return touchedSpots.map((touchedSpot) { return LineTooltipItem( '${touchedSpot.y.toString()}\n${_getLongDate(touchedSpot.x)}', TextStyle( color: Theme.of(context).colorScheme.onPrimary, fontWeight: FontWeight.bold)); }).toList(); }, ), ), ), ); } AxisTitles _getBottomTitles(List spots) { return AxisTitles( sideTitles: SideTitles( interval: 90, reservedSize: 40, showTitles: true, maxIncluded: false, minIncluded: false, getTitlesWidget: (value, meta) => SideTitleWidget( meta: meta, child: Text(_getDate(value)), ), ), ); } AxisTitles _getLeftTitles(List spots) { return AxisTitles( sideTitles: SideTitles( reservedSize: 50, showTitles: true, maxIncluded: false, minIncluded: false, getTitlesWidget: (value, meta) => SideTitleWidget( meta: meta, child: Text(value.toStringAsFixed(2)), ), ), ); } String _getDate(double value) { intl.DateFormat hmFormat = intl.DateFormat('Hm'); return hmFormat.format( DateTime.fromMillisecondsSinceEpoch((value * 1000 * 60).toInt())); } String _getLongDate(double value) { DateTime date = DateTime.fromMillisecondsSinceEpoch((value * 1000 * 60).toInt()); int daysDifference = (DateTime.now().weekday - date.weekday + 7) % 7; if (daysDifference == 0) { return 'Today ${intl.DateFormat('Hm').format(date)}'; } else if (daysDifference == 1) { return 'Yesterday ${intl.DateFormat('Hm').format(date)}'; } return intl.DateFormat('yyyy-MM-dd H:m').format(date); } }