Files
be_happy_public/lib/presentation/screens/onboarding_screen.dart
2026-05-12 12:02:40 +03:00

171 lines
5.4 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 'package:flutter/material.dart';
import '../components/gradient_button.dart';
class OnboardingScreen extends StatefulWidget {
const OnboardingScreen({super.key});
@override
State<OnboardingScreen> createState() => _OnboardingScreenState();
}
class _OnboardingScreenState extends State<OnboardingScreen> {
final PageController _pageController = PageController();
int _currentPage = 0;
final List<Map<String, String>> _slides = [
{
'image': 'assets/onboard_1.jpg',
'title': 'Найдите самокат на карте и выберите нужный',
},
{
'image': 'assets/onboard_2.jpg',
'title': 'Отсканируйте QR-код или введите номер который указан под козлом',
},
{
'image': 'assets/onboard_3.png',
'title': 'Дождитесь звукового сигнала. При наличии замка отстегните его',
},
{
'image': 'assets/onboard_4.jpg',
'title': 'Выберите тариф и начните поездку',
},
{
'image': 'assets/onboard_5.jpg',
'title': 'Управляйте скоростью с помощью курка тормоза',
},
{
'image': 'assets/onboard_6.jpg',
'title': 'Для торможения используйте курок тормоза',
},
{
'image': 'assets/onboard_7.png',
'title': 'Для завершения аренды припаркуйте самокат в разрешённом месте',
},
];
void _nextPage() {
if (_currentPage < _slides.length - 1) {
_pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
} else {
// TODO: переход дальше (авторизация / главная)
Navigator.pop(context);
}
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
/// Фон — PageView
PageView.builder(
controller: _pageController,
itemCount: _slides.length,
physics: const NeverScrollableScrollPhysics(),
onPageChanged: (index) {
setState(() {
_currentPage = index;
});
},
itemBuilder: (context, index) {
return Image.asset(
_slides[index]['image']!,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
);
},
),
/// Градиент сверху для читаемости
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withOpacity(0.35),
Colors.transparent,
],
stops: const [0.0, 0.7],
),
),
),
/// Контент
SafeArea(
child: Column(
children: [
const Expanded(child: SizedBox()),
/// Текст
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
_slides[_currentPage]['title']!,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 32),
/// Кнопка
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: GradientButton(
text: _currentPage == _slides.length - 1
? 'Начать'
: 'Далее',
onTap: _nextPage,
width: double.infinity,
height: 56,
fontSize: 18,
showArrows: true,
),
),
const SizedBox(height: 24),
/// Индикатор
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(_slides.length, (index) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: index == _currentPage ? 10 : 8,
height: index == _currentPage ? 10 : 8,
margin: const EdgeInsets.symmetric(horizontal: 3),
decoration: BoxDecoration(
color: index == _currentPage
? Colors.greenAccent
: Colors.white.withOpacity(0.3),
shape: BoxShape.circle,
),
);
}),
),
const SizedBox(height: 24),
],
),
),
],
),
);
}
}