fix functional bugs

This commit is contained in:
2026-05-29 11:40:55 +03:00
parent 591265a7fc
commit 134ffdde60
50 changed files with 1086 additions and 771 deletions

View File

@@ -1,13 +1,8 @@
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';
import 'package:shared_preferences/shared_preferences.dart';
// Подключи сюда свои реальные экраны:
import 'phone_screen.dart';
import 'pin_login_screen.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@@ -19,35 +14,61 @@ class SplashScreen extends StatefulWidget {
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _revealAnimation;
static const double logoSize = 300;
// Фаза 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: 2500),
duration: const Duration(milliseconds: 3000),
);
// анимация движения "затемняющего" прямоугольника
_revealAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
_fillProgress = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeInOut),
),
);
// запускаем анимацию
_controller.forward().then((_) async {
// небольшая пауза после анимации
await Future.delayed(const Duration(milliseconds: 800));
if (!mounted) {
return;
}
context.read<SplashBloc>().add(AuthCheckRequested());
_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
@@ -56,69 +77,102 @@ class _SplashScreenState extends State<SplashScreen>
super.dispose();
}
@override
@override
Widget build(BuildContext context) {
final double screenWidth = MediaQuery.of(context).size.width;
final double endTranslation = screenWidth / 2 + logoSize;
return Scaffold(
backgroundColor: const Color(0xFF3A3A3A),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, _) {
final double offset = _revealAnimation.value * (logoSize * 1.2);
return Stack(
alignment: Alignment.center,
children: [
// Цветной логотип (на заднем плане)
Image.asset(
'assets/logo_color.png',
width: logoSize,
height: logoSize,
fit: BoxFit.contain,
body: Stack(
children: [
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFF293A69),
Color(0xFF202741),
],
),
),
),
),
// Прямоугольник, который "уезжает" вправо, открывая логотип
ClipRect(
child: Align(
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor: 1,
child: Container(
width: logoSize,
height: logoSize,
color: const Color(0xFF3A3A3A),
transform: Matrix4.translationValues(offset, 0, 0),
),
// 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,
),
),
),
// Обводка логотипа (поверх)
Image.asset(
'assets/logo_outline.png',
width: logoSize * 1.01,
height: logoSize * 1.01,
fit: BoxFit.contain,
),
],
);
},
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.only(bottom: 24),
child: Text(
'Версия приложения 1.0',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 12,
);
},
),
),
),
// 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,
),
),
),
],
),
);
}
}
}