import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:uuid/uuid.dart'; import '../../theme/app_theme.dart'; import 'package:christian_period_tracker/models/user_profile.dart'; import 'package:christian_period_tracker/models/cycle_entry.dart'; import '../home/home_screen.dart'; import '../husband/husband_home_screen.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../providers/user_provider.dart'; class OnboardingScreen extends ConsumerStatefulWidget { const OnboardingScreen({super.key}); @override ConsumerState createState() => _OnboardingScreenState(); } class _OnboardingScreenState extends ConsumerState { final PageController _pageController = PageController(); int _currentPage = 0; bool _isNavigating = false; // Debounce flag // Form data UserRole _role = UserRole.wife; String _name = ''; RelationshipStatus _relationshipStatus = RelationshipStatus.single; FertilityGoal? _fertilityGoal; int _averageCycleLength = 28; DateTime? _lastPeriodStart; bool _isIrregularCycle = false; @override void dispose() { _pageController.dispose(); super.dispose(); } void _nextPage() async { if (_isNavigating) return; _isNavigating = true; // Husband Flow: Role (0) -> Name (1) -> Finish // Wife Flow: Role (0) -> Name (1) -> Relationship (2) -> [Fertility (3)] -> Cycle (4) int nextPage = _currentPage + 1; // Logic for skipping pages if (_role == UserRole.husband) { if (_currentPage == 1) { await _completeOnboarding(); return; } } else { // Wife flow if (_currentPage == 2 && _relationshipStatus != RelationshipStatus.married) { // Skip fertility goal (page 3) if not married nextPage = 4; } } if (nextPage <= 4) { // Max pages await _pageController.animateToPage( nextPage, duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, ); } else { await _completeOnboarding(); } // Reset debounce after animation Future.delayed(const Duration(milliseconds: 500), () { if (mounted) setState(() => _isNavigating = false); }); } void _previousPage() async { if (_isNavigating) return; _isNavigating = true; int prevPage = _currentPage - 1; // Logic for reverse skipping if (_role == UserRole.wife) { if (_currentPage == 4 && _relationshipStatus != RelationshipStatus.married) { // Skip back over fertility goal (page 3) prevPage = 2; } } if (prevPage >= 0) { await _pageController.animateToPage( prevPage, duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, ); } // Reset debounce after animation Future.delayed(const Duration(milliseconds: 500), () { if (mounted) setState(() => _isNavigating = false); }); } Future _completeOnboarding() async { final userProfile = UserProfile( id: const Uuid().v4(), name: _name, role: _role, relationshipStatus: _role == UserRole.husband ? RelationshipStatus.married : _relationshipStatus, fertilityGoal: (_role == UserRole.wife && _relationshipStatus == RelationshipStatus.married) ? _fertilityGoal : null, averageCycleLength: _averageCycleLength, lastPeriodStartDate: _lastPeriodStart, isIrregularCycle: _isIrregularCycle, hasCompletedOnboarding: true, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); await ref.read(userProfileProvider.notifier).updateProfile(userProfile); if (mounted) { // Navigate to appropriate home screen if (_role == UserRole.husband) { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => const HusbandHomeScreen(), ), ); } else { Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const HomeScreen()), ); } } } @override Widget build(BuildContext context) { // Different background color for husband flow final bgColor = _role == UserRole.husband ? AppColors.warmCream : AppColors.cream; return Scaffold( backgroundColor: bgColor, body: SafeArea( child: Column( children: [ // Progress indicator (hide on role page 0) if (_currentPage > 0) Padding( padding: const EdgeInsets.all(24), child: SmoothPageIndicator( controller: _pageController, count: _role == UserRole.husband ? 2 : 5, effect: WormEffect( dotHeight: 8, dotWidth: 8, spacing: 12, activeDotColor: _role == UserRole.husband ? AppColors.navyBlue : AppColors.sageGreen, dotColor: AppColors.lightGray.withOpacity(0.3), ), ), ), // Pages Expanded( child: PageView( controller: _pageController, physics: const NeverScrollableScrollPhysics(), // Disable swipe onPageChanged: (index) { setState(() => _currentPage = index); }, children: [ _buildRolePage(), // Page 0 _buildNamePage(), // Page 1 _buildRelationshipPage(), // Page 2 (Wife only) _buildFertilityGoalPage(), // Page 3 (Wife married only) _buildCyclePage(), // Page 4 (Wife only) ], ), ), ], ), ), ); } Widget _buildRolePage() { return Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 80, height: 80, decoration: BoxDecoration( gradient: LinearGradient( colors: [AppColors.blushPink, AppColors.rose.withOpacity(0.7)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), ), child: const Icon( Icons.favorite_rounded, size: 40, color: Colors.white, ), ), const SizedBox(height: 32), Text( 'Who is this app for?', textAlign: TextAlign.center, style: GoogleFonts.outfit( fontSize: 28, fontWeight: FontWeight.w600, color: AppColors.charcoal, ), ), const SizedBox(height: 48), _buildRoleOption(UserRole.wife, 'For Her', 'Track cycle, health, and faith', Icons.female), const SizedBox(height: 16), _buildRoleOption(UserRole.husband, 'For Him', 'Support your wife and grow together', Icons.male), const Spacer(), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _nextPage, style: ElevatedButton.styleFrom( backgroundColor: _role == UserRole.husband ? AppColors.navyBlue : AppColors.sageGreen, ), child: const Text('Continue'), ), ), ], ), ); } Widget _buildRoleOption(UserRole role, String title, String subtitle, IconData icon) { final isSelected = _role == role; // Dynamic colors based on role selection final activeColor = role == UserRole.wife ? AppColors.sageGreen : AppColors.navyBlue; final activeBg = role == UserRole.wife ? AppColors.sageGreen.withOpacity(0.1) : AppColors.navyBlue.withOpacity(0.1); return GestureDetector( onTap: () => setState(() => _role = role), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: isSelected ? activeBg : Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all( color: isSelected ? activeColor : AppColors.lightGray.withOpacity(0.5), width: isSelected ? 2 : 1, ), boxShadow: isSelected ? [ BoxShadow( color: activeColor.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 4), ) ] : [], ), child: Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: isSelected ? activeColor : AppColors.lightGray.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( icon, color: isSelected ? Colors.white : AppColors.warmGray, size: 24, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: GoogleFonts.outfit( fontSize: 18, fontWeight: FontWeight.w600, color: AppColors.charcoal, ), ), const SizedBox(height: 4), Text( subtitle, style: GoogleFonts.outfit( fontSize: 14, color: AppColors.warmGray, ), ), ], ), ), if (isSelected) Icon(Icons.check_circle, color: activeColor), ], ), ), ); } Widget _buildNamePage() { final isHusband = _role == UserRole.husband; final activeColor = isHusband ? AppColors.navyBlue : AppColors.sageGreen; return Padding( padding: const EdgeInsets.all(32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 40), Text( isHusband ? 'What\'s your name, sir?' : 'What\'s your name?', style: GoogleFonts.outfit( fontSize: 28, fontWeight: FontWeight.w600, color: isHusband ? AppColors.navyBlue : AppColors.charcoal, ), ), const SizedBox(height: 8), Text( 'We\'ll use this to personalize the app.', style: GoogleFonts.outfit( fontSize: 14, color: AppColors.warmGray, ), ), const SizedBox(height: 32), TextField( onChanged: (value) => setState(() => _name = value), decoration: InputDecoration( hintText: 'Enter your name', prefixIcon: Icon( Icons.person_outline, color: AppColors.warmGray, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: activeColor), ), ), style: GoogleFonts.outfit(fontSize: 16), textCapitalization: TextCapitalization.words, ), const Spacer(), Row( children: [ Expanded( child: OutlinedButton( onPressed: _previousPage, style: OutlinedButton.styleFrom( foregroundColor: isHusband ? AppColors.navyBlue : AppColors.sageGreen, side: BorderSide(color: isHusband ? AppColors.navyBlue : AppColors.sageGreen), ), child: const Text('Back'), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: (_name.isNotEmpty && !_isNavigating) ? _nextPage : null, style: ElevatedButton.styleFrom( backgroundColor: activeColor, ), child: Text(isHusband ? 'Finish Setup' : 'Continue'), ), ), ], ), ], ), ); } Widget _buildRelationshipPage() { return Padding( padding: const EdgeInsets.all(32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 40), Text( 'Tell us about yourself', style: GoogleFonts.outfit( fontSize: 28, fontWeight: FontWeight.w600, color: AppColors.charcoal, ), ), const SizedBox(height: 32), _buildRelationshipOption(RelationshipStatus.single, 'Single', 'Wellness focus', Icons.person_outline), const SizedBox(height: 12), _buildRelationshipOption(RelationshipStatus.engaged, 'Engaged', 'Prepare for marriage', Icons.favorite_border), const SizedBox(height: 12), _buildRelationshipOption(RelationshipStatus.married, 'Married', 'Fertility & intimacy', Icons.favorite), const Spacer(), Row( children: [ Expanded( child: OutlinedButton( onPressed: _previousPage, style: OutlinedButton.styleFrom(foregroundColor: AppColors.sageGreen, side: BorderSide(color: AppColors.sageGreen)), child: const Text('Back'), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: (_relationshipStatus != null && !_isNavigating) ? _nextPage : null, child: const Text('Continue'), ), ), ], ), ], ), ); } Widget _buildRelationshipOption(RelationshipStatus status, String title, String subtitle, IconData icon) { final isSelected = _relationshipStatus == status; return GestureDetector( onTap: () => setState(() => _relationshipStatus = status), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isSelected ? AppColors.sageGreen.withOpacity(0.1) : Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all( color: isSelected ? AppColors.sageGreen : AppColors.lightGray.withOpacity(0.5), width: isSelected ? 2 : 1, ), ), child: Row( children: [ Icon(icon, color: isSelected ? AppColors.sageGreen : AppColors.warmGray), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: GoogleFonts.outfit(fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.charcoal)), Text(subtitle, style: GoogleFonts.outfit(fontSize: 13, color: AppColors.warmGray)), ], ), ), if (isSelected) Icon(Icons.check_circle, color: AppColors.sageGreen), ], ), ), ); } Widget _buildFertilityGoalPage() { return Padding( padding: const EdgeInsets.all(32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 40), Text('What\'s your goal?', style: GoogleFonts.outfit(fontSize: 28, fontWeight: FontWeight.w600, color: AppColors.charcoal)), const SizedBox(height: 32), _buildGoalOption(FertilityGoal.tryingToConceive, 'Trying to Conceive', 'Track fertile days', Icons.child_care_outlined), const SizedBox(height: 12), _buildGoalOption(FertilityGoal.tryingToAvoid, 'Natural Family Planning', 'Track fertility signs', Icons.calendar_today_outlined), const SizedBox(height: 12), _buildGoalOption(FertilityGoal.justTracking, 'Just Tracking', 'Monitor cycle health', Icons.insights_outlined), const Spacer(), Row( children: [ Expanded( child: OutlinedButton( onPressed: _previousPage, style: OutlinedButton.styleFrom(foregroundColor: AppColors.sageGreen, side: BorderSide(color: AppColors.sageGreen)), child: const Text('Back'), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: (_fertilityGoal != null && !_isNavigating) ? _nextPage : null, child: const Text('Continue'), ), ), ], ), ], ), ); } Widget _buildGoalOption(FertilityGoal goal, String title, String subtitle, IconData icon) { final isSelected = _fertilityGoal == goal; return GestureDetector( onTap: () => setState(() => _fertilityGoal = goal), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isSelected ? AppColors.sageGreen.withOpacity(0.1) : Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all( color: isSelected ? AppColors.sageGreen : AppColors.lightGray.withOpacity(0.5), width: isSelected ? 2 : 1, ), ), child: Row( children: [ Icon(icon, color: isSelected ? AppColors.sageGreen : AppColors.warmGray), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: GoogleFonts.outfit(fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.charcoal)), Text(subtitle, style: GoogleFonts.outfit(fontSize: 13, color: AppColors.warmGray)), ], ), ), if (isSelected) Icon(Icons.check_circle, color: AppColors.sageGreen), ], ), ), ); } Widget _buildCyclePage() { return Padding( padding: const EdgeInsets.all(32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 40), Text('About your cycle', style: GoogleFonts.outfit(fontSize: 28, fontWeight: FontWeight.w600, color: AppColors.charcoal)), const SizedBox(height: 32), Text('Average cycle length', style: GoogleFonts.outfit(fontSize: 16, fontWeight: FontWeight.w500, color: AppColors.charcoal)), Row( children: [ Expanded( child: Slider( value: _averageCycleLength.toDouble(), min: 21, max: 40, divisions: 19, onChanged: (value) => setState(() => _averageCycleLength = value.round()), ), ), Text('$_averageCycleLength days', style: GoogleFonts.outfit(fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.sageGreen)), ], ), // Irregular Cycle Checkbox CheckboxListTile( title: Text('My cycles are irregular', style: GoogleFonts.outfit(fontSize: 14, color: AppColors.charcoal)), value: _isIrregularCycle, onChanged: (val) => setState(() => _isIrregularCycle = val ?? false), activeColor: AppColors.sageGreen, contentPadding: EdgeInsets.zero, controlAffinity: ListTileControlAffinity.leading, ), const SizedBox(height: 24), Text('Last period start date', style: GoogleFonts.outfit(fontSize: 16, fontWeight: FontWeight.w500, color: AppColors.charcoal)), const SizedBox(height: 8), GestureDetector( onTap: () async { final date = await showDatePicker( context: context, initialDate: _lastPeriodStart ?? DateTime.now(), firstDate: DateTime.now().subtract(const Duration(days: 60)), lastDate: DateTime.now(), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: const ColorScheme.light(primary: AppColors.sageGreen, onPrimary: Colors.white, surface: Colors.white, onSurface: AppColors.charcoal), ), child: child!, ); }, ); if (date != null) setState(() => _lastPeriodStart = date); }, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.lightGray.withOpacity(0.5))), child: Row( children: [ Icon(Icons.calendar_today, color: AppColors.warmGray), const SizedBox(width: 12), Text(_lastPeriodStart != null ? "${_lastPeriodStart!.month}/${_lastPeriodStart!.day}/${_lastPeriodStart!.year}" : "Select Date", style: GoogleFonts.outfit(fontSize: 16, color: AppColors.charcoal)), ], ), ), ), const Spacer(), Row( children: [ Expanded( child: OutlinedButton( onPressed: _previousPage, style: OutlinedButton.styleFrom(foregroundColor: AppColors.sageGreen, side: BorderSide(color: AppColors.sageGreen)), child: const Text('Back'), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: (_lastPeriodStart != null && !_isNavigating) ? _nextPage : null, child: const Text('Get Started'), ), ), ], ), ], ), ); } }