part of 'deliveries.dart'; // ------------------------------------------------------------------------- // DELIVERIES DONE SCREEN // ------------------------------------------------------------------------- class DeliveriesDone extends StatefulWidget { final bool isCancelled; final int bonusPoints; const DeliveriesDone({ super.key, this.isCancelled = false, this.bonusPoints = 0, }); @override State createState() => _DeliveriesDoneState(); } class _DeliveriesDoneState extends State { late ConfettiController _confettiController; final GlobalKey _scratcherKey = GlobalKey(); double _opacity = 0.0; bool _isScratched = false; // Track scratch state @override void initState() { super.initState(); _confettiController = ConfettiController( duration: const Duration(seconds: 3), ); } @override void dispose() { _confettiController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // Check if we should show the scratch card final bool showScratchCard = !widget.isCancelled && widget.bonusPoints > 0; return Scaffold( backgroundColor: Colors.white, body: Stack( children: [ // Main Content SafeArea( child: showScratchCard ? _buildScratchCardContent() : _buildStandardContent(), ), // Confetti Layer (on top) Align( alignment: Alignment.topCenter, child: ConfettiWidget( confettiController: _confettiController, blastDirectionality: BlastDirectionality.explosive, shouldLoop: false, colors: const [ Colors.green, Colors.blue, Colors.pink, Colors.orange, Colors.purple, ], createParticlePath: drawStar, ), ), ], ), ); } Widget _buildStandardContent() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Spacer(), Lottie.asset( widget.isCancelled ? 'assets/lotties/Error Occurred!.json' : 'assets/lotties/result page succes.json', height: 220, repeat: false, errorBuilder: (c, e, s) => Icon( widget.isCancelled ? Icons.cancel : Icons.check_circle, size: 120, color: widget.isCancelled ? Colors.red : Colors.green, ), ), const SizedBox(height: 20), Text( widget.isCancelled ? 'Delivery Cancelled' : 'Delivery Completed!', style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), Text( widget.isCancelled ? 'This order was cancelled.' : 'Great job! Your delivery was successful.', style: const TextStyle(fontSize: 16, color: Colors.grey), textAlign: TextAlign.center, ), const Spacer(), _buildDoneButton(isEnabled: true), ], ); } Widget _buildScratchCardContent() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Spacer(), Text( 'You won a Scratch Card!', style: TextStyle( fontSize: 28, // Increased fontWeight: FontWeight.bold, color: Colors.black, fontFamily: FontConstants.fontFamily, ), ), const SizedBox(height: 12), Text( 'Scratch to reveal your bonus points', style: TextStyle( fontSize: 18, // Increased color: Colors.grey, fontFamily: FontConstants.fontFamily, ), ), const SizedBox(height: 30), Center( child: Container( width: 250, height: 250, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Scratcher( key: _scratcherKey, brushSize: 50, threshold: 50, color: ColorConstants.primaryColor, onChange: (value) { // Optional: haptic feedback or sound while scratching }, onThreshold: () { _confettiController.play(); setState(() { _opacity = 1.0; _isScratched = true; // Enable button }); }, // Custom cover content instead of just solid color image: Image.asset( 'assets/images/nearlelauncher.png', fit: BoxFit.scaleDown, width: 100, // Constrain width so it fits nicely height: 100, ), child: Container( width: 250, height: 250, color: Colors.white, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.monetization_on, size: 80, color: Colors.amber, ), const SizedBox(height: 16), Text( '${widget.bonusPoints}', style: TextStyle( fontSize: 48, fontWeight: FontWeight.bold, color: Colors.black, fontFamily: FontConstants.fontFamily, ), ), Text( 'Points', style: TextStyle( fontSize: 20, fontWeight: FontWeight.w600, color: Colors.grey, fontFamily: FontConstants.fontFamily, ), ), ], ), ), ), ), ), ), const Spacer(), _buildDoneButton(isEnabled: _isScratched), ], ); } Widget _buildDoneButton({required bool isEnabled}) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: SizedBox( width: double.infinity, height: 55, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: isEnabled ? ColorConstants.primaryColor : Colors.grey, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), onPressed: isEnabled ? () { Get.offAll(() => const BottomPage(initialIndex: 1)); } : null, child: const Text( 'Done', style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), ), ), ), ); } Path drawStar(Size size) { // Method to draw star shape for confetti double degToRad(double deg) => deg * (math.pi / 180.0); const numberOfPoints = 5; final halfWidth = size.width / 2; final externalRadius = halfWidth; final internalRadius = halfWidth / 2.5; final degreesPerStep = degToRad(360 / numberOfPoints); final halfDegreesPerStep = degreesPerStep / 2; final path = Path(); final fullAngle = degToRad(360); path.moveTo(size.width, halfWidth); for (double step = 0; step < fullAngle; step += degreesPerStep) { path.lineTo( halfWidth + externalRadius * math.cos(step), halfWidth + externalRadius * math.sin(step), ); path.lineTo( halfWidth + internalRadius * math.cos(step + halfDegreesPerStep), halfWidth + internalRadius * math.sin(step + halfDegreesPerStep), ); } path.close(); return path; } }