# Theme Implementation Guide - HMG Patient App

## Overview
This Flutter application implements a comprehensive **dual-theme system** supporting both **Light Mode** and **Dark Mode**. The theme system is built with a combination of Flutter's native theming and a custom color management system.

---

## Architecture

### 1. **Core Components**

#### A. AppTheme Class (`lib/theme/app_theme.dart`)
- **Purpose**: Defines the Material theme configurations for both light and dark modes
- **Key Methods**:
  - `getTheme(isArabic)` - Returns light theme configuration
  - `getDarkTheme(isArabic)` - Returns dark theme configuration

**Features**:
- Dynamic font family selection based on locale (Arabic: `CairoArabic`, English: `Poppins`)
- Platform-specific page transitions (Android: Zoom, iOS: Cupertino)
- Consistent styling for AppBar, BottomSheet, FloatingActionButton
- Transparent splash colors for better UX
- System overlay styles (Dark for light theme, Light for dark theme)

#### B. AppColors Class (`lib/theme/colors.dart`)
- **Purpose**: Centralized color management with dual-palette support
- **Architecture**: Three-tier color system

**Three Access Patterns**:

1. **Static Getters (Global State-Based)**
   ```dart
   AppColors.primaryRedColor  // Uses AppColors.isDarkMode flag
   ```
   - Checks global `AppColors.isDarkMode` boolean
   - Returns dark or light palette value accordingly

2. **AppColorsDark Class (Dark Palette)**
   ```dart
   AppColors.dark.primaryRedColor  // Always dark variant
   ```
   - Constant dark mode color values
   - Used as source for dark theme colors

3. **BuildContext Extension (Theme-Aware)**
   ```dart
   context.primaryRedColor  // Uses Theme brightness
   ```
   - Reads `Theme.of(context).brightness`
   - Automatically adapts to MaterialApp's themeMode

---

## 2. **Theme State Management**

### ProfileSettingsViewModel
Located in `lib/features/profile_settings/profile_settings_view_model.dart`

**Responsibilities**:
- Manages dark mode state (`_isDarkMode` boolean)
- Persists preference to local storage (CacheService)
- Triggers UI rebuilds on theme changes

**Key Methods**:

```dart
// Called at app startup (before first frame)
void loadDarkMode() {
  final saved = _cacheService.getBool(key: _darkModeKey);
  _isDarkMode = saved ?? false;
  AppColors.isDarkMode = _isDarkMode;
  // No notifyListeners() - called before build
}

// Toggle theme and persist
void toggleDarkMode(bool value) {
  _isDarkMode = value;
  AppColors.isDarkMode = value;
  _cacheService.saveBool(key: _darkModeKey, value: value);
  notifyListeners(); // Triggers rebuild
}
```

---

## 3. **Application Lifecycle**

### Initialization Flow (`main.dart`)

```dart
Future<void> callInitializations() async {
  // ... Firebase, dependencies setup ...
  
  // Restore dark mode BEFORE first frame
  getIt.get<ProfileSettingsViewModel>().loadDarkMode();
}
```

### Theme Application in Widget Tree

```dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ProfileSettingsViewModel>(
      builder: (context, profileVm, _) {
        final isArabic = EasyLocalization.of(context)?.locale.languageCode == "ar";
        
        return MaterialApp(
          key: ValueKey('app_theme_${profileVm.isDarkMode}'), // Force rebuild on theme change
          theme: AppTheme.getTheme(isArabic),
          darkTheme: AppTheme.getDarkTheme(isArabic),
          themeMode: profileVm.isDarkMode ? ThemeMode.dark : ThemeMode.light,
          // ... other properties
        );
      },
    );
  }
}
```

**Key Mechanism**:
- `Consumer<ProfileSettingsViewModel>` listens for theme changes
- When `toggleDarkMode()` is called → `notifyListeners()` → Widget rebuilds
- `themeMode` property switches between `ThemeMode.dark` and `ThemeMode.light`
- `ValueKey` forces MaterialApp to rebuild entirely on theme change

---

## 4. **Color System Design**

### Dual-Palette Architecture

