diff --git a/lib/presentation/pages/home/widgets/header.dart b/lib/presentation/pages/home/widgets/header.dart index b4882e9..2ba3973 100644 --- a/lib/presentation/pages/home/widgets/header.dart +++ b/lib/presentation/pages/home/widgets/header.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'dart:math' as math; import '../../../../common/extension/extension.dart'; +import '../../../../common/painter/wave_painter.dart'; import '../../../../common/theme/theme.dart'; import '../../../components/spacer/spacer.dart'; @@ -12,244 +14,248 @@ class HomeHeader extends StatefulWidget { } class _HomeHeaderState extends State with TickerProviderStateMixin { - late AnimationController _backgroundAnimationController; - late AnimationController _pulseAnimationController; - late AnimationController _rotationAnimationController; + late AnimationController _animationController; + late AnimationController _particleController; + late AnimationController _waveController; + late AnimationController _breathController; - late Animation _circleAnimation; - late Animation _pulseAnimation; - late Animation _rotationAnimation; + late Animation _fadeInAnimation; + late Animation _slideAnimation; + late Animation _scaleAnimation; + late Animation _particleAnimation; + late Animation _waveAnimation; + late Animation _breathAnimation; @override void initState() { super.initState(); - // Background animation controller for floating circles - _backgroundAnimationController = AnimationController( - duration: const Duration(seconds: 15), + // Main content animations + _animationController = AnimationController( + duration: const Duration(milliseconds: 1200), vsync: this, - )..repeat(reverse: true); // Add reverse for smooth back-and-forth + ); - // Pulse animation for subtle breathing effect - _pulseAnimationController = AnimationController( - duration: const Duration(seconds: 6), - vsync: this, - )..repeat(reverse: true); - - // Rotation animation for decorative elements (keep this smooth) - _rotationAnimationController = AnimationController( - duration: const Duration(seconds: 45), + _particleController = AnimationController( + duration: const Duration(seconds: 8), vsync: this, )..repeat(); - _circleAnimation = - Tween( - begin: 0.0, - end: 20.0, // Reduced movement range - ).animate( + _waveController = AnimationController( + duration: const Duration(seconds: 6), + vsync: this, + )..repeat(); + + _breathController = AnimationController( + duration: const Duration(seconds: 4), + vsync: this, + )..repeat(reverse: true); + + // Content animations + _fadeInAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.6, curve: Curves.easeOut), + ), + ); + + _slideAnimation = + Tween(begin: const Offset(0, 0.5), end: Offset.zero).animate( CurvedAnimation( - parent: _backgroundAnimationController, - curve: Curves.easeInOutSine, // Smoother curve + parent: _animationController, + curve: const Interval(0.2, 0.8, curve: Curves.easeOutCubic), ), ); - _pulseAnimation = Tween(begin: 0.08, end: 0.12).animate( + _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation( - parent: _pulseAnimationController, - curve: Curves.easeInOutSine, // Smoother breathing effect + parent: _animationController, + curve: const Interval(0.0, 0.7, curve: Curves.elasticOut), ), ); - _rotationAnimation = Tween(begin: 0.0, end: 2 * 3.14159).animate( - CurvedAnimation( - parent: _rotationAnimationController, - curve: Curves.linear, - ), + _particleAnimation = Tween( + begin: 0.0, + end: 2 * math.pi, + ).animate(_particleController); + + _waveAnimation = Tween( + begin: 0.0, + end: 2 * math.pi, + ).animate(_waveController); + + _breathAnimation = Tween(begin: 0.8, end: 1.2).animate( + CurvedAnimation(parent: _breathController, curve: Curves.easeInOut), ); + + _animationController.forward(); } @override void dispose() { - _backgroundAnimationController.dispose(); - _pulseAnimationController.dispose(); - _rotationAnimationController.dispose(); + _animationController.dispose(); + _particleController.dispose(); + _waveController.dispose(); + _breathController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { - return Container( - height: 280, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - AppColor.primary, - AppColor.primaryLight, - AppColor.primaryLight.withOpacity(0.8), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - stops: const [0.0, 0.7, 1.0], - ), - boxShadow: [ - BoxShadow( - color: AppColor.primary.withOpacity(0.3), - blurRadius: 20, - offset: const Offset(0, 10), + return AnimatedBuilder( + animation: Listenable.merge([ + _particleController, + _waveController, + _breathController, + ]), + builder: (context, child) { + return Container( + height: 280, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.primary, + AppColor.primaryLight, + AppColor.primaryLight.withOpacity(0.8), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + stops: const [0.0, 0.7, 1.0], + ), + boxShadow: [ + BoxShadow( + color: AppColor.primary.withOpacity(0.3), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], ), - ], - ), - child: Stack( - children: [ - // Animated decorative circles - AnimatedBuilder( - animation: Listenable.merge([ - _backgroundAnimationController, - _pulseAnimationController, - ]), - builder: (context, child) { - return Stack( - children: [ - // Large floating circle - Positioned( - top: -50 + _circleAnimation.value, - right: -50 + (_circleAnimation.value * 0.5), - child: AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Container( - width: 150, - height: 150, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColor.white.withOpacity( - _pulseAnimation.value, - ), - ), - ); - }, - ), - ), + child: Stack( + children: [ + // Enhanced animated background + _buildAnimatedBackground(), - // Medium floating circle - Positioned( - top: 80 - (_circleAnimation.value * 0.3), - right: -20 + (_circleAnimation.value * 0.8), - child: AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Container( - width: 80, - height: 80, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColor.white.withOpacity( - _pulseAnimation.value * 0.5, - ), - ), - ); - }, - ), - ), - - // Small floating circle - Positioned( - top: 150 + (_circleAnimation.value * 0.4), - right: 30 - (_circleAnimation.value * 0.2), - child: AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColor.white.withOpacity( - _pulseAnimation.value * 0.7, - ), - ), - ); - }, - ), - ), - - // Left side decorative circles - Positioned( - top: 60 + (_circleAnimation.value * 0.6), - left: -30, - child: AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Container( - width: 100, - height: 100, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColor.white.withOpacity( - _pulseAnimation.value * 0.3, - ), - ), - ); - }, - ), - ), - - Positioned( - bottom: 20 - (_circleAnimation.value * 0.5), - left: -20 + (_circleAnimation.value * 0.3), - child: AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Container( - width: 60, - height: 60, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColor.white.withOpacity( - _pulseAnimation.value * 0.4, - ), - ), - ); - }, - ), - ), - ], - ); - }, + // Main content + SafeArea(child: _buildContent(context)), + ], ), - - // Rotating subtle gradient overlay - AnimatedBuilder( - animation: _rotationAnimationController, - builder: (context, child) { - return Transform.rotate( - angle: _rotationAnimation.value, - child: Container( - decoration: BoxDecoration( - gradient: RadialGradient( - center: const Alignment(0.8, -0.8), - radius: 1.5, - colors: [ - AppColor.white.withOpacity(0.05), - Colors.transparent, - AppColor.primary.withOpacity(0.1), - ], - stops: const [0.0, 0.6, 1.0], - ), - ), - ), - ); - }, - ), - - // Content - SafeArea(child: _buildContent(context)), - ], - ), + ); + }, ); } - Padding _buildContent(BuildContext context) { + Widget _buildAnimatedBackground() { + return Stack( + children: [ + // Floating particles with orbital motion + ...List.generate(12, (index) { + final double radius = 60 + (index * 15); + final double angle = _particleAnimation.value + (index * 0.5); + final double centerX = MediaQuery.of(context).size.width * 0.8; + final double centerY = 100; + + return Positioned( + left: centerX + math.cos(angle) * radius - 4, + top: centerY + math.sin(angle) * (radius * 0.5) - 4, + child: Transform.scale( + scale: _breathAnimation.value * 0.4, + child: Container( + width: 2 + (index % 3), + height: 2 + (index % 3), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.white.withOpacity(0.7), + boxShadow: [ + BoxShadow( + color: AppColor.white.withOpacity(0.3), + blurRadius: 6, + spreadRadius: 1, + ), + ], + ), + ), + ), + ); + }), + + // Wave patterns + Positioned.fill( + child: CustomPaint( + painter: WavePainter( + animation: _waveAnimation.value, + color: AppColor.white.withOpacity(0.08), + ), + ), + ), + + // Sparkle effects + ...List.generate(8, (index) { + return Positioned( + left: (index * 60.0) % MediaQuery.of(context).size.width, + top: 30 + (index * 25.0), + child: Transform.rotate( + angle: _particleAnimation.value * 2 + index, + child: Transform.scale( + scale: math.sin(_particleAnimation.value + index) * 0.3 + 0.8, + child: Icon( + Icons.auto_awesome, + size: 8 + (index % 3) * 3, + color: AppColor.white.withOpacity(0.5), + ), + ), + ), + ); + }), + + // Gradient overlay for depth + Container( + decoration: BoxDecoration( + gradient: RadialGradient( + center: const Alignment(0.8, -0.3), + radius: 1.5, + colors: [ + Colors.transparent, + AppColor.primary.withOpacity(0.1), + Colors.transparent, + ], + ), + ), + ), + + // Additional left side particles + ...List.generate(6, (index) { + final double radius = 40 + (index * 10); + final double angle = _particleAnimation.value * 0.5 + (index * 1.2); + final double centerX = MediaQuery.of(context).size.width * 0.1; + final double centerY = 120; + + return Positioned( + left: centerX + math.cos(angle) * radius - 2, + top: centerY + math.sin(angle) * (radius * 0.7) - 2, + child: Transform.scale( + scale: _breathAnimation.value * 0.3 + 0.5, + child: Container( + width: 2 + (index % 2), + height: 2 + (index % 2), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.white.withOpacity(0.4), + boxShadow: [ + BoxShadow( + color: AppColor.white.withOpacity(0.2), + blurRadius: 4, + ), + ], + ), + ), + ), + ); + }), + ], + ); + } + + Widget _buildContent(BuildContext context) { String greeting(BuildContext context) { final hour = DateTime.now().hour; @@ -270,189 +276,203 @@ class _HomeHeaderState extends State with TickerProviderStateMixin { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - // Top bar with subtle animation - TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: const Duration(milliseconds: 800), - builder: (context, value, child) { - return Transform.translate( - offset: Offset(0, 20 * (1 - value)), - child: Opacity( - opacity: value, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'AppSkel POS Owner', - style: AppStyle.lg.copyWith( - color: AppColor.white.withOpacity(0.9), - fontWeight: FontWeight.w600, - letterSpacing: 0.3, - ), - ), - const SpaceHeight(2), - Text( - 'Manager', - style: AppStyle.sm.copyWith( - color: AppColor.textLight, - fontSize: 11, - fontWeight: FontWeight.w400, - ), - ), - ], - ), - ), - // Animated notification icon - AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Transform.scale( - scale: 1.0 + (_pulseAnimation.value * 0.1), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColor.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(14), - border: Border.all( - color: AppColor.white.withOpacity(0.3), - width: 1, + // Top bar with enhanced animation + SlideTransition( + position: _slideAnimation, + child: FadeTransition( + opacity: _fadeInAnimation, + child: Transform.scale( + scale: _scaleAnimation.value, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'AppSkel POS Owner', + style: AppStyle.lg.copyWith( + color: AppColor.white.withOpacity(0.9), + fontWeight: FontWeight.w600, + letterSpacing: 0.3, + shadows: [ + Shadow( + color: Colors.black.withOpacity(0.2), + offset: const Offset(0, 1), + blurRadius: 2, ), - boxShadow: [ - BoxShadow( - color: AppColor.white.withOpacity(0.1), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: const Icon( - Icons.notifications_none_rounded, - color: AppColor.white, - size: 20, - ), + ], ), - ); - }, + ), + const SpaceHeight(2), + Text( + 'Manager', + style: AppStyle.sm.copyWith( + color: AppColor.white.withOpacity(0.7), + fontSize: 11, + fontWeight: FontWeight.w400, + ), + ), + ], ), - ], - ), + ), + // Enhanced notification icon with breathing animation + AnimatedBuilder( + animation: _breathController, + builder: (context, child) { + return Transform.scale( + scale: _breathAnimation.value * 0.1 + 1.0, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.25), + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: AppColor.white.withOpacity(0.3), + width: 1, + ), + boxShadow: [ + BoxShadow( + color: AppColor.white.withOpacity(0.2), + blurRadius: 8 + (_breathAnimation.value * 2), + offset: const Offset(0, 2), + ), + ], + ), + child: const Icon( + Icons.notifications_none_rounded, + color: AppColor.white, + size: 20, + ), + ), + ); + }, + ), + ], ), - ); - }, + ), + ), ), const SpaceHeight(24), - // Greeting Section with staggered animation - TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: const Duration(milliseconds: 1000), - builder: (context, value, child) { - return Transform.translate( - offset: Offset(0, 30 * (1 - value)), - child: Opacity( - opacity: value, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '${greeting(context)},', - style: AppStyle.lg.copyWith( - color: AppColor.white, - fontWeight: FontWeight.w500, - ), + // Greeting Section with enhanced animations + SlideTransition( + position: _slideAnimation, + child: FadeTransition( + opacity: _fadeInAnimation, + child: Transform.scale( + scale: _scaleAnimation.value, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${greeting(context)},', + style: AppStyle.lg.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w500, + shadows: [ + Shadow( + color: Colors.black.withOpacity(0.2), + offset: const Offset(0, 1), + blurRadius: 2, + ), + ], ), - const SpaceHeight(2), - Text( - 'Vira Vania! 👋', - style: AppStyle.h4.copyWith( - color: AppColor.white, - fontWeight: FontWeight.w800, - letterSpacing: -0.5, - ), + ), + const SpaceHeight(2), + Text( + 'Vira Vania! 👋', + style: AppStyle.h4.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w800, + letterSpacing: -0.5, + shadows: [ + Shadow( + color: Colors.black.withOpacity(0.2), + offset: const Offset(0, 2), + blurRadius: 4, + ), + ], ), - const SpaceHeight(8), - Text( - context.lang.home_header_desc, - style: AppStyle.md.copyWith( - color: AppColor.white.withOpacity(0.85), - fontWeight: FontWeight.w400, - height: 1.3, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, + ), + const SpaceHeight(8), + Text( + context.lang.home_header_desc, + style: AppStyle.md.copyWith( + color: AppColor.white.withOpacity(0.85), + fontWeight: FontWeight.w400, + height: 1.3, ), - ], - ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], ), - ); - }, + ), + ), ), const SpaceHeight(16), - // Today's highlight with delayed animation - TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: const Duration(milliseconds: 1200), - builder: (context, value, child) { - return Transform.translate( - offset: Offset(0, 20 * (1 - value)), - child: Opacity( - opacity: value, - child: AnimatedBuilder( - animation: _pulseAnimationController, - builder: (context, child) { - return Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, + // Today's highlight with enhanced breathing animation + FadeTransition( + opacity: _fadeInAnimation, + child: SlideTransition( + position: _slideAnimation, + child: AnimatedBuilder( + animation: _breathController, + builder: (context, child) { + return Transform.scale( + scale: _breathAnimation.value * 0.05 + 1.0, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.25), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.white.withOpacity(0.3), + width: 1, ), - decoration: BoxDecoration( - color: AppColor.white.withOpacity( - 0.2 + (_pulseAnimation.value * 0.05), + boxShadow: [ + BoxShadow( + color: AppColor.white.withOpacity(0.1), + blurRadius: 6 + (_breathAnimation.value * 2), + offset: const Offset(0, 2), ), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: AppColor.white.withOpacity(0.3), - width: 1, - ), - boxShadow: [ - BoxShadow( - color: AppColor.white.withOpacity(0.1), - blurRadius: 4 + (_pulseAnimation.value * 2), - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( + ], + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Transform.scale( + scale: _breathAnimation.value * 0.1 + 1.0, + child: Icon( Icons.trending_up_rounded, color: AppColor.white, size: 14, ), - const SizedBox(width: 6), - Text( - '${context.lang.sales_today} +25%', - style: AppStyle.sm.copyWith( - color: AppColor.white, - fontWeight: FontWeight.w600, - ), + ), + const SizedBox(width: 6), + Text( + '${context.lang.sales_today} +25%', + style: AppStyle.sm.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + letterSpacing: 0.3, ), - ], - ), - ); - }, - ), - ), - ); - }, + ), + ], + ), + ), + ); + }, + ), + ), ), ], ),