import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:bookatanker/supplier/todaysprice/custom_calendar.dart'; import '../../common/settings.dart'; // Contains date picker + filtered graph class GraphScreen extends StatefulWidget { final int selectedType; const GraphScreen({super.key, required this.selectedType}); @override State createState() => _GraphScreenState(); } class _GraphScreenState extends State { List> filteredDrinking = []; List> filteredBore = []; DateTimeRange? selectedRange; @override void initState() { super.initState(); _loadLastWeek(); // Load last week by default } void _loadLastWeek() { DateTime today = DateTime.now(); DateTime lastWeek = today.subtract(const Duration(days: 7)); debugPrint('$lastWeek'); // Update selectedRange so the card shows last week selectedRange = DateTimeRange(start: lastWeek, end: today); _filterData(lastWeek, today); setState(() {}); // trigger rebuild } void _pickDateRange() async { final result = await showDialog( context: context, builder: (context) => AdvancedDateRangePicker( initialRange: selectedRange, ), ); if (result != null) { selectedRange = result; _filterData(result.start, result.end); setState(() { selectedRange = result; // store this for showing in card above graph }); } } void _filterData(DateTime start, DateTime end) { setState(() { filteredDrinking = weeklyPriceData["Drinking Water"]! .where((d) { DateTime date = DateTime.parse(d["date"]); return !date.isBefore(start) && !date.isAfter(end); }).toList(); filteredBore = weeklyPriceData["bore Water"]! .where((d) { DateTime date = DateTime.parse(d["date"]); return !date.isBefore(start) && !date.isAfter(end); }).toList(); }); } void _openDateMenu() { showMenu( context: context, color: Colors.white, elevation: 6, // smooth shadow position: const RelativeRect.fromLTRB(1000, 100, 10, 0), // position near icon items: [ PopupMenuItem( value: "week", child: Text("Last Week", style: fontTextStyle(14, Colors.black, FontWeight.w500), ), ), PopupMenuItem( value: "month", child: Text("Last Month", style: fontTextStyle(14, Colors.black, FontWeight.w500), ), ), PopupMenuItem( value: "custom", child: Text("Custom Dates", style: fontTextStyle(14, Colors.black, FontWeight.w500), ), ), ], ).then((value) { if (value == null) return; if (value == "week") { DateTime today = DateTime.now(); DateTime lastWeek = today.subtract(const Duration(days: 7)); setState(() { selectedRange = DateTimeRange(start: lastWeek, end: today); _filterData(lastWeek, today); }); } else if (value == "month") { DateTime today = DateTime.now(); DateTime lastMonth = DateTime(today.year, today.month - 1, today.day); setState(() { selectedRange = DateTimeRange(start: lastMonth, end: today); _filterData(lastMonth, today); }); } else if (value == "custom") { _pickDateRange(); } }); } // For showing date in card above graph String _formattedDateRange() { if (selectedRange == null) return "Select Date"; final start = selectedRange!.start; final end = selectedRange!.end; const months = [ "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; if (start.month == end.month) { return "${start.day} – ${end.day} ${months[start.month]}"; } else { return "${start.day} ${months[start.month]} – ${end.day} ${months[end.month]}"; } } String _formattedAvgPrice() { List> activeList = widget.selectedType == 0 ? filteredDrinking : filteredBore; debugPrint('$activeList'); if (activeList.isEmpty) return "-"; double total = 0; for (var item in activeList) { total += (item["price"] as num).toDouble(); } double avg = total / activeList.length; return "${avg.toStringAsFixed(2)}"; } @override Widget build(BuildContext context) { return Column( children: [ // 🔥 TOP ROW (LEFT: BOX, RIGHT: CALENDAR) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // LEFT BOX Padding( padding: const EdgeInsets.only(top: 14, left: 10), child: Container( height: 100, width: 180, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 8, spreadRadius: 2, offset: const Offset(2, 4), ), ], ), child: AnimatedSwitcher( duration: const Duration(milliseconds: 350), transitionBuilder: (child, animation) { return FadeTransition( opacity: animation, child: SlideTransition( position: Tween( begin: const Offset(0.2, 0), // Soft slide from right end: Offset.zero, ).animate(animation), child: child, ), ); }, child: Column( key: ValueKey(widget.selectedType), // IMPORTANT 🔑 crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.selectedType == 0 ? "Drinking Water" : "Bore Water", style: fontTextStyle(14, Colors.black, FontWeight.w600), ), const SizedBox(height: 4), Text( _formattedDateRange(), style: fontTextStyle(14, Colors.grey.shade700, FontWeight.w500), ), const SizedBox(height: 4), RichText( text: TextSpan( children: [ TextSpan( text: "${_formattedAvgPrice()} ", style: fontTextStyle(20, Colors.black, FontWeight.bold), ), TextSpan( text: "/5000 L", style: fontTextStyle(14, Colors.grey.shade600, FontWeight.w400), ), ], ), ), ], ), ), ), ), // RIGHT CALENDAR BUTTON Padding( padding: const EdgeInsets.only(top: 4, right: 8), child: InkWell( onTap: () => _openDateMenu(), borderRadius: BorderRadius.circular(10), child: Container( padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.grey.shade300), boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 4, offset: Offset(0, 2), ), ], ), child: Row( children: const [ Icon(Icons.calendar_month, size: 28, color: Colors.blueAccent), Icon(Icons.arrow_drop_down, size: 28, color: Colors.blueAccent), ], ), ), ), ), ], ), const SizedBox(height: 5), // Show graph only if data is available if (filteredDrinking.isNotEmpty || filteredBore.isNotEmpty) Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 10), child: DoublePriceBarGraph( drinkingData: filteredDrinking, boreData: filteredBore, ), ), ) else Padding( padding: EdgeInsets.all(30), child: Text("No data available for the selected dates", style: fontTextStyle(13, Colors.black87, FontWeight.w600), ), ), ], ); } } Widget buildLegend() { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // Drinking Water Legend Row( children: [ Container( width: 14, height: 14, decoration: BoxDecoration( color: Colors.blueAccent, borderRadius: BorderRadius.circular(4), ), ), const SizedBox(width: 6), Text( "Drinking Water", style: fontTextStyle(12, Colors.black87, FontWeight.w600), ), ], ), const SizedBox(width: 20), // Bore Water Legend Row( children: [ Container( width: 14, height: 14, decoration: BoxDecoration( color: Colors.orangeAccent, borderRadius: BorderRadius.circular(4), ), ), const SizedBox(width: 6), Text( "Bore Water", style: fontTextStyle(12, Colors.black87, FontWeight.w600), ), ], ), ], ); } class DoublePriceBarGraph extends StatelessWidget { final List> drinkingData; final List> boreData; const DoublePriceBarGraph({ super.key, required this.drinkingData, required this.boreData, }); @override Widget build(BuildContext context) { final drinkMap = {for (var d in drinkingData) d["date"]: d}; final boreMap = {for (var b in boreData) b["date"]: b}; final allDates = [...drinkMap.keys, ...boreMap.keys].toSet().toList() ..sort((a, b) => DateTime.parse(a).compareTo(DateTime.parse(b))); // FIXED return Row( crossAxisAlignment: CrossAxisAlignment.end, children: allDates.map((date) { final d = drinkMap[date]; final b = boreMap[date]; double drinkPrice = d?["price"]?.toDouble() ?? 0.0; double borePrice = b?["price"]?.toDouble() ?? 0.0; String day = DateTime.parse(date).day.toString(); return Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ // Drinking _buildBar(drinkPrice, Colors.blueAccent), const SizedBox(width: 0), // Bore _buildBar(borePrice, Colors.orangeAccent) ], ), const SizedBox(height: 6), Text(day, style: fontTextStyle(12, Colors.black87, FontWeight.w600)), ], ), ); }).toList(), ); } Widget _buildBar(double price, Color color) { return Column( children: [ Text( "₹${price.toInt()}", style: fontTextStyle(9, color, FontWeight.bold), ), Container( width: 20, height: price / 15, // Adjust scaling if bars too short decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(5), ), ), ], ); } } final Map>> weeklyPriceData = { "Drinking Water": [ { "date": "2025-11-01", "price": 1570, "minPrice": 1550, "maxPrice": 1650, "avgPrice": 1600 }, { "date": "2025-11-02", "price": 1590, "minPrice": 1560, "maxPrice": 1660, "avgPrice": 1610 }, { "date": "2025-11-03", "price": 1550, "minPrice": 1520, "maxPrice": 1600, "avgPrice": 1560 }, { "date": "2025-11-04", "price": 1610, "minPrice": 1580, "maxPrice": 1670, "avgPrice": 1620 }, { "date": "2025-11-05", "price": 1630, "minPrice": 1600, "maxPrice": 1700, "avgPrice": 1650 }, { "date": "2025-11-06", "price": 1580, "minPrice": 1550, "maxPrice": 1650, "avgPrice": 1600 }, { "date": "2025-11-07", "price": 1600, "minPrice": 1580, "maxPrice": 1670, "avgPrice": 1620 }, { "date": "2025-11-08", "price": 1640, "minPrice": 1600, "maxPrice": 1700, "avgPrice": 1650 }, { "date": "2025-11-09", "price": 1620, "minPrice": 1590, "maxPrice": 1680, "avgPrice": 1630 }, { "date": "2025-11-10", "price": 1575, "minPrice": 1550, "maxPrice": 1640, "avgPrice": 1600 }, { "date": "2025-11-11", "price": 1585, "minPrice": 1550, "maxPrice": 1650, "avgPrice": 1605 }, { "date": "2025-11-12", "price": 1615, "minPrice": 1580, "maxPrice": 1670, "avgPrice": 1625 }, { "date": "2025-11-13", "price": 1590, "minPrice": 1560, "maxPrice": 1650, "avgPrice": 1610 }, { "date": "2025-11-14", "price": 1645, "minPrice": 1610, "maxPrice": 1710, "avgPrice": 1660 }, { "date": "2025-11-15", "price": 1625, "minPrice": 1590, "maxPrice": 1680, "avgPrice": 1635 }, { "date": "2025-11-16", "price": 1580, "minPrice": 1550, "maxPrice": 1640, "avgPrice": 1595 }, { "date": "2025-11-17", "price": 1570, "minPrice": 1540, "maxPrice": 1630, "avgPrice": 1580 }, { "date": "2025-11-18", "price": 1600, "minPrice": 1580, "maxPrice": 1660, "avgPrice": 1620 }, { "date": "2025-11-19", "price": 1630, "minPrice": 1600, "maxPrice": 1690, "avgPrice": 1650 }, { "date": "2025-11-20", "price": 1650, "minPrice": 1610, "maxPrice": 1720, "avgPrice": 1670 }, { "date": "2025-11-21", "price": 1610, "minPrice": 1580, "maxPrice": 1670, "avgPrice": 1630 }, { "date": "2025-11-22", "price": 1590, "minPrice": 1560, "maxPrice": 1650, "avgPrice": 1605 }, { "date": "2025-11-23", "price": 1620, "minPrice": 1590, "maxPrice": 1680, "avgPrice": 1630 }, { "date": "2025-11-24", "price": 1670, "minPrice": 1630, "maxPrice": 1730, "avgPrice": 1680 }, { "date": "2025-11-25", "price": 1690, "minPrice": 1650, "maxPrice": 1750, "avgPrice": 1700 }, { "date": "2025-11-26", "price": 1580, "minPrice": 1550, "maxPrice": 1640, "avgPrice": 1600 }, { "date": "2025-11-27", "price": 1600, "minPrice": 1570, "maxPrice": 1670, "avgPrice": 1620 }, { "date": "2025-11-28", "price": 1615, "minPrice": 1580, "maxPrice": 1680, "avgPrice": 1630 }, { "date": "2025-11-29", "price": 1635, "minPrice": 1600, "maxPrice": 1700, "avgPrice": 1650 }, { "date": "2025-11-30", "price": 1605, "minPrice": 1580, "maxPrice": 1670, "avgPrice": 1620 }, ], "bore Water": [ { "date": "2025-11-01", "price": 780, "minPrice": 760, "maxPrice": 810, "avgPrice": 790 }, { "date": "2025-11-02", "price": 800, "minPrice": 780, "maxPrice": 840, "avgPrice": 810 }, { "date": "2025-11-03", "price": 770, "minPrice": 750, "maxPrice": 800, "avgPrice": 780 }, { "date": "2025-11-04", "price": 820, "minPrice": 800, "maxPrice": 850, "avgPrice": 830 }, { "date": "2025-11-05", "price": 830, "minPrice": 810, "maxPrice": 860, "avgPrice": 840 }, { "date": "2025-11-06", "price": 785, "minPrice": 760, "maxPrice": 820, "avgPrice": 795 }, { "date": "2025-11-07", "price": 810, "minPrice": 790, "maxPrice": 840, "avgPrice": 820 }, { "date": "2025-11-08", "price": 825, "minPrice": 800, "maxPrice": 860, "avgPrice": 835 }, { "date": "2025-11-09", "price": 795, "minPrice": 770, "maxPrice": 830, "avgPrice": 810 }, { "date": "2025-11-10", "price": 820, "minPrice": 790, "maxPrice": 860, "avgPrice": 830 }, { "date": "2025-11-11", "price": 810, "minPrice": 780, "maxPrice": 850, "avgPrice": 820 }, { "date": "2025-11-12", "price": 830, "minPrice": 800, "maxPrice": 870, "avgPrice": 840 }, { "date": "2025-11-13", "price": 785, "minPrice": 770, "maxPrice": 820, "avgPrice": 795 }, { "date": "2025-11-14", "price": 750, "minPrice": 730, "maxPrice": 790, "avgPrice": 760 }, { "date": "2025-11-15", "price": 770, "minPrice": 750, "maxPrice": 810, "avgPrice": 780 }, { "date": "2025-11-16", "price": 825, "minPrice": 800, "maxPrice": 870, "avgPrice": 840 }, { "date": "2025-11-17", "price": 840, "minPrice": 820, "maxPrice": 880, "avgPrice": 850 }, { "date": "2025-11-18", "price": 810, "minPrice": 790, "maxPrice": 840, "avgPrice": 820 }, { "date": "2025-11-19", "price": 790, "minPrice": 770, "maxPrice": 830, "avgPrice": 800 }, { "date": "2025-11-20", "price": 830, "minPrice": 800, "maxPrice": 870, "avgPrice": 840 }, { "date": "2025-11-21", "price": 850, "minPrice": 820, "maxPrice": 890, "avgPrice": 860 }, { "date": "2025-11-22", "price": 780, "minPrice": 760, "maxPrice": 810, "avgPrice": 790 }, { "date": "2025-11-23", "price": 790, "minPrice": 770, "maxPrice": 820, "avgPrice": 800 }, { "date": "2025-11-24", "price": 835, "minPrice": 810, "maxPrice": 870, "avgPrice": 845 }, { "date": "2025-11-25", "price": 820, "minPrice": 800, "maxPrice": 860, "avgPrice": 830 }, { "date": "2025-11-26", "price": 760, "minPrice": 740, "maxPrice": 800, "avgPrice": 780 }, { "date": "2025-11-27", "price": 810, "minPrice": 780, "maxPrice": 850, "avgPrice": 820 }, { "date": "2025-11-28", "price": 795, "minPrice": 770, "maxPrice": 830, "avgPrice": 805 }, { "date": "2025-11-29", "price": 835, "minPrice": 810, "maxPrice": 870, "avgPrice": 845 }, { "date": "2025-11-30", "price": 820, "minPrice": 790, "maxPrice": 860, "avgPrice": 830 }, ] };