some fix
# Conflicts: # lib/presentation/navigation/app_router.dart # pubspec.yaml
This commit is contained in:
@@ -1,178 +1,178 @@
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user