Files
AppRecoleccion/lib/screens/onboarding/onboarding_screen.dart

122 lines
6.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../core/app_colors.dart';
class OnboardingScreen extends StatefulWidget {
const OnboardingScreen({super.key});
@override State<OnboardingScreen> createState() => _OnboardingScreenState();
}
class _OnboardingScreenState extends State<OnboardingScreen> {
final _ctrl = PageController();
int _page = 0;
static const _pages = [
_OnboardPage(icon:Icons.delete_sweep_rounded, color:AppColors.guindaPrimary,
title:'Bienvenido a Celaya Limpia',
subtitle:'El sistema de recoleccion inteligente del H. Ayuntamiento de Celaya.',
desc:'Recibe alertas en tiempo real, conoce tu horario y ayuda a mantener tu ciudad limpia.'),
_OnboardPage(icon:Icons.notifications_active, color:AppColors.azulInfo,
title:'Alertas inteligentes',
subtitle:'Te avisamos exactamente cuando debes sacar tu basura.',
desc:'Recibiras 3 alertas:\n\n30 min antes: el camion esta en camino.\n15 min antes: saca tus bolsas a la acera.\nAl pasar: confirma que fue recogida.\n\nNunca mas pierdas al camion recolector.'),
_OnboardPage(icon:Icons.recycling, color:AppColors.verdeExito,
title:'Guia de separacion',
subtitle:'Aprende a separar correctamente tus residuos.',
desc:'Bolsa verde: organicos (comida, jardin)\nBolsa azul: reciclables (PET, latas)\nBolsa negra: no reciclables\n\nUsa la camara IA para identificar si un residuo es organico o inorganico al instante.'),
_OnboardPage(icon:Icons.star, color:Colors.amber,
title:'Tu opinion importa',
subtitle:'Califica el servicio y ayuda a mejorarlo.',
desc:'Despues de cada recoleccion podras:\n\nCalificar de 1 a 5 estrellas\nDejar comentarios al Ayuntamiento\nReportar incidencias con foto\n\nTus reportes son atendidos por el equipo municipal.'),
];
Future<void> _finish() async {
final p = await SharedPreferences.getInstance();
await p.setBool('onboarding_done', true);
if (!mounted) return;
Navigator.pushReplacementNamed(context, '/login');
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
PageView.builder(controller:_ctrl, onPageChanged:(p)=>setState(()=>_page=p),
itemCount:_pages.length,
itemBuilder:(_,i)=>_PageContent(page:_pages[i])),
Positioned(bottom:120, left:0, right:0,
child:Row(mainAxisAlignment:MainAxisAlignment.center,
children:List.generate(_pages.length,(i)=>AnimatedContainer(
duration:const Duration(milliseconds:250),
margin:const EdgeInsets.symmetric(horizontal:4),
width:_page==i?24:8, height:8,
decoration:BoxDecoration(
color:_page==i?_pages[i].color:Colors.grey.shade300,
borderRadius:BorderRadius.circular(4)))))),
Positioned(bottom:40, left:24, right:24,
child:Row(children:[
if (_page>0)
TextButton(onPressed:()=>_ctrl.previousPage(
duration:const Duration(milliseconds:300),curve:Curves.easeOut),
child:const Text('Atras',style:TextStyle(color:AppColors.grisTexto)))
else
TextButton(onPressed:_finish,
child:const Text('Omitir',style:TextStyle(color:AppColors.grisTexto))),
const Spacer(),
ElevatedButton(
onPressed:_page<_pages.length-1
?()=>_ctrl.nextPage(duration:const Duration(milliseconds:300),curve:Curves.easeOut)
:_finish,
style:ElevatedButton.styleFrom(
backgroundColor:_pages[_page].color, foregroundColor:Colors.white,
padding:const EdgeInsets.symmetric(horizontal:28,vertical:12),
shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(25))),
child:Text(_page<_pages.length-1?'Siguiente':'Comenzar',
style:const TextStyle(fontWeight:FontWeight.bold))),
])),
]));
}
@override void dispose(){ _ctrl.dispose(); super.dispose(); }
}
class _OnboardPage {
final IconData icon; final Color color;
final String title, subtitle, desc;
const _OnboardPage({required this.icon,required this.color,
required this.title,required this.subtitle,required this.desc});
}
class _PageContent extends StatelessWidget {
final _OnboardPage page;
const _PageContent({super.key, required this.page});
@override
Widget build(BuildContext context) => Container(
decoration:BoxDecoration(gradient:LinearGradient(
begin:Alignment.topCenter, end:Alignment.bottomCenter,
colors:[page.color, page.color.withOpacity(0.85), Colors.white],
stops:const[0,0.4,0.7])),
child:SafeArea(child:Column(children:[
const SizedBox(height:48),
Container(width:120,height:120,
decoration:BoxDecoration(color:Colors.white.withOpacity(0.2),shape:BoxShape.circle,
border:Border.all(color:Colors.white.withOpacity(0.5),width:2)),
child:Icon(page.icon,size:60,color:Colors.white)),
const SizedBox(height:28),
Padding(padding:const EdgeInsets.symmetric(horizontal:32),child:Column(children:[
Text(page.title,textAlign:TextAlign.center,
style:const TextStyle(fontSize:24,fontWeight:FontWeight.bold,color:Colors.white)),
const SizedBox(height:10),
Text(page.subtitle,textAlign:TextAlign.center,
style:TextStyle(fontSize:14,color:Colors.white.withOpacity(0.9))),
])),
const SizedBox(height:32),
Expanded(child:Container(margin:const EdgeInsets.symmetric(horizontal:20),
padding:const EdgeInsets.all(22),
decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(20),
boxShadow:[BoxShadow(color:page.color.withOpacity(0.2),blurRadius:20,offset:const Offset(0,8))]),
child:Text(page.desc,textAlign:TextAlign.left,
style:const TextStyle(fontSize:13,height:1.7,color:AppColors.negroTexto)))),
const SizedBox(height:110),
])));
}