|  |  |  | import 'dart:async'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/core/app_assets.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/core/app_export.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/theme/colors.dart'; | 
					
						
							|  |  |  | import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; | 
					
						
							|  |  |  | import 'package:lottie/lottie.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SplashAnimationScreen extends StatefulWidget { | 
					
						
							|  |  |  |   final Widget? routeWidget; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SplashAnimationScreen({super.key, this.routeWidget}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   _SplashAnimationScreenState createState() { | 
					
						
							|  |  |  |     return _SplashAnimationScreenState(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _SplashAnimationScreenState extends State<SplashAnimationScreen> with SingleTickerProviderStateMixin { | 
					
						
							|  |  |  |   late final AnimationController _controller; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     _controller = AnimationController(vsync: this); | 
					
						
							|  |  |  |     _controller.addListener(() { | 
					
						
							|  |  |  |       if (_controller.status == AnimationStatus.completed) { | 
					
						
							|  |  |  |         Navigator.of(context).pushReplacement(FadePage(page: widget.routeWidget ?? LandingNavigation())); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _controller.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Scaffold( | 
					
						
							|  |  |  |       backgroundColor: AppColors.whiteColor, | 
					
						
							|  |  |  |       body: Stack( | 
					
						
							|  |  |  |         children: [ | 
					
						
							|  |  |  |           Lottie.asset(AppAnimations.splashLaunching, controller: _controller, width: double.infinity, height: double.infinity, onLoaded: (composition) { | 
					
						
							|  |  |  |             _controller | 
					
						
							|  |  |  |               ..duration = composition.duration | 
					
						
							|  |  |  |               ..forward(); // Start the animation
 | 
					
						
							|  |  |  |           }, repeat: false, reverse: false, frameRate: FrameRate(60), fit: BoxFit.fill) | 
					
						
							|  |  |  |               .center, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // todo: do-not remove this code,as animation need to test on multiple screen sizes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AnimatedScreen extends StatefulWidget { | 
					
						
							|  |  |  |   const AnimatedScreen({super.key}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<AnimatedScreen> createState() => _AnimatedScreenState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _AnimatedScreenState extends State<AnimatedScreen> with TickerProviderStateMixin { | 
					
						
							|  |  |  |   late AnimationController _moveController; | 
					
						
							|  |  |  |   late Animation<Offset> _positionAnimation; | 
					
						
							|  |  |  |   late AnimationController _expandController; | 
					
						
							|  |  |  |   late Animation<double> _expandAnimation; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool isRipple = false; | 
					
						
							|  |  |  |   late final AnimationController _controller; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     _controller = AnimationController(vsync: this); | 
					
						
							|  |  |  |     _controller.addListener(() { | 
					
						
							|  |  |  |       if (_controller.status == AnimationStatus.completed) { | 
					
						
							|  |  |  |         // Navigator.of(context).pushReplacement(
 | 
					
						
							|  |  |  |         //   FadePage(
 | 
					
						
							|  |  |  |         //     page: LoginScreen(),
 | 
					
						
							|  |  |  |         //   ),
 | 
					
						
							|  |  |  |         // );
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Step 1: Move circle from bottom-left to top-right
 | 
					
						
							|  |  |  |     _moveController = AnimationController(vsync: this, duration: const Duration(seconds: 1)); | 
					
						
							|  |  |  |     _positionAnimation = Tween<Offset>( | 
					
						
							|  |  |  |       begin: const Offset(-1, 1), | 
					
						
							|  |  |  |       end: const Offset(1, -1), | 
					
						
							|  |  |  |     ).animate( | 
					
						
							|  |  |  |       CurvedAnimation(parent: _moveController, curve: const Cubic(0.82, -0.01, 0.58, 1)), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Step 2: Expand white circle from center
 | 
					
						
							|  |  |  |     _expandController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000)); | 
					
						
							|  |  |  |     _expandAnimation = Tween<double>( | 
					
						
							|  |  |  |       begin: 0.0, | 
					
						
							|  |  |  |       end: 4.0, | 
					
						
							|  |  |  |     ).animate(CurvedAnimation(parent: _expandController, curve: Curves.easeOut)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Trigger the animations in sequence
 | 
					
						
							|  |  |  |     _moveController.forward().whenComplete(() { | 
					
						
							|  |  |  |       setState(() { | 
					
						
							|  |  |  |         isRipple = true; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       _expandController.forward().whenComplete(() { | 
					
						
							|  |  |  |         setState(() { | 
					
						
							|  |  |  |           isRipple = false; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _controller.dispose(); | 
					
						
							|  |  |  |     _moveController.dispose(); | 
					
						
							|  |  |  |     _expandController.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     final screenSize = MediaQuery.of(context).size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Scaffold( | 
					
						
							|  |  |  |       backgroundColor: AppColors.whiteColor, | 
					
						
							|  |  |  |       body: Stack( | 
					
						
							|  |  |  |         children: [ | 
					
						
							|  |  |  |           // Moving rotated ellipse
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           Lottie.asset(AppAnimations.splashLaunching, controller: _controller, onLoaded: (composition) { | 
					
						
							|  |  |  |             _controller | 
					
						
							|  |  |  |               ..duration = composition.duration | 
					
						
							|  |  |  |               ..forward(); // Start the animation
 | 
					
						
							|  |  |  |           }, repeat: false, reverse: false, frameRate: FrameRate(60), fit: BoxFit.fill) | 
					
						
							|  |  |  |               .center, | 
					
						
							|  |  |  |           Lottie.asset(AppAnimations.loadingAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill).center, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           AnimatedContainer( | 
					
						
							|  |  |  |             duration: Duration(milliseconds: 500), | 
					
						
							|  |  |  |             width: screenSize.width, | 
					
						
							|  |  |  |             height: screenSize.height, | 
					
						
							|  |  |  |             color: isRipple ? AppColors.primaryRedColor : AppColors.whiteColor, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           AnimatedBuilder( | 
					
						
							|  |  |  |             animation: _moveController, | 
					
						
							|  |  |  |             builder: (context, child) { | 
					
						
							|  |  |  |               final pos = _positionAnimation.value; | 
					
						
							|  |  |  |               return Positioned( | 
					
						
							|  |  |  |                 left: ((screenSize.width * .75) * (pos.dx)).h, | 
					
						
							|  |  |  |                 top: ((screenSize.height * 0.75) * (pos.dy)).h, | 
					
						
							|  |  |  |                 child: Transform.rotate( | 
					
						
							|  |  |  |                   angle: -120 * 3.1415927 / 150, // convert degrees to radians
 | 
					
						
							|  |  |  |                   child: Container( | 
					
						
							|  |  |  |                     width: 400.h, | 
					
						
							|  |  |  |                     height: 653.h, | 
					
						
							|  |  |  |                     decoration: BoxDecoration( | 
					
						
							|  |  |  |                       color: Color(0xffED1C2B), | 
					
						
							|  |  |  |                       borderRadius: BorderRadius.circular(330.h), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           // Expanding white circle
 | 
					
						
							|  |  |  |           AnimatedBuilder( | 
					
						
							|  |  |  |             animation: _expandController, | 
					
						
							|  |  |  |             builder: (context, child) { | 
					
						
							|  |  |  |               return Center( | 
					
						
							|  |  |  |                 child: Transform.scale( | 
					
						
							|  |  |  |                   scale: _expandAnimation.value, | 
					
						
							|  |  |  |                   child: Opacity( | 
					
						
							|  |  |  |                     opacity: 1.0, //- _expandAnimation.value.clamp(0.0, 1.0),
 | 
					
						
							|  |  |  |                     child: Container( | 
					
						
							|  |  |  |                         decoration: const BoxDecoration( | 
					
						
							|  |  |  |                       color: Colors.white, | 
					
						
							|  |  |  |                       shape: BoxShape.circle, | 
					
						
							|  |  |  |                       // border: Border.fromBorderSide(BorderSide(
 | 
					
						
							|  |  |  |                       //   width: 0,
 | 
					
						
							|  |  |  |                       //   color: Color(0xffED1C2B),
 | 
					
						
							|  |  |  |                       // )
 | 
					
						
							|  |  |  |                     )), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                   // ),
 | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           // AnimatedBuilder(
 | 
					
						
							|  |  |  |           //   animation: _expandController,
 | 
					
						
							|  |  |  |           //   builder: (context, child) {
 | 
					
						
							|  |  |  |           //     final screenSize = MediaQuery.of(context).size;
 | 
					
						
							|  |  |  |           //     final maxDiameter =
 | 
					
						
							|  |  |  |           //         (screenSize.width > screenSize.height ? screenSize.width : screenSize.height) * 2;
 | 
					
						
							|  |  |  |           //
 | 
					
						
							|  |  |  |           //     return Center(
 | 
					
						
							|  |  |  |           //       child: Transform.scale(
 | 
					
						
							|  |  |  |           //         scale: _expandAnimation.value * maxDiameter / 100, // scale up to fill screen
 | 
					
						
							|  |  |  |           //         child: Opacity(
 | 
					
						
							|  |  |  |           //           opacity: (1.0 - _expandAnimation.value).clamp(0.0, 1.0),
 | 
					
						
							|  |  |  |           //           child: Container(
 | 
					
						
							|  |  |  |           //             decoration: const BoxDecoration(
 | 
					
						
							|  |  |  |           //               color: Colors.white,
 | 
					
						
							|  |  |  |           //               shape: BoxShape.circle,
 | 
					
						
							|  |  |  |           //             ),
 | 
					
						
							|  |  |  |           //           ),
 | 
					
						
							|  |  |  |           //         ),
 | 
					
						
							|  |  |  |           //       ),
 | 
					
						
							|  |  |  |           //     );
 | 
					
						
							|  |  |  |           //   },
 | 
					
						
							|  |  |  |           // ),
 | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MoveObjectDemo extends StatefulWidget { | 
					
						
							|  |  |  |   const MoveObjectDemo({super.key}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<MoveObjectDemo> createState() => _MoveObjectDemoState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _MoveObjectDemoState extends State<MoveObjectDemo> with SingleTickerProviderStateMixin { | 
					
						
							|  |  |  |   late AnimationController _controller; | 
					
						
							|  |  |  |   late Animation<Alignment> _alignmentAnimation; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _controller = AnimationController( | 
					
						
							|  |  |  |       vsync: this, | 
					
						
							|  |  |  |       duration: const Duration(seconds: 1), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _alignmentAnimation = AlignmentTween( | 
					
						
							|  |  |  |       begin: Alignment(-2.0, 2.5), | 
					
						
							|  |  |  |       end: Alignment(2.5, -2), | 
					
						
							|  |  |  |     ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _controller.forward(); // start animation
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _controller.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Scaffold( | 
					
						
							|  |  |  |       body: AnimatedBuilder( | 
					
						
							|  |  |  |         animation: _alignmentAnimation, | 
					
						
							|  |  |  |         builder: (context, child) { | 
					
						
							|  |  |  |           return Align( | 
					
						
							|  |  |  |             alignment: _alignmentAnimation.value, | 
					
						
							|  |  |  |             child: Transform.rotate( | 
					
						
							|  |  |  |               angle: -120 * 3.1415927 / 180, | 
					
						
							|  |  |  |               child: Container( | 
					
						
							|  |  |  |                 width: 200, | 
					
						
							|  |  |  |                 height: 375, | 
					
						
							|  |  |  |                 decoration: BoxDecoration( | 
					
						
							|  |  |  |                   color: const Color(0xffED1C2B), | 
					
						
							|  |  |  |                   borderRadius: BorderRadius.circular(330), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Transform.rotate(
 | 
					
						
							|  |  |  |             //   angle: -120 * 3.1415927 / 180, // convert to radians
 | 
					
						
							|  |  |  |             //   child: Container(
 | 
					
						
							|  |  |  |             //     width: 400,
 | 
					
						
							|  |  |  |             //     height: 653,
 | 
					
						
							|  |  |  |             //     decoration: BoxDecoration(
 | 
					
						
							|  |  |  |             //       color: const Color(0xffED1C2B),
 | 
					
						
							|  |  |  |             //       borderRadius: BorderRadius.circular(330),
 | 
					
						
							|  |  |  |             //     ),
 | 
					
						
							|  |  |  |             //   ),
 | 
					
						
							|  |  |  |             // ),
 | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MoveOnClickDemo extends StatefulWidget { | 
					
						
							|  |  |  |   const MoveOnClickDemo({super.key}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<MoveOnClickDemo> createState() => _MoveOnClickDemoState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _MoveOnClickDemoState extends State<MoveOnClickDemo> with TickerProviderStateMixin { | 
					
						
							|  |  |  |   late AnimationController _controller; | 
					
						
							|  |  |  |   late Animation<Alignment> _alignmentAnimation; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     init(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   init() { | 
					
						
							|  |  |  |     _controller = AnimationController( | 
					
						
							|  |  |  |       vsync: this, | 
					
						
							|  |  |  |       duration: const Duration(milliseconds: 1000), // Figma duration
 | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _alignmentAnimation = AlignmentTween( | 
					
						
							|  |  |  |       // begin: Alignment(-10.0, 5),
 | 
					
						
							|  |  |  |       // end: Alignment(5, -2),
 | 
					
						
							|  |  |  |       begin: Alignment.bottomLeft, | 
					
						
							|  |  |  |       end: Alignment.topRight, | 
					
						
							|  |  |  |     ).animate(CurvedAnimation( | 
					
						
							|  |  |  |       parent: _controller, | 
					
						
							|  |  |  |       curve: const Cubic(0.82, -0.01, 0.58, 1), // Figma cubic-bezier
 | 
					
						
							|  |  |  |     )); | 
					
						
							|  |  |  |     _animate(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _controller.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _animate() { | 
					
						
							|  |  |  |     if (_controller.isCompleted) { | 
					
						
							|  |  |  |       _controller.reverse(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       _controller.forward(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Scaffold( | 
					
						
							|  |  |  |       body: GestureDetector( | 
					
						
							|  |  |  |         onTap: _animate, // trigger on click
 | 
					
						
							|  |  |  |         onDoubleTap: () { | 
					
						
							|  |  |  |           _controller.dispose(); | 
					
						
							|  |  |  |           init(); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         child: AnimatedBuilder( | 
					
						
							|  |  |  |           animation: _alignmentAnimation, | 
					
						
							|  |  |  |           builder: (context, child) { | 
					
						
							|  |  |  |             print(_alignmentAnimation.value); | 
					
						
							|  |  |  |             return Align( | 
					
						
							|  |  |  |               alignment: _alignmentAnimation.value, | 
					
						
							|  |  |  |               child: Transform.rotate( | 
					
						
							|  |  |  |                 angle: -120 * 3.1415927 / 145, // -120 deg
 | 
					
						
							|  |  |  |                 child: Container( | 
					
						
							|  |  |  |                   width: 100, | 
					
						
							|  |  |  |                   height: 150, | 
					
						
							|  |  |  |                   decoration: BoxDecoration( | 
					
						
							|  |  |  |                     color: const Color(0xffED1C2B), | 
					
						
							|  |  |  |                     borderRadius: BorderRadius.circular(330), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |