| 1 | import 'package:flutter/material.dart'; |
| 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; |
| 3 | import 'package:go_router/go_router.dart'; |
| 4 | import 'package:hugeicons/hugeicons.dart'; |
| 5 | import 'package:shadcn_ui/shadcn_ui.dart'; |
| 6 | import 'package:cue/cue.dart'; |
| 7 | |
| 8 | import '../../../core/providers/app_providers.dart'; |
| 9 | import '../../../core/routes/app_routes.dart'; |
| 10 | import '../../../core/theme/app_theme.dart'; |
| 11 | import '../../../l10n/app_localizations.dart'; |
| 12 | |
| 13 | class OnboardingThemeScreen extends ConsumerStatefulWidget { |
| 14 | const OnboardingThemeScreen({super.key}); |
| 15 | |
| 16 | @override |
| 17 | ConsumerState<OnboardingThemeScreen> createState() => |
| 18 | _OnboardingThemeScreenState(); |
| 19 | } |
| 20 | |
| 21 | class _OnboardingThemeScreenState extends ConsumerState<OnboardingThemeScreen> { |
| 22 | @override |
| 23 | Widget build(BuildContext context) { |
| 24 | final l10n = AppLocalizations.of(context)!; |
| 25 | final theme = Theme.of(context); |
| 26 | final currentTheme = ref.watch(themeModeProvider); |
| 27 | |
| 28 | return Scaffold( |
| 29 | appBar: AppBar( |
| 30 | title: Text(l10n.choose_theme), |
| 31 | leading: IconButton( |
| 32 | icon: const HugeIcon(icon: HugeIcons.strokeRoundedArrowLeft01), |
| 33 | onPressed: () { |
| 34 | context.pop(); |
| 35 | }, |
| 36 | ), |
| 37 | ), |
| 38 | body: SafeArea( |
| 39 | child: Cue.onMount( |
| 40 | motion: .smooth(), |
| 41 | child: Padding( |
| 42 | padding: const EdgeInsets.symmetric( |
| 43 | horizontal: 24.0, |
| 44 | vertical: 16.0, |
| 45 | ), |
| 46 | child: Column( |
| 47 | crossAxisAlignment: CrossAxisAlignment.stretch, |
| 48 | children: [ |
| 49 | Actor( |
| 50 | acts: [.fadeIn(), .slideY(from: 0.08)], |
| 51 | child: Text( |
| 52 | l10n.choose_theme_desc, |
| 53 | style: theme.textTheme.titleMedium?.copyWith( |
| 54 | color: theme.colorScheme.onSurface.withValues(alpha: 0.7), |
| 55 | ), |
| 56 | ), |
| 57 | ), |
| 58 | const SizedBox(height: 32), |
| 59 | |
| 60 | Expanded( |
| 61 | child: Actor( |
| 62 | delay: 60.ms, |
| 63 | acts: [.fadeIn(), .slideY(from: 0.08)], |
| 64 | child: ListView( |
| 65 | children: [ |
| 66 | _buildThemeCard( |
| 67 | type: AppThemeType.system, |
| 68 | title: l10n.theme_card_system, |
| 69 | subtitle: l10n.theme_card_system_sub, |
| 70 | iconWidget: HugeIcon( |
| 71 | icon: HugeIcons.strokeRoundedSettings01, |
| 72 | color: currentTheme == AppThemeType.system |
| 73 | ? theme.colorScheme.primary |
| 74 | : theme.colorScheme.onSurface, |
| 75 | ), |
| 76 | currentTheme: currentTheme, |
| 77 | context: context, |
| 78 | ), |
| 79 | const SizedBox(height: 16), |
| 80 | _buildThemeCard( |
| 81 | type: AppThemeType.light, |
| 82 | title: l10n.theme_card_light, |
| 83 | subtitle: l10n.theme_card_light_sub, |
| 84 | iconWidget: HugeIcon( |
| 85 | icon: HugeIcons.strokeRoundedSun01, |
| 86 | color: currentTheme == AppThemeType.light |
| 87 | ? theme.colorScheme.primary |
| 88 | : theme.colorScheme.onSurface, |
| 89 | ), |
| 90 | currentTheme: currentTheme, |
| 91 | context: context, |
| 92 | ), |
| 93 | const SizedBox(height: 16), |
| 94 | _buildThemeCard( |
| 95 | type: AppThemeType.dark, |
| 96 | title: l10n.theme_card_dark, |
| 97 | subtitle: l10n.theme_card_dark_sub, |
| 98 | iconWidget: HugeIcon( |
| 99 | icon: HugeIcons.strokeRoundedMoon02, |
| 100 | color: currentTheme == AppThemeType.dark |
| 101 | ? theme.colorScheme.primary |
| 102 | : theme.colorScheme.onSurface, |
| 103 | ), |
| 104 | currentTheme: currentTheme, |
| 105 | context: context, |
| 106 | ), |
| 107 | const SizedBox(height: 16), |
| 108 | _buildThemeCard( |
| 109 | type: AppThemeType.claude, |
| 110 | title: l10n.theme_card_claude, |
| 111 | subtitle: l10n.theme_card_claude_sub, |
| 112 | iconWidget: HugeIcon( |
| 113 | icon: HugeIcons.strokeRoundedPaintBrush02, |
| 114 | color: currentTheme == AppThemeType.claude |
| 115 | ? theme.colorScheme.primary |
| 116 | : theme.colorScheme.onSurface, |
| 117 | ), |
| 118 | currentTheme: currentTheme, |
| 119 | context: context, |
| 120 | ), |
| 121 | ], |
| 122 | ), |
| 123 | ), |
| 124 | ), |
| 125 | |
| 126 | const SizedBox(height: 24), |
| 127 | Actor( |
| 128 | delay: 120.ms, |
| 129 | acts: [.fadeIn(), .slideY(from: 0.08)], |
| 130 | child: ShadButton( |
| 131 | width: double.infinity, |
| 132 | onPressed: () async { |
| 133 | if (context.mounted) { |
| 134 | context.push(AppRoutes.onboardingNotifications); |
| 135 | } |
| 136 | }, |
| 137 | child: Text( |
| 138 | l10n.finish_setup, |
| 139 | style: const TextStyle( |
| 140 | fontSize: 16, |
| 141 | fontWeight: FontWeight.w600, |
| 142 | ), |
| 143 | ), |
| 144 | ), |
| 145 | ), |
| 146 | ], |
| 147 | ), |
| 148 | ), |
| 149 | ), |
| 150 | ), |
| 151 | ); |
| 152 | } |
| 153 | |
| 154 | Widget _buildThemeCard({ |
| 155 | required AppThemeType type, |
| 156 | required String title, |
| 157 | required String subtitle, |
| 158 | required Widget iconWidget, |
| 159 | required AppThemeType currentTheme, |
| 160 | required BuildContext context, |
| 161 | }) { |
| 162 | final theme = Theme.of(context); |
| 163 | final isSelected = currentTheme == type; |
| 164 | |
| 165 | return GestureDetector( |
| 166 | onTap: () { |
| 167 | ref.read(themeModeProvider.notifier).setThemeMode(type); |
| 168 | }, |
| 169 | child: Container( |
| 170 | padding: const EdgeInsets.all(20), |
| 171 | decoration: BoxDecoration( |
| 172 | color: theme.colorScheme.surface, |
| 173 | borderRadius: BorderRadius.circular(16), |
| 174 | border: Border.all( |
| 175 | color: isSelected |
| 176 | ? theme.colorScheme.primary |
| 177 | : theme.colorScheme.outline.withValues(alpha: 0.3), |
| 178 | width: isSelected ? 2 : 1, |
| 179 | ), |
| 180 | ), |
| 181 | child: Row( |
| 182 | children: [ |
| 183 | Container( |
| 184 | padding: const EdgeInsets.all(12), |
| 185 | decoration: BoxDecoration( |
| 186 | color: theme.scaffoldBackgroundColor, |
| 187 | borderRadius: BorderRadius.circular(12), |
| 188 | ), |
| 189 | child: iconWidget, |
| 190 | ), |
| 191 | const SizedBox(width: 16), |
| 192 | Expanded( |
| 193 | child: Column( |
| 194 | crossAxisAlignment: CrossAxisAlignment.start, |
| 195 | children: [ |
| 196 | Text( |
| 197 | title, |
| 198 | style: theme.textTheme.titleMedium?.copyWith( |
| 199 | fontWeight: FontWeight.bold, |
| 200 | ), |
| 201 | ), |
| 202 | const SizedBox(height: 4), |
| 203 | Text( |
| 204 | subtitle, |
| 205 | style: theme.textTheme.labelMedium?.copyWith( |
| 206 | color: theme.colorScheme.onSurface.withValues(alpha: 0.5), |
| 207 | ), |
| 208 | ), |
| 209 | ], |
| 210 | ), |
| 211 | ), |
| 212 | if (isSelected) |
| 213 | HugeIcon( |
| 214 | icon: HugeIcons.strokeRoundedCheckmarkCircle01, |
| 215 | color: theme.colorScheme.primary, |
| 216 | ), |
| 217 | ], |
| 218 | ), |
| 219 | ), |
| 220 | ); |
| 221 | } |
| 222 | } |