157 lines
4.4 KiB
Dart
157 lines
4.4 KiB
Dart
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;
|
|
}
|