```dart
class AppColors {
  static bool isDarkMode = false; // Global flag
  
  // Pattern: Conditional getter
  static Color get primaryRedColor => 
    isDarkMode ? dark.primaryRedColor : const Color(0xFFED1C2B);
  
  // Dark palette instance
  static const AppColorsDark dark = AppColorsDark();
}

class AppColorsDark {
  const AppColorsDark();
  
  // Dark mode variants
  Color get primaryRedColor => const Color(0xFFDE5C5D);
  Color get scaffoldBgColor => const Color(0xFF191919);
  Color get textColor => const Color(0xFFFFFFFF);
  // ... 100+ color definitions
}
```

### BuildContext Extension for Theme-Aware Colors

```dart
extension AppColorsContext on BuildContext {
  bool get _isDark => Theme.of(this).brightness == Brightness.dark;
  
  Color get scaffoldBgColor => 
    _isDark ? AppColors.dark.scaffoldBgColor : const Color(0xFFF8F8F8);
  
  Color get textColor => 
    _isDark ? AppColors.dark.textColor : const Color(0xFF2E3039);
}
```

**Usage in Widgets**:
```dart
// Option 1: Static (uses global flag)
color: AppColors.primaryRedColor

// Option 2: Extension (uses Theme.of(context))
color: context.primaryRedColor

// Option 3: Direct dark access
color: AppColors.dark.primaryRedColor
```

---

## 5. **User Interface Implementation**

### Theme Toggle Control (`profile_settings.dart`)

```dart
Consumer<ProfileSettingsViewModel>(
  builder: (context, profileVm, _) {
    return actionItem(
      AppAssets.darkModeIcon,
      LocaleKeys.darkMode.tr(context: context),
      () {
        profileVm.toggleDarkMode(!profileVm.isDarkMode);
      },
      switchValue: profileVm.isDarkMode,
      onSwitchChanged: (value) {
        profileVm.toggleDarkMode(value);
      },
    );
  },
)
```

---

## 6. **Color Categories**

### Organized Color Groups

| Category | Light Example | Dark Example |
|----------|---------------|--------------|
| **Scaffold/Background** | `0xFFF8F8F8` | `0xFF191919` |
| **Primary Brand** | `0xFFED1C2B` (Red) | `0xFFDE5C5D` (Softer Red) |
| **Text** | `0xFF2E3039` (Dark) | `0xFFFFFFFF` (White) |
| **Success** | `0xFF18C273` (Green) | `0xFF18C273` (Same) |
| **Error** | `0xFFED1C2B` | `0xFFD63D48` |
| **Card Surface** | `0xFFFFFFFF` | `0xFF1E1E1E` |
| **Borders** | `0x332E3039` | `0x55ECECEC` |
| **Shimmer Base** | `0xFFE0E0E0` | `0xFF2C2C2C` |

### Special Purpose Colors
- **Rating Stars**: Constant across themes (`0xFFFFA726`)
- **Health Calculators**: Feature-specific colors maintained in both themes
- **Status Colors**: Pending, Processing, Completed, Rejected
- **Info Banners**: Warning backgrounds with adjusted opacity for dark mode

---

## 7. **Best Practices for Developers**

### Adding New Colors

1. **Define in Light Theme**:
```dart
static Color get newFeatureColor => 
  isDarkMode ? dark.newFeatureColor : const Color(0xFFXXXXXX);
```

2. **Add Dark Variant**:
```dart
class AppColorsDark {
  Color get newFeatureColor => const Color(0xFFYYYYYY);
}
```

3. **Optional: Add to BuildContext Extension**:
```dart
extension AppColorsContext on BuildContext {
  Color get newFeatureColor => 
    _isDark ? AppColors.dark.newFeatureColor : const Color(0xFFXXXXXX);
}
```

### Using Colors in Widgets

**Recommended Approach**:
```dart
// For colors that should adapt to theme
Container(
  color: AppColors.scaffoldBgColor, // Uses global isDarkMode
)

// Or using context extension
Container(
  color: context.scaffoldBgColor, // Uses Theme.brightness
)
```

**Avoid**:
```dart
// Don't hardcode colors
Container(
  color: Color(0xFFED1C2B), // ❌ Won't adapt to dark mode
)
```

### Testing Theme Changes

```dart
// Toggle theme programmatically
context.read<ProfileSettingsViewModel>().toggleDarkMode(true);

// Check current state
final isDark = context.read<ProfileSettingsViewModel>().isDarkMode;
```

