155 lines
6.2 KiB
Dart
155 lines
6.2 KiB
Dart
import 'package:fl_chart/fl_chart.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import '../services/hydration_service.dart';
|
|
import '../widgets/glass_card.dart';
|
|
|
|
class StatsScreen extends StatelessWidget {
|
|
const StatsScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final service = context.watch<HydrationService>();
|
|
final history = service.history;
|
|
final color = service.dynamicWaterColor;
|
|
|
|
return Scaffold(
|
|
body: SafeArea(
|
|
child: ListView(
|
|
padding: const EdgeInsets.all(24.0),
|
|
children: [
|
|
Text(
|
|
"Insights",
|
|
style: GoogleFonts.montserrat(fontSize: 28, fontWeight: FontWeight.bold)
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
Row(
|
|
children: [
|
|
_buildMetricCard("Streak", "5 Days", Icons.local_fire_department, Colors.orange),
|
|
const SizedBox(width: 12),
|
|
_buildMetricCard("Avg", "1.8 L", Icons.water, Colors.blue),
|
|
const SizedBox(width: 12),
|
|
_buildMetricCard("Goal", "90%", Icons.check_circle, Colors.green),
|
|
],
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
Text("Intake Breakdown", style: GoogleFonts.montserrat(fontSize: 16, fontWeight: FontWeight.w600)),
|
|
const SizedBox(height: 12),
|
|
GlassCard(
|
|
child: Column(
|
|
children: [
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.circular(10),
|
|
child: SizedBox(
|
|
height: 12,
|
|
child: Row(
|
|
children: service.breakdown.entries.map((entry) {
|
|
if (entry.value == 0) return const SizedBox.shrink();
|
|
final flex = (entry.value * 10).toInt();
|
|
return Expanded(
|
|
flex: flex == 0 ? 1 : flex,
|
|
child: Container(color: entry.key.color),
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: service.breakdown.entries.where((e) => e.value > 0).map((entry) {
|
|
return Row(
|
|
children: [
|
|
Container(width: 8, height: 8, decoration: BoxDecoration(color: entry.key.color, shape: BoxShape.circle)),
|
|
const SizedBox(width: 6),
|
|
Text(entry.key.label, style: GoogleFonts.lato(fontSize: 12, color: Colors.grey.shade700)),
|
|
],
|
|
);
|
|
}).toList(),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
Text("Weekly Overview", style: GoogleFonts.montserrat(fontSize: 16, fontWeight: FontWeight.w600)),
|
|
const SizedBox(height: 12),
|
|
AspectRatio(
|
|
aspectRatio: 1.5,
|
|
child: GlassCard(
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(right: 16, top: 16, bottom: 0),
|
|
child: BarChart(
|
|
BarChartData(
|
|
gridData: const FlGridData(show: false),
|
|
titlesData: FlTitlesData(
|
|
show: true,
|
|
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
leftTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
bottomTitles: AxisTitles(
|
|
sideTitles: SideTitles(
|
|
showTitles: true,
|
|
getTitlesWidget: (value, meta) {
|
|
const days = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
|
|
if (value.toInt() < days.length) {
|
|
return Text(days[value.toInt()], style: GoogleFonts.lato(fontSize: 10, color: Colors.grey));
|
|
}
|
|
return const SizedBox();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
borderData: FlBorderData(show: false),
|
|
barGroups: history.asMap().entries.map((e) {
|
|
return BarChartGroupData(
|
|
x: e.key,
|
|
barRods: [
|
|
BarChartRodData(
|
|
toY: e.value,
|
|
color: e.value >= service.dailyGoal ? color : color.withOpacity(0.5),
|
|
width: 12,
|
|
borderRadius: BorderRadius.circular(6),
|
|
backDrawRodData: BackgroundBarChartRodData(
|
|
show: true,
|
|
toY: 4000,
|
|
color: Colors.grey.withOpacity(0.1),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 80),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildMetricCard(String title, String value, IconData icon, Color color) {
|
|
return Expanded(
|
|
child: GlassCard(
|
|
padding: const EdgeInsets.all(12),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Icon(icon, size: 20, color: color),
|
|
const SizedBox(height: 8),
|
|
Text(value, style: GoogleFonts.montserrat(fontSize: 18, fontWeight: FontWeight.bold)),
|
|
Text(title, style: GoogleFonts.lato(fontSize: 12, color: Colors.grey.shade600)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|