YSHOP ADMINSTRATION SCREENSHOTS

Costumer Page

Store Owner’s Page

Driver Page

import 'dart:ui';
import 'dart:math' as math;
import 'package:flutter/material.dart';

/// 🎬 ULTRA SLOW CINEMATIC BURGER ASSEMBLY
/// Features: 
/// - HEAVY layer assembly with strict sequencing
/// - Each layer takes its full time
/// - Smooth cross-fade between angles
/// - Products appear ONLY after full6 is 100%
class BurgerAssemblyWidget extends StatefulWidget {
  final ValueNotifier<double> scrollNotifier;
  final double height;
  final String? storeName;
  final VoidCallback? onAssembled;
  final ValueNotifier<double>? welcomeOpacityNotifier;

  const BurgerAssemblyWidget({
    Key? key,
    required this.scrollNotifier,
    this.height = 300,
    this.storeName,
    this.onAssembled,
    this.welcomeOpacityNotifier,
  }) : super(key: key);

  @override
  State<BurgerAssemblyWidget> createState() => _BurgerAssemblyWidgetState();
}

class _BurgerAssemblyWidgetState extends State<BurgerAssemblyWidget>
    with TickerProviderStateMixin {

  // 🎬 ANIMATION CONTROLLERS
  late AnimationController _breathingController;
  late AnimationController _shimmerController;
  late AnimationController _particleController;
  late AnimationController _cameraRotationController;
  late AnimationController _transitionController;
  late List<AnimationController> _layerControllers;

  // 📊 STATE MANAGEMENT
  double _scrollOffset = 0.0;
  double _assemblyProgress = 0.0;
  bool _isAssembled = false;
  bool _isTransitioning = false;
  bool _showFinalBurger = false;
  bool _animationStarted = false;  // ✅ هل بدأت الـ animation
  late ValueNotifier<double> initialWelcomeOpacityNotifier;
  late List<double> _layerProgresses;
  late List<bool> _layerLocked;  // ✅ طبقة مقفلة = انتهت ولا ترجع للخلف
  late List<Particle> _particles;

  // 🎨 LAYER DEFINITIONS
  final List<BurgerLayer> _layers = [
    BurgerLayer(asset: 'assets/images/burger3D/bottom_bun.png', entryAngle: math.pi * 0.25, glowColor: Color(0xFFFFD700), label: 'Golden Base'),
    BurgerLayer(asset: 'assets/images/burger3D/beef_patty.png', entryAngle: -math.pi * 0.3, glowColor: Color(0xFFFF4500), label: 'Fresh Beef'),
    BurgerLayer(asset: 'assets/images/burger3D/cheese_slice.png', entryAngle: math.pi * 0.4, glowColor: Color(0xFFFFA500), label: 'Melted Cheese'),
    BurgerLayer(asset: 'assets/images/burger3D/lettuce.png', entryAngle: -math.pi * 0.2, glowColor: Color(0xFF32CD32), label: 'Fresh Lettuce'),
    BurgerLayer(asset: 'assets/images/burger3D/sauce_layer.png', entryAngle: math.pi * 0.35, glowColor: Color(0xFFFF6347), label: 'Special Sauce'),
    BurgerLayer(asset: 'assets/images/burger3D/top_bun.png', entryAngle: -math.pi * 0.15, glowColor: Color(0xFFFFD700), label: 'Perfect Crown'),
  ];

  @override
  void initState() {
    super.initState();
    initialWelcomeOpacityNotifier = ValueNotifier<double>(1.0);
    _initializeAnimations();
    _initializeParticles();
    widget.scrollNotifier.addListener(_handleScroll);
  }

  void _initializeAnimations() {
    _breathingController = AnimationController(vsync: this, duration: const Duration(milliseconds: 4000))..repeat(reverse: true);
    _shimmerController = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000))..repeat();
    _particleController = AnimationController(vsync: this, duration: const Duration(milliseconds: 2000));
    _cameraRotationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000));
    _transitionController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000));

    _layerControllers = List.generate(_layers.length, (i) => AnimationController(vsync: this, duration: Duration(milliseconds: 2500)));
    _layerProgresses = List.filled(_layers.length, 0.0);
    _layerLocked = List.filled(_layers.length, false);  // ✅ في البداية لا شيء مقفول

    for (int i = 0; i < _layerControllers.length; i++) {
      _layerControllers[i].addListener(() {
        if (mounted) {
          setState(() {
            _layerProgresses[i] = _layerControllers[i].value.clamp(0.0, 1.0);
            _updateAssemblyProgress();
          });
        }
      });
    }
  }

  void _initializeParticles() {
    final random = math.Random();
    _particles = List.generate(14, (i) => Particle(
      x: random.nextDouble() * 2 - 1,
      y: random.nextDouble() * 2 - 1,
      speed: 0.12 + random.nextDouble() * 0.36,
      size: 1.0 + random.nextDouble() * 3.0,
      opacity: 0.4 + random.nextDouble() * 0.4,
      color: _layers[random.nextInt(_layers.length)].glowColor,
    ));
  }

  // ✅ تشغيل الـ animation التلقائية (بدون ربط مع scroll)
  void _startAutomaticAnimation() {
    if (_animationStarted) return;
    _animationStarted = true;

    for (int i = 0; i < _layers.length; i++) {
      // كل طبقة تبدأ بعد انتهاء الطبقة السابقة
      final delayMs = i * 600;  // تأخير 600ms لكل طبقة
      
      Future.delayed(Duration(milliseconds: delayMs), () {
        if (!_isAssembled && mounted) {
          _layerControllers[i].animateTo(1.0, duration: Duration(milliseconds: 600), curve: Curves.easeOutCubic);
          setState(() {
            _layerLocked[i] = true;
          });
        }
      });
    }

    // بعد انتهاء جميع الطبقات (6 * 600 = 3600ms)
    Future.delayed(Duration(milliseconds: 3600 + 200), () {
      if (!_isAssembled && mounted) {
        setState(() {
          _isTransitioning = true;
        });
        // الآن نبدأ الـ fade والبرجر 3D
        _transitionController.animateTo(1.0, duration: Duration(milliseconds: 1000));
      }
    });

    // بعد الـ transition، نشغل camera rotation
    Future.delayed(Duration(milliseconds: 4800), () {
      if (!_isAssembled && mounted) {
        setState(() {
          _showFinalBurger = true;
        });
        _cameraRotationController.animateTo(0.83, duration: Duration(milliseconds: 1500), curve: Curves.easeInOutCubic);
      }
    });

    // full6
    Future.delayed(Duration(milliseconds: 6400), () {
      if (!_isAssembled && mounted) {
        _cameraRotationController.animateTo(1.0, duration: Duration(milliseconds: 800), curve: Curves.easeOutCubic);
      }
    });

    // Products
    Future.delayed(Duration(milliseconds: 7300), () {
      if (!_isAssembled && mounted) {
        setState(() { _isAssembled = true; });
        widget.onAssembled?.call();
      }
    });
  }

  void _handleScroll() {
    if (_isAssembled) return;

    final scroll = widget.scrollNotifier.value;
    
    setState(() {
      _scrollOffset = scroll;
      initialWelcomeOpacityNotifier.value = (1.0 - (scroll / 80.0)).clamp(0.0, 1.0);
      widget.welcomeOpacityNotifier?.value = initialWelcomeOpacityNotifier.value;
    });

    // ✅ أول scroll = ابدأ الـ animation التلقائية
    if (!_animationStarted && scroll > 0) {
      _startAutomaticAnimation();
    }

    // لا نتحكم في الطبقات من خلال scroll، الـ animation تتحكم بكل شيء
  }

  void _updateAssemblyProgress() {
    final avg = _layerProgresses.reduce((a, b) => a + b) / _layerProgresses.length;
    _assemblyProgress = avg.clamp(0.0, 1.0);
  }

  @override
  void dispose() {
    widget.scrollNotifier.removeListener(_handleScroll);
    initialWelcomeOpacityNotifier.dispose();
    _breathingController.dispose();
    _shimmerController.dispose();
    _particleController.dispose();
    _cameraRotationController.dispose();
    _transitionController.dispose();
    for (var c in _layerControllers) c.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: widget.height * 1.8,
      child: Stack(
        alignment: Alignment.center,
        clipBehavior: Clip.none,
        children: [
          _buildBackground(),
          _buildParticleSystem(),
          if (_assemblyProgress < 0.1) _buildInitialWelcomeText(),
          AnimatedBuilder(
            animation: _transitionController,
            builder: (context, child) => Opacity(opacity: 1.0 - _transitionController.value, child: _buildAssemblyView()),
          ),
          if (_showFinalBurger) _build3DBurgerWithCameraRotation(),
          if (_isAssembled) _buildWelcomeText(),
        ],
      ),
    );
  }

  Widget _buildBackground() {
    return AnimatedBuilder(
      animation: _shimmerController,
      builder: (context, child) {
        final intensity = _assemblyProgress < 0.95 ? _assemblyProgress * 0.25 : _assemblyProgress * 0.5;
        return Container(
          width: widget.height * 2,
          height: widget.height * 2,
          decoration: BoxDecoration(
            gradient: RadialGradient(
              colors: [
                Color(0xFF6366F1).withOpacity(0.08 * intensity),
                Color(0xFF8B5CF6).withOpacity(0.04 * intensity),
                Colors.transparent,
              ],
            ),
          ),
          child: CustomPaint(painter: BackgroundPainter(progress: _shimmerController.value, intensity: intensity)),
        );
      },
    );
  }

  Widget _buildParticleSystem() {
    return AnimatedBuilder(
      animation: _particleController,
      builder: (context, child) => CustomPaint(
        size: Size(widget.height * 2, widget.height * 2),
        painter: ParticlePainter(particles: _particles, progress: _particleController.value, assemblyProgress: _assemblyProgress),
      ),
    );
  }

  Widget _buildAssemblyView() {
    return Transform.scale(
      scale: 1.0 + (_assemblyProgress * 0.15),
      child: Stack(
        alignment: Alignment.center,
        children: List.generate(_layers.length, (i) => _buildLayer(i)),
      ),
    );
  }

  Widget _buildLayer(int index) {
    final progress = _layerProgresses[index].clamp(0.0, 1.0);
    final stackOrder = _layers.length - 1 - index;
    final layerThickness = 12.0;
    final totalStackHeight = (_layers.length - 1) * layerThickness;
    final baseTop = -(totalStackHeight / 2);
    final targetY = baseTop + (stackOrder * layerThickness);
    
    final startHeight = 700.0;
    final descendCurve = Curves.easeOutCubic.transform(progress);
    final currentY = startHeight * (1 - descendCurve) + targetY * descendCurve;
    final scale = (0.85 + (progress * 0.15));

    return AnimatedBuilder(
      animation: _breathingController,
      builder: (context, child) {
        final breathOffset = progress >= 0.98 ? math.sin(_breathingController.value * math.pi * 2) * 2.0 : 0.0;
        
        return Transform(
          alignment: Alignment.center,
          transform: Matrix4.identity()..translate(0.0, currentY + breathOffset)..scale(scale),
          child: Stack(
            alignment: Alignment.center,
            children: [
              if (progress > 0.6 && progress < 0.95)
                Container(
                  width: widget.height * 0.7,
                  height: widget.height * 0.7,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    boxShadow: [BoxShadow(color: _layers[index].glowColor.withOpacity(0.08 * (progress - 0.6)), blurRadius: 15 * (progress - 0.6), spreadRadius: 2 * (progress - 0.6))],
                  ),
                ),
              Image.asset(_layers[index].asset, width: widget.height * 1.5, fit: BoxFit.contain),
              
              // Layer label - يظهر فقط عندما تكون الطبقة وحدها
              if (progress >= 0.4 && progress <= 0.65)
              Positioned(
                top: 80,
                right: 20,
                child: AnimatedOpacity(
                  opacity: progress >= 0.4 && progress <= 0.65 ? 1.0 : 0.0,
                  duration: Duration(milliseconds: 200),
                  child: ShaderMask(
                    shaderCallback: (bounds) => LinearGradient(
                      colors: [_layers[index].glowColor, _layers[index].glowColor.withOpacity(0.6)],
                    ).createShader(bounds),
                    child: Text(
                      _layers[index].label,
                      style: TextStyle(
                        fontFamily: 'TenorSans',
                        fontSize: 18,
                        fontWeight: FontWeight.w700,
                        letterSpacing: 2,
                        color: Colors.white,
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  Widget _build3DBurgerWithCameraRotation() {
    final burgerAngles = [
      'assets/images/burger3D/full1.png',
      'assets/images/burger3D/full2.png',
      'assets/images/burger3D/full3.png',
      'assets/images/burger3D/full4.png',
      'assets/images/burger3D/full5.png',
      'assets/images/burger3D/full6.png',
    ];

    return AnimatedBuilder(
      animation: Listenable.merge([_breathingController, _cameraRotationController, _transitionController]),
      builder: (context, child) {
        final rotation = Curves.easeInOutCubic.transform(_cameraRotationController.value);
        final breathScale = 1.0 + (math.sin(_breathingController.value * math.pi * 2) * 0.015);
        final floatY = math.sin(_breathingController.value * math.pi * 2) * 5.0;
        final fadeIn = Curves.easeOut.transform(_transitionController.value);

        return Opacity(
          opacity: fadeIn,
          child: Transform.translate(
            offset: Offset(0, floatY - 50),
            child: Transform.scale(
              scale: breathScale,
              child: Stack(
                alignment: Alignment.center,
                children: [
                  Container(
                    width: widget.height * 1.0,
                    height: widget.height * 1.0,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      gradient: RadialGradient(
                        colors: [
                          Color(0xFFFF6B35).withOpacity(0.15 * rotation),
                          Color(0xFFFFC837).withOpacity(0.08 * rotation),
                          Colors.transparent,
                        ],
                      ),
                      boxShadow: [BoxShadow(color: Color(0xFFFF6B35).withOpacity(0.2 * rotation), blurRadius: 40, spreadRadius: 5)],
                    ),
                  ),
                  ...List.generate(burgerAngles.length, (i) => _buildBurgerAngleLayer(burgerAngles[i], i, burgerAngles.length, rotation)),
                  if (rotation > 0.85)
                    CustomPaint(
                      size: Size(widget.height * 2, widget.height * 2),
                      painter: LightRayPainter(progress: _breathingController.value, intensity: (rotation - 0.85) / 0.15),
                    ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _buildBurgerAngleLayer(String path, int index, int total, double rotation) {
    double opacity = 0.0;
    
    if (total == 1) {
      opacity = 1.0;
    } else {
      final segmentSize = 1.0 / (total - 1);
      final myStart = index * segmentSize;
      final myEnd = (index + 1) * segmentSize;
      final fadeDuration = segmentSize * 0.25;  // أقل من السابق للظهور الأسرع
      
      if (index == 0) {
        // First image: ظهور دائم ثم تلاشي سلس (نفس منطق الطبقات)
        if (rotation <= myStart + fadeDuration) {
          opacity = 1.0;
        } else if (rotation < myEnd) {
          opacity = 1.0 - Curves.easeInOut.transform(((rotation - (myStart + fadeDuration)) / fadeDuration).clamp(0.0, 1.0));
        }
      } else if (index == total - 1) {
        // Last image: ظهور سلس ثم دائم (نفس منطق الطبقات)
        if (rotation < myStart - fadeDuration) {
          opacity = 0.0;
        } else if (rotation < myStart + fadeDuration) {
          opacity = Curves.easeInOut.transform(((rotation - (myStart - fadeDuration)) / (fadeDuration * 2)).clamp(0.0, 1.0));
        } else {
          opacity = 1.0;
        }
      } else {
        // Middle images: ظهور سلس → دائم → تلاشي سلس (نفس منطق الطبقات)
        if (rotation < myStart - fadeDuration) {
          opacity = 0.0;
        } else if (rotation < myStart + fadeDuration) {
          opacity = Curves.easeInOut.transform(((rotation - (myStart - fadeDuration)) / (fadeDuration * 2)).clamp(0.0, 1.0));
        } else if (rotation < myEnd - fadeDuration) {
          opacity = 1.0;
        } else if (rotation < myEnd + fadeDuration) {
          opacity = 1.0 - Curves.easeInOut.transform(((rotation - (myEnd - fadeDuration)) / (fadeDuration * 2)).clamp(0.0, 1.0));
        }
      }
    }

    return Opacity(opacity: opacity.clamp(0.0, 1.0), child: Image.asset(path, width: widget.height * 1.5, fit: BoxFit.contain));
  }

  Widget _buildWelcomeText() {
    return Positioned(
      bottom: 40,
      child: AnimatedOpacity(
        opacity: 1.0,
        duration: const Duration(milliseconds: 800),
        child: Column(
          children: [
            ShaderMask(
              shaderCallback: (bounds) => LinearGradient(colors: [Color(0xFFFF6B35), Color(0xFFFFC837)]).createShader(bounds),
              child: Text('CRAFTED WITH PASSION', style: TextStyle(fontFamily: 'TenorSans', fontSize: 11, fontWeight: FontWeight.w600, letterSpacing: 4, color: Colors.white)),
            ),
            SizedBox(height: 12),
            Text('Welcome to ${widget.storeName ?? "Paradise"}', style: TextStyle(fontFamily: 'TenorSans', fontSize: 32, fontWeight: FontWeight.w900, color: Colors.white)),
          ],
        ),
      ),
    );
  }

  Widget _buildInitialWelcomeText() {
    return ValueListenableBuilder<double>(
      valueListenable: initialWelcomeOpacityNotifier,
      builder: (context, opacity, _) => AnimatedBuilder(
        animation: _shimmerController,
        builder: (context, child) {
          final shimmer = (math.sin(_shimmerController.value * math.pi * 2) * 0.5) + 0.5;
          return Opacity(
            opacity: opacity,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ShaderMask(
                  shaderCallback: (bounds) => LinearGradient(
                    begin: Alignment(-1.5 + (shimmer * 3), -0.2),
                    end: Alignment(1.5 + (shimmer * 3), 0.2),
                    colors: [Color(0xFF6366F1).withOpacity(0.2), Color(0xFFFF6B35).withOpacity(0.8), Color(0xFFFFC837), Color(0xFFFF6B35).withOpacity(0.8), Color(0xFF6366F1).withOpacity(0.2)],
                    stops: [0.0, 0.35, 0.5, 0.65, 1.0],
                  ).createShader(bounds),
                  child: Text('DISCOVER EXCELLENCE', style: TextStyle(fontFamily: 'TenorSans', fontSize: 14, fontWeight: FontWeight.w600, letterSpacing: 5, color: Colors.white)),
                ),
                SizedBox(height: 20),
                ShaderMask(
                  shaderCallback: (bounds) => LinearGradient(colors: [Colors.white, Color(0xFFFFC837), Colors.white]).createShader(bounds),
                  child: Text('Scroll Down to Explore', style: TextStyle(fontFamily: 'TenorSans', fontSize: 28, fontWeight: FontWeight.w700, color: Colors.white)),
                ),
                SizedBox(height: 30),
                Transform.translate(offset: Offset(0, shimmer * 10), child: Icon(Icons.keyboard_arrow_down_rounded, size: 28, color: Colors.white)),
              ],
            ),
          );
        },
      ),
    );
  }
}

// PAINTERS
class BackgroundPainter extends CustomPainter {
  final double progress, intensity;
  BackgroundPainter({required this.progress, required this.intensity});
  
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..style = PaintingStyle.stroke..strokeWidth = 1.5;
    final center = Offset(size.width / 2, size.height / 2);
    for (int i = 0; i < 4; i++) {
      final phase = (progress + (i * 0.2));
      final offset = (math.sin(phase * math.pi * 2) * 0.5) + 0.5;
      final radius = size.width * 0.2 + (i * size.width * 0.08) + (offset * size.width * 0.1);
      paint.color = Color(0xFF8B5CF6).withOpacity(((1 - offset) * intensity * 0.12).clamp(0.0, 1.0));
      canvas.drawCircle(center, radius, paint);
    }
  }
  
  @override
  bool shouldRepaint(BackgroundPainter old) => true;
}

class ParticlePainter extends CustomPainter {
  final List<Particle> particles;
  final double progress, assemblyProgress;
  ParticlePainter({required this.particles, required this.progress, required this.assemblyProgress});
  
  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    for (var p in particles) {
      final angle = p.x * math.pi * 2 + progress * math.pi * 2;
      final radius = (p.y.abs() * size.width * 0.4);
      final paint = Paint()
        ..color = p.color.withOpacity(p.opacity * assemblyProgress * 0.5)
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, p.size);
      canvas.drawCircle(Offset(center.dx + math.cos(angle) * radius, center.dy + math.sin(angle) * radius), p.size, paint);
    }
  }
  
  @override
  bool shouldRepaint(ParticlePainter old) => true;
}

class LightRayPainter extends CustomPainter {
  final double progress, intensity;
  LightRayPainter({required this.progress, required this.intensity});
  
  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final paint = Paint()..style = PaintingStyle.fill..maskFilter = MaskFilter.blur(BlurStyle.normal, 12);
    for (int i = 0; i < 6; i++) {
      final angle = (i / 6) * math.pi * 2 + progress * math.pi * 0.3;
      final length = size.width * 0.25 * intensity;
      paint.shader = RadialGradient(colors: [Color(0xFFFFC837).withOpacity(0.15 * intensity), Colors.transparent]).createShader(Rect.fromCircle(center: center, radius: length));
      final path = Path()
        ..moveTo(center.dx, center.dy)
        ..lineTo(center.dx + math.cos(angle) * length, center.dy + math.sin(angle) * length)
        ..lineTo(center.dx + math.cos(angle + 0.08) * length, center.dy + math.sin(angle + 0.08) * length)
        ..close();
      canvas.drawPath(path, paint);
    }
  }
  
  @override
  bool shouldRepaint(LightRayPainter old) => true;
}

// MODELS
class BurgerLayer {
  final String asset;
  final double entryAngle;
  final Color glowColor;
  final String label;
  BurgerLayer({required this.asset, required this.entryAngle, required this.glowColor, required this.label});
}

class Particle {
  final double x, y, speed, size, opacity;
  final Color color;
  Particle({required this.x, required this.y, required this.speed, required this.size, required this.opacity, required this.color});
}