import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/auth_provider.dart'; import '../providers/dashboard_provider.dart'; import '../providers/mark_list_provider.dart'; import 'mark_list_screen.dart'; class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); @override State createState() => _DashboardScreenState(); } class _DashboardScreenState extends State with TickerProviderStateMixin { late AnimationController _scaleCtrl; late AnimationController _shineCtrl; @override void initState() { super.initState(); _scaleCtrl = AnimationController( vsync: this, duration: const Duration(milliseconds: 1200), lowerBound: 0.97, upperBound: 1.0, )..repeat(reverse: true); _shineCtrl = AnimationController( vsync: this, duration: const Duration(seconds: 2), )..repeat(); WidgetsBinding.instance.addPostFrameCallback((_) async { final auth = Provider.of(context, listen: false); final dash = Provider.of(context, listen: false); dash.init(context); await dash.loadSummary(context); final marks = Provider.of(context, listen: false); marks.init(context); await marks.loadMarks(context); }); } @override void dispose() { _scaleCtrl.dispose(); _shineCtrl.dispose(); super.dispose(); } // ============================================================ // CENTERED ADD MARK POPUP // ============================================================ void _showAddMarkForm(double scale) { final markCtrl = TextEditingController(); final originCtrl = TextEditingController(); final destCtrl = TextEditingController(); showDialog( context: context, barrierDismissible: true, builder: (_) { return Center( child: Material( color: Colors.transparent, child: Container( width: MediaQuery.of(context).size.width * 0.88, padding: EdgeInsets.all(20 * scale), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20 * scale), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 16, offset: const Offset(0, 6), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( "Add Mark No", style: TextStyle( fontSize: 20 * scale, fontWeight: FontWeight.bold, color: Colors.indigo, ), ), SizedBox(height: 18 * scale), _inputField(markCtrl, "Mark No", scale), SizedBox(height: 12 * scale), _inputField(originCtrl, "Origin", scale), SizedBox(height: 12 * scale), _inputField(destCtrl, "Destination", scale), SizedBox(height: 22 * scale), SizedBox( width: double.infinity, child: DecoratedBox( decoration: BoxDecoration( gradient: const LinearGradient( colors: [Colors.indigo, Colors.deepPurple], ), borderRadius: BorderRadius.circular(12 * scale), ), child: ElevatedButton( onPressed: () async { final mark = markCtrl.text.trim(); final origin = originCtrl.text.trim(); final dest = destCtrl.text.trim(); if (mark.isEmpty || origin.isEmpty || dest.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("All fields are required")), ); return; } final provider = Provider.of(context, listen: false); final res = await provider.addMark(context, mark, origin, dest); if (res['success'] == true) { await Provider.of(context, listen: false) .loadMarks(context); Navigator.pop(context); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(res['message'] ?? "Failed")), ); } }, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: EdgeInsets.symmetric(vertical: 14 * scale), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12 * scale), ), ), child: Text( "Submit", style: TextStyle( fontSize: 16 * scale, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), ), SizedBox(height: 6 * scale), ], ), ), ), ); }, ); } // ============================================================ // MAIN UI (Responsive) // ============================================================ @override Widget build(BuildContext context) { final auth = Provider.of(context); final dash = Provider.of(context); final marks = Provider.of(context); final name = auth.user?['customer_name'] ?? "User"; final width = MediaQuery.of(context).size.width; final scale = (width / 430).clamp(0.88, 1.08); return SingleChildScrollView( padding: EdgeInsets.all(16 * scale), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // WELCOME CARD WITH ANIMATION AnimatedBuilder( animation: _scaleCtrl, builder: (_, __) { return Transform.scale( scale: _scaleCtrl.value, child: Stack( children: [ Container( padding: EdgeInsets.all(20 * scale), width: double.infinity, decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFFFFA726), Color(0xFFFFEB3B)], ), borderRadius: BorderRadius.circular(18 * scale), ), child: Text( "Welcome, $name 👋", style: TextStyle( fontSize: 24 * scale, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), // Shine Animation AnimatedBuilder( animation: _shineCtrl, builder: (_, __) { final left = _shineCtrl.value * (MediaQuery.of(context).size.width + 140) - 140; return Positioned( left: left, top: -40 * scale, bottom: -40 * scale, child: Transform.rotate( angle: -0.45, child: Container( width: 120 * scale, decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.white.withOpacity(0), Colors.white.withOpacity(.3), Colors.white.withOpacity(0), ], ), ), ), ), ); }, ) ], ), ); }, ), SizedBox(height: 18 * scale), _summarySection( dash, rawAmount: "₹${dash.totalRaw ?? 0}", scale: scale, ), SizedBox(height: 26 * scale), // MARK LIST CARD Container( padding: EdgeInsets.all(16 * scale), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(14 * scale), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(.06), blurRadius: 8 * scale, ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Add Mark Button Center( child: SizedBox( width: width * 0.95, child: DecoratedBox( decoration: BoxDecoration( gradient: const LinearGradient( colors: [Colors.indigo, Colors.deepPurple], ), borderRadius: BorderRadius.circular(12 * scale), ), child: ElevatedButton( onPressed: () => _showAddMarkForm(scale), style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: EdgeInsets.symmetric(vertical: 14 * scale), ), child: Text( "Add Mark No", style: TextStyle( fontSize: 16 * scale, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), ), ), SizedBox(height: 16 * scale), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Latest Mark Numbers", style: TextStyle( fontSize: 18 * scale, fontWeight: FontWeight.bold, ), ), if (marks.marks.isNotEmpty) GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (_) => const MarkListScreen()), ); }, child: Text( "View All →", style: TextStyle( fontSize: 15 * scale, color: Colors.indigo, fontWeight: FontWeight.bold, ), ), ), ], ), SizedBox(height: 12 * scale), // Scrollable Mark List SizedBox( height: 300 * scale, child: Scrollbar( thumbVisibility: true, child: ListView.builder( padding: EdgeInsets.zero, itemCount: marks.marks.length, itemBuilder: (context, i) => _markTile(marks.marks[i], scale), ), ), ), ], ), ), SizedBox(height: 40 * scale), ], ), ); } // ============================================================ // SUMMARY SECTION // ============================================================ Widget _summarySection(dash, {required String rawAmount, required double scale}) { return Container( padding: EdgeInsets.all(14 * scale), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(14 * scale), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(.06), blurRadius: 8 * scale, ), ], ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _summaryTile("Active Orders", dash.activeOrders ?? 0, Colors.blue, Icons.inventory, scale), _summaryTile("In Transit", dash.inTransitOrders ?? 0, Colors.orange, Icons.local_shipping, scale), ], ), SizedBox(height: 12 * scale), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _summaryTile("Delivered", dash.deliveredOrders ?? 0, Colors.green, Icons.check_circle, scale), _summaryTile("Total Value", "₹${dash.totalValue ?? 0}", Colors.teal, Icons.money, scale), ], ), SizedBox(height: 16 * scale), _rawAmountTile("Raw Amount", rawAmount, scale), ], ), ); } Widget _summaryTile(String title, dynamic value, Color color, IconData icon, double scale) { return Container( width: MediaQuery.of(context).size.width * 0.41, padding: EdgeInsets.all(14 * scale), decoration: BoxDecoration( color: color.withOpacity(.12), borderRadius: BorderRadius.circular(14 * scale), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( value.toString(), style: TextStyle( fontSize: 20 * scale, fontWeight: FontWeight.bold, color: color, ), ), SizedBox(height: 2 * scale), SizedBox( width: 100 * scale, child: Text( title, style: TextStyle( fontSize: 13 * scale, fontWeight: FontWeight.w600, ), ), ), ], ), Icon(icon, size: 28 * scale, color: color), ], ), ); } Widget _rawAmountTile(String title, String value, double scale) { return Container( padding: EdgeInsets.all(14 * scale), decoration: BoxDecoration( color: Colors.deepPurple.shade50, borderRadius: BorderRadius.circular(14 * scale), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( value, style: TextStyle( fontSize: 20 * scale, color: Colors.deepPurple, fontWeight: FontWeight.bold, ), ), Text( title, style: TextStyle( fontSize: 13 * scale, color: Colors.grey, ), ), ], ), Icon(Icons.currency_rupee, size: 28 * scale, color: Colors.deepPurple), ], ), ); } // ============================================================ // MARK TILE // ============================================================ Widget _markTile(dynamic m, double scale) { return Container( margin: EdgeInsets.only(bottom: 12 * scale), padding: EdgeInsets.all(14 * scale), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF42A5F5), Color(0xFF80DEEA)], ), borderRadius: BorderRadius.circular(14 * scale), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( m['mark_no'], style: TextStyle( fontSize: 18 * scale, color: Colors.white, fontWeight: FontWeight.bold, ), ), Text( "${m['origin']} → ${m['destination']}", style: TextStyle( fontSize: 14 * scale, color: Colors.white, ), ), ], ), Container( padding: EdgeInsets.symmetric( horizontal: 10 * scale, vertical: 6 * scale, ), decoration: BoxDecoration( color: Colors.white.withOpacity(.2), borderRadius: BorderRadius.circular(8 * scale), ), child: Text( m['status'], style: TextStyle( fontSize: 12 * scale, color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ], ), ); } // ============================================================ // INPUT FIELD // ============================================================ Widget _inputField(TextEditingController controller, String label, double scale) { return TextField( controller: controller, style: TextStyle(fontSize: 15 * scale), decoration: InputDecoration( labelText: label, labelStyle: TextStyle(fontSize: 14 * scale), filled: true, fillColor: Colors.lightBlue.shade50, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12 * scale), borderSide: BorderSide.none, ), contentPadding: EdgeInsets.symmetric(horizontal: 14 * scale, vertical: 14 * scale), ), ); } }