105 lines
2.9 KiB
Dart
105 lines
2.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../core/theme/app_theme.dart';
|
|
|
|
/// Animated floating blob background used on auth screens.
|
|
/// [bright] = true → white blobs (for dark/gradient backgrounds).
|
|
/// [bright] = false → primary/accent blobs (for light backgrounds).
|
|
class AnimatedAuthBg extends StatefulWidget {
|
|
const AnimatedAuthBg({super.key, this.bright = false});
|
|
final bool bright;
|
|
|
|
@override
|
|
State<AnimatedAuthBg> createState() => _AnimatedAuthBgState();
|
|
}
|
|
|
|
class _AnimatedAuthBgState extends State<AnimatedAuthBg>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _ctrl;
|
|
late Animation<double> _anim;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_ctrl = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(seconds: 8),
|
|
)..repeat(reverse: true);
|
|
_anim = CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_ctrl.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Color _blob(double alpha) => widget.bright
|
|
? Colors.white.withValues(alpha: alpha * 1.5)
|
|
: AppColors.primary.withValues(alpha: alpha);
|
|
|
|
Color _blobAccent(double alpha) => widget.bright
|
|
? Colors.white.withValues(alpha: alpha * 1.2)
|
|
: AppColors.accent.withValues(alpha: alpha);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _anim,
|
|
builder: (_, __) {
|
|
final t = _anim.value;
|
|
return Stack(
|
|
children: [
|
|
Positioned(
|
|
top: -80 + t * 30,
|
|
left: -60 + t * 20,
|
|
child: AuthBlob(size: 300, color: _blob(0.08)),
|
|
),
|
|
Positioned(
|
|
top: 200 - t * 40,
|
|
right: -100 + t * 25,
|
|
child: AuthBlob(size: 250, color: _blobAccent(0.06)),
|
|
),
|
|
Positioned(
|
|
bottom: 100 + t * 30,
|
|
left: 50 - t * 15,
|
|
child: AuthBlob(size: 200, color: _blob(0.05)),
|
|
),
|
|
Positioned(
|
|
bottom: -50 + t * 20,
|
|
right: -50 + t * 10,
|
|
child: AuthBlob(size: 280, color: _blobAccent(0.07)),
|
|
),
|
|
Positioned(
|
|
top: 350 + t * 25,
|
|
left: 80 + t * 20,
|
|
child: AuthBlob(size: 160, color: _blob(0.04)),
|
|
),
|
|
Positioned(
|
|
top: -40 - t * 10,
|
|
left: 120 + t * 30,
|
|
child: AuthBlob(size: 180, color: _blobAccent(0.05)),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
/// A simple solid circle used as a background blob.
|
|
class AuthBlob extends StatelessWidget {
|
|
const AuthBlob({super.key, required this.size, required this.color});
|
|
|
|
final double size;
|
|
final Color color;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
width: size,
|
|
height: size,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
|
|
);
|
|
}
|
|
}
|