# Conflicts:
#	lib/presentation/navigation/app_router.dart
#	pubspec.yaml
This commit is contained in:
2026-08-11 00:14:00 +03:00
parent c9b8d143d1
commit 182be1049b
351 changed files with 24566 additions and 22898 deletions

View File

@@ -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,
),
),
),
],
),
);
}
}