---

## 8. **Persistence Layer**

### CacheService Integration
- Uses shared_preferences or similar local storage
- Key: `_darkModeKey` (defined in ProfileSettingsViewModel)
- Automatically loads on app startup
- Saves immediately on toggle

**Flow**:
1. App launches → `loadDarkMode()` reads from cache
2. User toggles → `toggleDarkMode(value)` saves to cache
3. App restart → Previous preference restored

---

## 9. **Font Handling**

### Locale-Specific Fonts

```dart
// In AppTheme
fontFamily: isArabic ? 'CairoArabic' : 'Poppins'

textTheme: const TextTheme(
  displayLarge: TextStyle(fontFamily: 'CairoArabic'),
  bodyLarge: TextStyle(fontFamily: 'CairoArabic'),
)
```

**Rationale**: Arabic text requires specialized fonts for proper rendering

---

## 10. **System Integration**

### AppBar System Overlay

```dart
// Light Theme
systemOverlayStyle: SystemUiOverlayStyle.dark  // Dark status bar icons

// Dark Theme
systemOverlayStyle: SystemUiOverlayStyle.light  // Light status bar icons
```

### Platform-Specific Adjustments

```dart
// SafeArea handling
SafeArea(
  top: false,
  bottom: Platform.isIOS ? false : true,
)
```

---

## 11. **Advanced Features**

### Gradient Support
```dart
static const LinearGradient aiLinearGradient = LinearGradient(
  colors: [Color(0xFF8A38F5), Color(0xFFE20BBB)],
  begin: Alignment.topLeft,
  end: Alignment.bottomRight,
);
```
*Note: Gradients remain constant across themes for brand consistency*

### Transparency Management
```dart
static const transparent = Colors.transparent;
// Used for splash colors, bottomSheet backgrounds
```

---

## 12. **Common Pitfalls & Solutions**

### Issue 1: Colors Not Updating
**Problem**: Widget doesn't reflect theme change
**Solution**: Ensure widget rebuilds on theme change
```dart
// Wrap with Consumer or use context.watch
Consumer<ProfileSettingsViewModel>(
  builder: (context, vm, _) => YourWidget(),
)
```

### Issue 2: Inconsistent Colors
**Problem**: Some UI elements use wrong theme
**Solution**: Always use `AppColors.*` or `context.*`, never hardcode

### Issue 3: Theme Not Persisting
**Problem**: Theme resets on app restart
**Solution**: Verify `loadDarkMode()` is called in `callInitializations()`

---

## 13. **File Structure**

```
lib/
├── theme/
│   ├── app_theme.dart          # Theme configurations
│   └── colors.dart             # Color definitions & dark palette
├── features/
│   └── profile_settings/
│       └── profile_settings_view_model.dart  # Theme state management
├── presentation/
│   └── profile_settings/
│       └── profile_settings.dart  # UI with theme toggle
└── main.dart                   # Theme initialization & application
```

---

## 14. **Summary**

### Workflow
1. **Initialization**: Load saved theme preference → Set `AppColors.isDarkMode`
2. **User Action**: Toggle switch in Settings → Call `toggleDarkMode()`
3. **State Update**: Update flag → Save to cache → Notify listeners
4. **UI Rebuild**: Consumer rebuilds → MaterialApp switches `themeMode`
5. **Color Resolution**: All `AppColors.*` getters return appropriate palette

### Key Advantages
✅ **Centralized**: Single source of truth for colors  
✅ **Type-Safe**: Compile-time color checking  
✅ **Persistent**: Survives app restarts  
✅ **Flexible**: Multiple access patterns for different use cases  
✅ **Maintainable**: Easy to add/modify colors  
✅ **Performance**: No runtime color calculations, just conditional returns  

---

## 15. **Migration Checklist for New Features**

When adding a new screen/feature:

- [ ] Use `AppColors.*` for all color references
- [ ] Test in both light and dark modes
- [ ] Ensure text contrast meets accessibility standards
- [ ] Add dark variants for any new colors
- [ ] Verify with Arabic locale (font rendering)
- [ ] Check shimmer/loading states in both themes
- [ ] Test on both iOS and Android

---

**Last Updated**: January 2024  
**Maintained By**: HMG Development Team

