Files
worker/APP_SETTINGS.md
2025-12-01 11:31:26 +07:00

6.5 KiB

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

// 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

// Generic get/set
AppSettingsBox.get<String>('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

// Main theme settings provider (persisted)
themeSettingsProvider

// Convenience providers
currentSeedColorProvider     // Color - current seed color
seedColorOptionsProvider     // List<SeedColorOption> - all options

Usage in App

// 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

// 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

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:

// 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):

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

// main.dart
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 1. Initialize Hive
  await Hive.initFlutter();

  // 2. Initialize AppSettingsBox
  await AppSettingsBox.init();

  // 3. Initialize other boxes...

  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}