100 lines
5.1 KiB
Dart
100 lines
5.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:fl_chart/fl_chart.dart';
|
|
import '../../../../constant/finance_design_system.dart';
|
|
import '../../../../controller/home/statistics/statistics_controller.dart';
|
|
|
|
class MonthlyChartWidget extends StatelessWidget {
|
|
const MonthlyChartWidget({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GetBuilder<StatisticsController>(
|
|
builder: (sc) {
|
|
return Container(
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
|
|
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4))],
|
|
),
|
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
|
Text('Monthly Report'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)),
|
|
const SizedBox(height: 16),
|
|
// Summary Row
|
|
Row(children: [
|
|
_summaryTile('Total Earnings'.tr, '${sc.monthlyTotalEarnings.toStringAsFixed(0)} ${'SYP'.tr}', FinanceDesignSystem.successGreen),
|
|
const SizedBox(width: 12),
|
|
_summaryTile('Total Trips'.tr, '${sc.monthlyTotalTrips}', FinanceDesignSystem.accentBlue),
|
|
const SizedBox(width: 12),
|
|
_summaryTile('Best Day'.tr, '${sc.bestDay}', const Color(0xFFFFD700)),
|
|
]),
|
|
const SizedBox(height: 20),
|
|
// Monthly Earnings Line Chart
|
|
SizedBox(
|
|
height: 200,
|
|
child: sc.monthlyEarnings.isEmpty
|
|
? Center(child: Text('No data yet'.tr, style: TextStyle(color: Colors.grey.shade400)))
|
|
: LineChart(LineChartData(
|
|
lineTouchData: LineTouchData(
|
|
enabled: true,
|
|
touchTooltipData: LineTouchTooltipData(
|
|
getTooltipItems: (spots) => spots.map((s) => LineTooltipItem(
|
|
'${s.y.toStringAsFixed(0)} ${'SYP'.tr}',
|
|
const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12),
|
|
)).toList(),
|
|
),
|
|
),
|
|
gridData: FlGridData(show: true, drawVerticalLine: false,
|
|
getDrawingHorizontalLine: (v) => FlLine(color: Colors.grey.shade100, strokeWidth: 1),
|
|
),
|
|
titlesData: FlTitlesData(
|
|
bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, interval: 5,
|
|
getTitlesWidget: (v, m) => Padding(padding: const EdgeInsets.only(top: 8),
|
|
child: Text('${v.toInt()}', style: TextStyle(fontSize: 10, color: Colors.grey.shade500)),
|
|
),
|
|
)),
|
|
leftTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
),
|
|
borderData: FlBorderData(show: false),
|
|
lineBarsData: [
|
|
LineChartBarData(
|
|
spots: sc.monthlyEarnings.map((e) => FlSpot(e.day.toDouble(), e.pricePerDay)).toList(),
|
|
isCurved: true, curveSmoothness: 0.3,
|
|
color: FinanceDesignSystem.accentBlue, barWidth: 3,
|
|
dotData: FlDotData(show: true, getDotPainter: (s, p, d, i) =>
|
|
FlDotCirclePainter(radius: 3, color: FinanceDesignSystem.accentBlue, strokeWidth: 1, strokeColor: Colors.white),
|
|
),
|
|
belowBarData: BarAreaData(
|
|
show: true,
|
|
gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter,
|
|
colors: [FinanceDesignSystem.accentBlue.withOpacity(0.2), FinanceDesignSystem.accentBlue.withOpacity(0.0)],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
)),
|
|
),
|
|
]),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _summaryTile(String label, String value, Color color) {
|
|
return Expanded(
|
|
child: Container(
|
|
padding: const EdgeInsets.all(10),
|
|
decoration: BoxDecoration(color: color.withOpacity(0.08), borderRadius: BorderRadius.circular(12)),
|
|
child: Column(children: [
|
|
Text(value, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: color)),
|
|
const SizedBox(height: 2),
|
|
Text(label, style: TextStyle(fontSize: 9, color: Colors.grey.shade600), textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis),
|
|
]),
|
|
),
|
|
);
|
|
}
|
|
}
|