animated_background.dart 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import 'package:flutter/material.dart';
  2. import 'dart:math' as math;
  3. import '../../utils/colors.dart';
  4. import '../../utils/theme_notifier.dart';
  5. class AnimatedBackground extends StatefulWidget {
  6. final Widget child;
  7. final bool isZenMode;
  8. final Function()? onShake;
  9. const AnimatedBackground({
  10. super.key,
  11. required this.child,
  12. this.isZenMode = false,
  13. this.onShake,
  14. });
  15. @override
  16. State<AnimatedBackground> createState() => _AnimatedBackgroundState();
  17. }
  18. class _AnimatedBackgroundState extends State<AnimatedBackground>
  19. with TickerProviderStateMixin {
  20. late AnimationController _controller1;
  21. late AnimationController _controller2;
  22. late AnimationController _controller3;
  23. late AnimationController _shakeController;
  24. bool _isShaking = false;
  25. @override
  26. void initState() {
  27. super.initState();
  28. // Create multiple animation controllers for layered effects (optimized for performance)
  29. _controller1 = AnimationController(
  30. duration: const Duration(seconds: 60), // Slower animations for better performance
  31. vsync: this,
  32. )..repeat();
  33. _controller2 = AnimationController(
  34. duration: const Duration(seconds: 80), // Slower animations for better performance
  35. vsync: this,
  36. )..repeat();
  37. _controller3 = AnimationController(
  38. duration: const Duration(seconds: 100), // Much slower for better performance
  39. vsync: this,
  40. )..repeat();
  41. // Shake effect controller
  42. _shakeController = AnimationController(
  43. duration: const Duration(milliseconds: 800),
  44. vsync: this,
  45. );
  46. }
  47. @override
  48. void dispose() {
  49. _controller1.dispose();
  50. _controller2.dispose();
  51. _controller3.dispose();
  52. _shakeController.dispose();
  53. super.dispose();
  54. }
  55. void triggerShake() {
  56. if (!_isShaking) {
  57. _isShaking = true;
  58. _shakeController.forward().then((_) {
  59. _shakeController.reset();
  60. _isShaking = false;
  61. });
  62. widget.onShake?.call();
  63. }
  64. }
  65. @override
  66. Widget build(BuildContext context) {
  67. return ThemeAwareBuilder(
  68. builder: (context, theme) {
  69. return Stack(
  70. children: [
  71. // Base background
  72. Container(
  73. decoration: BoxDecoration(
  74. gradient: LinearGradient(
  75. begin: Alignment.topLeft,
  76. end: Alignment.bottomRight,
  77. colors: [
  78. ZenColors.currentAppBackground,
  79. ZenColors.currentSecondaryBackground,
  80. ],
  81. ),
  82. ),
  83. ),
  84. // Animated gradient layers (reduced to 2 for better performance)
  85. ...List.generate(2, (index) => _buildAnimatedLayer(index)),
  86. // Content overlay
  87. widget.child,
  88. ],
  89. );
  90. },
  91. );
  92. }
  93. Widget _buildAnimatedLayer(int layerIndex) {
  94. AnimationController controller;
  95. List<Color> colors;
  96. switch (layerIndex) {
  97. case 0:
  98. controller = _controller1;
  99. colors = widget.isZenMode
  100. ? ZenColors.zenModeColors
  101. : ZenColors.animationLayer1;
  102. break;
  103. case 1:
  104. controller = _controller2;
  105. colors = ZenColors.animationLayer2;
  106. break;
  107. default:
  108. controller = _controller3;
  109. colors = ZenColors.animationLayer3;
  110. }
  111. return AnimatedBuilder(
  112. animation: Listenable.merge([controller, _shakeController]),
  113. builder: (context, child) {
  114. // Add shake effect
  115. double shakeIntensity = 0.0;
  116. if (_isShaking) {
  117. shakeIntensity = math.sin(_shakeController.value * math.pi * 8) *
  118. (1 - _shakeController.value) * 10; // Decay over time
  119. }
  120. return Transform.translate(
  121. offset: Offset(
  122. shakeIntensity * (math.Random().nextDouble() - 0.5) * 2,
  123. shakeIntensity * (math.Random().nextDouble() - 0.5) * 2,
  124. ),
  125. child: Transform.rotate(
  126. angle: controller.value * 2 * math.pi,
  127. child: Container(
  128. decoration: BoxDecoration(
  129. gradient: RadialGradient(
  130. center: Alignment(
  131. math.sin(controller.value * 2 * math.pi) * 0.5,
  132. math.cos(controller.value * 2 * math.pi) * 0.5,
  133. ),
  134. radius: 1.5 + math.sin(controller.value * math.pi) * 0.5 +
  135. (shakeIntensity * 0.1), // Shake affects radius too
  136. colors: colors,
  137. ),
  138. ),
  139. ),
  140. ),
  141. );
  142. },
  143. );
  144. }
  145. }