Files
be_happy_public/lib/presentation/screens/splash_screen.dart
2026-05-29 11:40:55 +03:00

178 lines
5.6 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:math' as math;
import 'package:be_happy/presentation/event/spalsh_event.dart';
import 'package:be_happy/presentation/viewmodel/splash_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
// Фаза 1: Заполнение цветом слева направо (0.0 -> 0.5)
late final Animation<double> _fillProgress;
// Фаза 2: Укатывание вправо (0.6 -> 1.0)
late final Animation<double> _rollTranslation;
late final Animation<double> _rollRotation;
// Уменьшенный размер логотипа по вашему запросу
static const double logoSize = 130;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 3000),
);
_fillProgress = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeInOut),
),
);
_rollTranslation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.6, 1.0, curve: Curves.easeInCubic),
),
);
_rollRotation = Tween<double>(begin: 0.0, end: 2 * math.pi).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.6, 1.0, curve: Curves.easeIn),
),
);
// Добавляем задержку перед стартом, чтобы пользователь успел увидеть экран
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (!mounted) return;
// Ждем 500мс после того, как первый кадр отрисовался
await Future.delayed(const Duration(milliseconds: 500));
if (!mounted) return;
// Запускаем анимацию
_controller.forward().then((_) {
if (!mounted) return;
context.read<SplashBloc>().add(AuthCheckRequested());
});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final double screenWidth = MediaQuery.of(context).size.width;
final double endTranslation = screenWidth / 2 + logoSize;
return Scaffold(
body: Stack(
children: [
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFF293A69),
Color(0xFF202741),
],
),
),
),
),
// 2. Волна
Positioned(
top: 0,
left: 0,
right: 0,
child: Image.asset(
'assets/wave.png',
fit: BoxFit.contain,
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Image.asset(
'assets/splash_map.png',
fit: BoxFit.contain,
),
),
Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
final double translationX = _rollTranslation.value * endTranslation;
return Transform(
transform: Matrix4.translationValues(translationX, 0, 0)
..rotateZ(_rollRotation.value),
alignment: Alignment.center,
// Используем ShaderMask для эффекта заполнения/проявления
child: ShaderMask(
shaderCallback: (bounds) {
return LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
// Используем _fillProgress для сдвига жесткой границы градиента
colors: const [Colors.white, Colors.transparent],
stops: [_fillProgress.value, _fillProgress.value],
).createShader(bounds);
},
blendMode: BlendMode.dstIn, // Оставляет только ту часть логотипа, где градиент белый
child: Image.asset(
'assets/splash_logo.png',
width: logoSize,
height: logoSize,
fit: BoxFit.contain,
),
),
);
},
),
),
// 5. Версия приложения
Positioned(
left: 0,
right: 0,
bottom: 24,
child: Text(
'Версия приложения 1.0',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white.withOpacity(0.6),
fontSize: 12,
fontWeight: FontWeight.w300,
letterSpacing: 0.5,
),
),
),
],
),
);
}
}