didvan-app/lib/views/onboarding/onboarding_page.dart

305 lines
14 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. 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 'package:didvan/models/onboarding_entity.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/storage/storage.dart';
import 'package:didvan/views/onboarding/onboarding_indicator_painter.dart';
import 'package:flutter_svg/flutter_svg.dart';
final List<OnboardingEntity> onboardingPages = [
OnboardingEntity(
imagePath: 'lib/assets/images/onboarding/1.png',
title: 'چرا دیدوان؟',
description:
'جغرافیای زمانی هیچ‌گاه نمی‌ایستد و سفر به آینده یک سفر شگفت‌انگیز به جایی است که قسمت‌هایی از آن را قبلاً در گذشته دیده‌ایم، قسمت‌هایی از آن را طی مسیر به تدریج می‌بینیم و قسمت‌هایی از آن کاملاً بدیع هستند. برای سفر مطمئن در جغرافیای زمانی ما به سیستم‌های پیش‌نگر نیاز داریم و یکی از ارکان این سیستم‌ها، سامانه‌های رصد راهبردی هستند.',
),
OnboardingEntity(
imagePath: 'lib/assets/images/onboarding/2.png',
title: 'رادارهای استراتژیک',
description:
'رادارهای استراتژیک، قلب دیدوان هستند. رادارهایی که قرار است دید 360 درجه‌ای برای مدیران ایجاد کنند و به صورت مستمر گزارش‌هایی تحلیلی را از محیط‌های دور و نزدیک هر کسب و کار در اختیار مدیران قرار ‌دهند. رادارها به صورت موضوعی شامل رادار روند، رادار ریسک، رادار تکنولوژی، رادار استارت‌آپ و ماژول فرصت و تهدید دسته بندی شده‌اند و مدیران می‌توانند پیرامون این گزارشات به بحث و تبادل نظر بپردازند.',
),
OnboardingEntity(
imagePath: 'lib/assets/images/onboarding/3.png',
title: 'استودیو دیدوان',
description:
'''در استودیو آینده شما می‌توانید ویدیوهایی مستند از مسائلی مانند آموزش مفاهیم آینده‌گرا، تحلیل روندها، تحلیل صنعت و یا هر نوع اطلاعاتی که می‌تواند برای تصمیم‌گیری مدیران ارشد راهگشا باشد را ببینید.
همچنین در بخش دیگر این استودیو و در قالب پادکست، اطلاعاتی از جنس مسائل پیش گفته که ارزش تبدیل به فایل صوتی دارند را، می‌شنوید.
 ''',
),
OnboardingEntity(
imagePath: 'lib/assets/images/onboarding/4.png',
title: 'نبض صنعت',
description: 'در دنیای امروز، تصمیم‌گیری‌های کلیدی در صنایع مختلف به شدت وابسته به داده‌های دقیق و به‌روز شده‌اند. این داده‌ها شامل اطلاعات اقتصادی، مالی، خرید و فروش، بازار سرمایه، ارزهای دیجیتال، شاخص‌های کلان اقتصادی و دیگر حوزه‌ها هستند. استفاده هوشمندانه از داده‌ها این امکان را به مدیران می‌دهد تا تصمیماتی آگاهانه بگیرند، ریسک‌ها را کاهش دهند و عملکرد کلی خود را به سطحی بالاتر ارتقاء دهند.',
),
];
class OnboardingPage extends StatefulWidget {
const OnboardingPage({super.key});
@override
State<OnboardingPage> createState() => _OnboardingPageState();
}
class _OnboardingPageState extends State<OnboardingPage> {
final PageController _pageController = PageController();
int _currentPage = 0;
@override
void initState() {
super.initState();
_pageController.addListener(() {
if (_pageController.page != null) {
setState(() {
_currentPage = _pageController.page!.round();
});
}
});
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
void _onNextTap() async {
if (_currentPage < onboardingPages.length - 1) {
_pageController.nextPage(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
} else {
await _completeOnboarding();
}
}
Future<void> _completeOnboarding() async {
await StorageService.setValue(key: 'hasSeenOnboarding', value: 'true');
if (mounted) {
Navigator.of(context).pushReplacementNamed(
Routes.authenticaion,
arguments: {'isResetPassword': false},
);
}
}
void _skipOnboarding() async {
await _completeOnboarding();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
return Scaffold(
backgroundColor: colorScheme.background,
body: SafeArea(
child: Stack(
children: [
Directionality(
textDirection: TextDirection.ltr,
child: PageView.builder(
controller: _pageController,
itemCount: onboardingPages.length,
itemBuilder: (context, index) {
final page = onboardingPages[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 0),
child: Column(
children: [
Image.asset(
page.imagePath,
height: 350,
width: double.infinity,
fit: BoxFit.fitWidth,
errorBuilder: (context, error, stackTrace) {
return Container(
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(24),
),
child: Center(
child: Icon(
Icons.image_outlined,
size: 80,
color: colorScheme.primary.withOpacity(0.3),
),
),
);
},
),
SizedBox(
width: 60,
height: 60,
child: Stack(
alignment: Alignment.center,
children: [
CustomPaint(
size: const Size(60, 60),
painter: OnboardingIndicatorPainter(
pageCount: onboardingPages.length,
currentPage: _currentPage,
activeColor:
const Color.fromARGB(255, 1, 35, 72),
inactiveColor:
const Color.fromARGB(255, 0, 126, 167)),
),
GestureDetector(
onTap: _onNextTap,
child: Container(
width: 60,
height: 45,
decoration: const BoxDecoration(
color: Color.fromARGB(255, 1, 35, 72),
shape: BoxShape.circle,
),
child: Center(
child: SvgPicture.asset(
'lib/assets/icons/Arrow - Right 2.svg',
width: 25,
height: 25,
colorFilter: const ColorFilter.mode(
Colors.white,
BlendMode.srcIn,
),
),
),
),
),
],
),
),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
page.title,
textAlign: TextAlign.start,
style:
theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 22,
color: const Color.fromARGB(255, 0, 126, 167),
),
),
const SizedBox(height: 13),
Text(
page.description,
textDirection: TextDirection.rtl,
textAlign: TextAlign.start,
style: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromARGB(255, 41, 41, 41),
height: 1.6,
fontSize: 15
),
),
],
),
),
),
],
),
);
},
),
),
if (_currentPage > 0)
Positioned(
top: 16,
left: 16,
child: Container(
height: 40,
width: 40,
decoration: const BoxDecoration(
color: Color.fromARGB(230, 234, 234, 233),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(4)),
),
child: Center(
child: IconButton(
icon: SvgPicture.asset('lib/assets/icons/arrow-left.svg'),
onPressed: () {
_pageController.previousPage(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
},
),
),
),
),
Positioned(
bottom: 40,
left: 24,
right: 24,
child: Column(
children: [
Row(
children: [
Expanded(
flex: 4,
child: ElevatedButton(
onPressed: _onNextTap,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Text(
'بعدی',
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
),
),
const SizedBox(width: 16),
Expanded(
flex: 2,
child: OutlinedButton(
onPressed: _skipOnboarding,
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
side: BorderSide(
color: colorScheme.primary.withOpacity(0.3),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Text(
'صرف نظر کردن',
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.black,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
),
],
),
),
],
),
),
);
}
}