import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import '../../../core/theme/app_colors.dart'; /// Vector shopping-cart illustration drawn in code. /// /// Painting it avoids shipping a raster asset and keeps it crisp on 4K desktop /// displays as well as tablet screens. class WelcomeIllustration extends StatelessWidget { const WelcomeIllustration({super.key, this.size = 240}); final double size; @override Widget build(BuildContext context) { return SizedBox( width: size, height: size, child: CustomPaint(painter: _CartPainter()), ) .animate(onPlay: (c) => c.repeat(reverse: true)) .moveY(begin: 0, end: -8, duration: 2400.ms, curve: Curves.easeInOut); } } class _CartPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final w = size.width; final h = size.height; final unit = w / 100; // Soft backdrop disc. canvas.drawCircle( Offset(w * 0.5, h * 0.5), w * 0.46, Paint()..color = AppColors.primarySurface, ); // Decorative arc. canvas.drawArc( Rect.fromCircle(center: Offset(w * 0.5, h * 0.5), radius: w * 0.46), -1.1, 2.0, false, Paint() ..color = AppColors.primaryBorder ..style = PaintingStyle.stroke ..strokeWidth = unit * 1.6 ..strokeCap = StrokeCap.round, ); final stroke = Paint() ..color = AppColors.primary ..style = PaintingStyle.stroke ..strokeWidth = unit * 3 ..strokeCap = StrokeCap.round ..strokeJoin = StrokeJoin.round; final fill = Paint()..color = AppColors.primary.withValues(alpha: 0.16); // Cart basket. final basket = Path() ..moveTo(w * 0.30, h * 0.36) ..lineTo(w * 0.78, h * 0.36) ..lineTo(w * 0.70, h * 0.60) ..lineTo(w * 0.37, h * 0.60) ..close(); canvas.drawPath(basket, fill); canvas.drawPath(basket, stroke); // Handle running to the push bar. canvas.drawPath( Path() ..moveTo(w * 0.16, h * 0.26) ..lineTo(w * 0.24, h * 0.26) ..lineTo(w * 0.30, h * 0.36), stroke, ); // Basket ribs. for (var i = 1; i <= 2; i++) { final t = i / 3; canvas.drawLine( Offset(w * (0.30 + 0.48 * t), h * 0.36), Offset(w * (0.37 + 0.33 * t), h * 0.60), stroke..strokeWidth = unit * 1.6, ); } stroke.strokeWidth = unit * 3; // Wheels. for (final dx in [0.44, 0.66]) { canvas.drawCircle( Offset(w * dx, h * 0.70), unit * 5, Paint()..color = AppColors.surface, ); canvas.drawCircle(Offset(w * dx, h * 0.70), unit * 5, stroke); } // Groceries poking out of the basket. _item(canvas, Offset(w * 0.42, h * 0.30), unit * 5.5, AppColors.tierGold.withValues(alpha: 0.9)); _item(canvas, Offset(w * 0.55, h * 0.27), unit * 6.5, AppColors.success.withValues(alpha: 0.85)); _item(canvas, Offset(w * 0.67, h * 0.31), unit * 5, AppColors.danger.withValues(alpha: 0.75)); // Receipt tape drifting away from the terminal. final receipt = Path() ..moveTo(w * 0.80, h * 0.20) ..lineTo(w * 0.94, h * 0.20) ..lineTo(w * 0.94, h * 0.44) ..lineTo(w * 0.905, h * 0.40) ..lineTo(w * 0.87, h * 0.44) ..lineTo(w * 0.835, h * 0.40) ..lineTo(w * 0.80, h * 0.44) ..close(); canvas.drawPath(receipt, Paint()..color = AppColors.surface); canvas.drawPath( receipt, Paint() ..color = AppColors.primaryLight ..style = PaintingStyle.stroke ..strokeWidth = unit * 1.4 ..strokeJoin = StrokeJoin.round, ); // Receipt lines. final line = Paint() ..color = AppColors.primaryBorder ..strokeWidth = unit * 1.2 ..strokeCap = StrokeCap.round; for (var i = 0; i < 3; i++) { final y = h * (0.25 + i * 0.05); canvas.drawLine(Offset(w * 0.835, y), Offset(w * 0.905, y), line); } } void _item(Canvas canvas, Offset center, double radius, Color color) { canvas.drawCircle(center, radius, Paint()..color = color); canvas.drawCircle( center, radius, Paint() ..color = Colors.white.withValues(alpha: 0.5) ..style = PaintingStyle.stroke ..strokeWidth = 1.5, ); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }