diff --git a/lib/screens/main_shell.dart b/lib/screens/main_shell.dart index 941136e..bda3d28 100644 --- a/lib/screens/main_shell.dart +++ b/lib/screens/main_shell.dart @@ -5,6 +5,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import '../services/odoo_service.dart'; import '../services/notification_service.dart'; import '../services/theme_manager.dart'; +import '../widgets/restaurant_background.dart'; import 'notifications_screen.dart'; import 'loyalty_dashboard.dart'; import 'branches_screen.dart'; @@ -201,9 +202,11 @@ class _MainShellState extends State { ], ), ), - child: IndexedStack( - index: _currentIndex, - children: _pages, + child: RestaurantBackground( + child: IndexedStack( + index: _currentIndex, + children: _pages, + ), ), ), bottomNavigationBar: NavigationBar( diff --git a/lib/screens/orders_screen.dart b/lib/screens/orders_screen.dart index 0aad784..f67ff74 100644 --- a/lib/screens/orders_screen.dart +++ b/lib/screens/orders_screen.dart @@ -80,10 +80,14 @@ class _OrdersScreenState extends State { final theme = Theme.of(context); if (_isLoading) { - return const Scaffold(body: Center(child: CircularProgressIndicator())); + return const Scaffold( + backgroundColor: Colors.transparent, + body: Center(child: CircularProgressIndicator()), + ); } return Scaffold( + backgroundColor: Colors.transparent, appBar: AppBar(title: const Text('Order & Points History')), body: RefreshIndicator( onRefresh: _fetchHistory, diff --git a/lib/widgets/restaurant_background.dart b/lib/widgets/restaurant_background.dart new file mode 100644 index 0000000..6a27a6e --- /dev/null +++ b/lib/widgets/restaurant_background.dart @@ -0,0 +1,280 @@ +import 'dart:math' as math; +import 'package:flutter/material.dart'; + +/// A custom background wrapper that renders a highly premium, subtle +/// vector pattern of noodle bowls, wavy noodles, chopsticks, and spices (star anise/leaves) +/// watermark in the background of the screen. +class RestaurantBackground extends StatelessWidget { + final Widget child; + + const RestaurantBackground({super.key, required this.child}); + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + return Stack( + children: [ + Positioned.fill( + child: CustomPaint( + painter: NoodlePatternPainter( + color: colorScheme.onSurface.withValues(alpha: 0.08), + ), + ), + ), + child, + ], + ); + } +} + +class NoodlePatternPainter extends CustomPainter { + final Color color; + + NoodlePatternPainter({required this.color}); + + @override + void paint(Canvas canvas, Size size) { + // Use a fixed-seed Random generator so coordinates remain perfectly stable + // on every repaint (preventing elements from flickering/moving). + final random = math.Random(5758); + + // Jittered grid parameters adjusted for larger scales + const double stepX = 145.0; + const double stepY = 145.0; + + int index = 0; + for (double y = 40; y < size.height; y += stepY) { + final double startX = (index % 2 == 0) ? 35.0 : 100.0; + for (double x = startX; x < size.width; x += stepX) { + // Apply random jitter of up to +/- 30 pixels to x and y coordinates + final double jitterX = (random.nextDouble() - 0.5) * 60.0; + final double jitterY = (random.nextDouble() - 0.5) * 60.0; + final double drawX = x + jitterX; + final double drawY = y + jitterY; + + // Skip drawing if the jittered offset pushes it outside the screen + if (drawX < 0 || + drawX > size.width || + drawY < 0 || + drawY > size.height) { + continue; + } + + // Random rotation between -0.6 and +0.6 radians + final double rotation = (random.nextDouble() - 0.5) * 1.2; + + // Random scale factor enlarged to range between 1.1x and 1.5x + final double scale = 1.1 + random.nextDouble() * 0.4; + + // Randomize the element's opacity slightly relative to the base color + final double alphaScale = 0.6 + random.nextDouble() * 0.8; + final elementColor = color.withValues( + alpha: (color.alpha / 255.0 * alphaScale).clamp(0.02, 0.15), + ); + + final paint = Paint() + ..color = elementColor + ..style = PaintingStyle.stroke + ..strokeWidth = 1.0 + ..strokeCap = StrokeCap.round; + + final fillPaint = Paint() + ..color = elementColor + ..style = PaintingStyle.fill; + + // Randomly select one of the 3 restaurant/noodle categories to draw + final int elementIndex = random.nextInt(3); + + canvas.save(); + canvas.translate(drawX, drawY); + canvas.rotate(rotation); + canvas.scale(scale); + + if (elementIndex == 0) { + _drawBowl(canvas, paint); + } else if (elementIndex == 1) { + _drawDrumstick(canvas, paint, fillPaint); + } else { + final vegIndex = random.nextInt(5); + if (vegIndex == 0) { + _drawMushroom(canvas, paint, fillPaint); + } else if (vegIndex == 1) { + _drawCarrot(canvas, paint, fillPaint); + } else if (vegIndex == 2) { + _drawBroccoli(canvas, paint, fillPaint); + } else if (vegIndex == 3) { + _drawChili(canvas, paint, fillPaint); + } else { + _drawTomato(canvas, paint, fillPaint); + } + } + + canvas.restore(); + } + index++; + } + } + + void _drawBowl(Canvas canvas, Paint paint) { + // Draw a noodle bowl outline + final path = Path() + ..moveTo(-12, -4) + ..arcTo(Rect.fromLTWH(-12, -10, 24, 18), 0, 3.14159, false) + ..lineTo(-12, -4) + ..close(); + canvas.drawPath(path, paint); + + // Rim lines + canvas.drawLine(const Offset(-13, -4), const Offset(13, -4), paint); + + // Steam/Noodles rising + final steam = Path() + ..moveTo(-5, -6) + ..quadraticBezierTo(-7, -10, -5, -15) + ..moveTo(0, -6) + ..quadraticBezierTo(-2, -11, 0, -16) + ..moveTo(5, -6) + ..quadraticBezierTo(3, -10, 5, -15); + canvas.drawPath(steam, paint); + } + + void _drawDrumstick(Canvas canvas, Paint paint, Paint fillPaint) { + // Plump cartoon-style chicken drumstick with asymmetric meaty bulge + final path = Path() + // Bone shaft left + ..moveTo(-1.5, 3) + ..lineTo(-1.5, 9) + // Left bone joint knob + ..cubicTo(-3.5, 9, -4.5, 11.5, -2.5, 13.5) + ..cubicTo(-1.0, 14.5, 0.0, 12.0, 0.0, 11.0) + // Right bone joint knob + ..cubicTo(0.0, 12.0, 1.0, 14.5, 2.5, 13.5) + ..cubicTo(4.5, 11.5, 3.5, 9, 1.5, 9) + // Bone shaft right + ..lineTo(1.5, 3) + // Taper out to meaty part + ..lineTo(5.5, 0) + // Asymmetric bulbous meat bulge (wide to the right, flatter on the left) + ..cubicTo(12.0, -3.5, 8.5, -12, 0, -12) + ..cubicTo(-6.0, -12, -7.0, -3.5, -5.5, 0) + ..close(); + + canvas.drawPath(path, paint); + canvas.drawPath(path, fillPaint); + } + + void _drawChili(Canvas canvas, Paint paint, Paint fillPaint) { + canvas.save(); + canvas.rotate(0.3); // Slight tilt for organic look + final body = Path() + ..moveTo(-3, -7) + ..quadraticBezierTo(2, -7, 4, -3) + ..quadraticBezierTo(5, 3, -4, 9) // Pointy pepper tip + ..quadraticBezierTo(-3, 2, -3, -7) + ..close(); + canvas.drawPath(body, paint); + canvas.drawPath(body, fillPaint); + + // Stem at the top + final stem = Path() + ..moveTo(0, -7) + ..quadraticBezierTo(1, -12, -3, -13); + canvas.drawPath(stem, paint); + canvas.restore(); + } + + void _drawTomato(Canvas canvas, Paint paint, Paint fillPaint) { + // Round tomato body + final body = Path() + ..addOval( + Rect.fromCenter(center: const Offset(0, 1), width: 14, height: 12), + ); + canvas.drawPath(body, paint); + canvas.drawPath(body, fillPaint); + + // Star-shaped leafy top + final leaves = Path() + ..moveTo(0, -5) + ..lineTo(-2, -8) + ..moveTo(0, -5) + ..lineTo(2, -8) + ..moveTo(0, -5) + ..lineTo(0, -9) + ..moveTo(0, -5) + ..quadraticBezierTo(-1, -7, -3.5, -6) + ..moveTo(0, -5) + ..quadraticBezierTo(1, -7, 3.5, -6); + canvas.drawPath(leaves, paint); + } + + void _drawMushroom(Canvas canvas, Paint paint, Paint fillPaint) { + // Cap + final cap = Path() + ..moveTo(-9, 0) + ..arcTo(Rect.fromLTWH(-9, -8, 18, 11), 3.14159, 3.14159, false) + ..close(); + canvas.drawPath(cap, paint); + canvas.drawPath(cap, fillPaint); + + // Stalk + final stalk = Path() + ..moveTo(-3, 0) + ..lineTo(-3, 6) + ..quadraticBezierTo(0, 8, 3, 6) + ..lineTo(3, 0) + ..close(); + canvas.drawPath(stalk, paint); + canvas.drawPath(stalk, fillPaint); + } + + void _drawCarrot(Canvas canvas, Paint paint, Paint fillPaint) { + canvas.save(); + canvas.rotate(-0.785); // Point carrot downwards + + // Carrot cone root body + final root = Path() + ..moveTo(-4, -6) + ..lineTo(4, -6) + ..lineTo(0, 9) // tip + ..close(); + canvas.drawPath(root, paint); + canvas.drawPath(root, fillPaint); + + // Leaves at the top + final leaves = Path() + ..moveTo(-2, -6) + ..quadraticBezierTo(-4, -12, -6, -10) + ..moveTo(0, -6) + ..quadraticBezierTo(0, -14, 2, -12) + ..moveTo(2, -6) + ..quadraticBezierTo(4, -11, 6, -9); + canvas.drawPath(leaves, paint); + + canvas.restore(); + } + + void _drawBroccoli(Canvas canvas, Paint paint, Paint fillPaint) { + // Stem + final stem = Path() + ..moveTo(-2.5, 2) + ..lineTo(-2.5, 8) + ..quadraticBezierTo(0, 10, 2.5, 8) + ..lineTo(2.5, 2) + ..close(); + canvas.drawPath(stem, paint); + canvas.drawPath(stem, fillPaint); + + // Crown cloud shape + final crown = Path() + ..moveTo(-7, 2) + ..cubicTo(-11, 2, -11, -5, -5, -5) + ..cubicTo(-5, -11, 5, -11, 5, -5) + ..cubicTo(11, -5, 11, 2, 7, 2) + ..close(); + canvas.drawPath(crown, paint); + canvas.drawPath(crown, fillPaint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +}