# App Settings & Theme System ## Overview The app uses a centralized `AppSettingsBox` (Hive) for storing all app-level settings. This includes theme preferences, language settings, notification preferences, and other user configurations. --- ## AppSettingsBox **Location**: `lib/core/database/app_settings_box.dart` ### Initialization ```dart // In main.dart - call before runApp() await AppSettingsBox.init(); ``` ### Storage Keys | Key | Type | Default | Description | |-----|------|---------|-------------| | **Theme** | | `seed_color_id` | String | `'blue'` | Selected theme color ID | | `theme_mode` | int | `0` | 0=system, 1=light, 2=dark | | **Language** | | `language_code` | String | `'vi'` | Language code (vi, en) | | **Notifications** | | `notifications_enabled` | bool | `true` | Master notification toggle | | `order_notifications` | bool | `true` | Order status notifications | | `promotion_notifications` | bool | `true` | Promotion notifications | | `chat_notifications` | bool | `true` | Chat message notifications | | **User Preferences** | | `onboarding_completed` | bool | `false` | Onboarding flow completed | | `biometric_enabled` | bool | `false` | Biometric login enabled | | `remember_login` | bool | `false` | Remember login credentials | | **App State** | | `last_sync_time` | String | - | Last data sync timestamp | | `app_version` | String | - | Last launched app version | | `first_launch_date` | String | - | First app launch date | ### Usage ```dart // Generic get/set AppSettingsBox.get('key', defaultValue: 'default'); await AppSettingsBox.set('key', value); // Helper methods AppSettingsBox.getSeedColorId(); // Returns 'blue', 'teal', etc. await AppSettingsBox.setSeedColorId('teal'); AppSettingsBox.getThemeModeIndex(); // Returns 0, 1, or 2 await AppSettingsBox.setThemeModeIndex(1); AppSettingsBox.getLanguageCode(); // Returns 'vi' or 'en' await AppSettingsBox.setLanguageCode('en'); AppSettingsBox.areNotificationsEnabled(); // Returns true/false AppSettingsBox.isOnboardingCompleted(); AppSettingsBox.isBiometricEnabled(); ``` --- ## Theme System ### Architecture ``` colors.dart → Seed color options & status colors app_theme.dart → ThemeData generation from seed color theme_provider.dart → Riverpod state management ``` ### Available Seed Colors | ID | Name | Color | |----|------|-------| | `blue` | Xanh dương | `#005B9A` (default) | | `teal` | Xanh ngọc | `#009688` | | `green` | Xanh lá | `#4CAF50` | | `purple` | Tím | `#673AB7` | | `indigo` | Chàm | `#3F51B5` | | `orange` | Cam | `#FF5722` | | `red` | Đỏ | `#E53935` | | `pink` | Hồng | `#E91E63` | ### Providers ```dart // Main theme settings provider (persisted) themeSettingsProvider // Convenience providers currentSeedColorProvider // Color - current seed color seedColorOptionsProvider // List - all options ``` ### Usage in App ```dart // app.dart - Dynamic theme class MyApp extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final settings = ref.watch(themeSettingsProvider); return MaterialApp( theme: AppTheme.lightTheme(settings.seedColor), darkTheme: AppTheme.darkTheme(settings.seedColor), themeMode: settings.themeMode, // ... ); } } ``` ### Changing Theme ```dart // Change seed color ref.read(themeSettingsProvider.notifier).setSeedColor('teal'); // Change theme mode ref.read(themeSettingsProvider.notifier).setThemeMode(ThemeMode.dark); // Toggle light/dark ref.read(themeSettingsProvider.notifier).toggleThemeMode(); ``` ### Color Picker Widget Example ```dart class ColorPickerWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final options = ref.watch(seedColorOptionsProvider); final current = ref.watch(themeSettingsProvider); return Wrap( spacing: 8, children: options.map((option) { final isSelected = option.id == current.seedColorId; return GestureDetector( onTap: () => ref .read(themeSettingsProvider.notifier) .setSeedColor(option.id), child: Container( width: 48, height: 48, decoration: BoxDecoration( color: option.color, shape: BoxShape.circle, border: isSelected ? Border.all(color: Colors.white, width: 3) : null, ), child: isSelected ? const Icon(Icons.check, color: Colors.white) : null, ), ); }).toList(), ); } } ``` --- ## Using ColorScheme With the `fromSeed()` approach, always use `Theme.of(context).colorScheme` for colors: ```dart // Via context extension (recommended) final cs = context.colorScheme; // Common color usage cs.primary // Main brand color (buttons, links) cs.onPrimary // Text/icons on primary color cs.primaryContainer // Softer brand background cs.onPrimaryContainer // Text on primaryContainer cs.secondary // Secondary accent cs.tertiary // Third accent color cs.surface // Card/container backgrounds cs.onSurface // Primary text color cs.onSurfaceVariant // Secondary text color cs.outline // Borders, dividers cs.outlineVariant // Lighter borders cs.error // Error states cs.onError // Text on error // Example widget Container( color: cs.primaryContainer, child: Text( 'Hello', style: TextStyle(color: cs.onPrimaryContainer), ), ) ``` ### Status Colors (Fixed) These colors don't change with theme (from backend): ```dart AppColors.success // #28a745 - Green AppColors.warning // #ffc107 - Yellow AppColors.danger // #dc3545 - Red AppColors.info // #17a2b8 - Blue ``` --- ## Files Reference | File | Purpose | |------|---------| | `lib/core/database/app_settings_box.dart` | Hive storage for all app settings | | `lib/core/theme/colors.dart` | Seed colors, status colors, gradients | | `lib/core/theme/app_theme.dart` | ThemeData generation | | `lib/core/theme/theme_provider.dart` | Riverpod providers for theme | | `lib/core/theme/typography.dart` | Text styles | --- ## Initialization Order ```dart // main.dart Future main() async { WidgetsFlutterBinding.ensureInitialized(); // 1. Initialize Hive await Hive.initFlutter(); // 2. Initialize AppSettingsBox await AppSettingsBox.init(); // 3. Initialize other boxes... runApp( ProviderScope( child: MyApp(), ), ); } ```