Files
afterwork/lib/core/theme/app_theme.dart
dahoud 92612abbd7 fix(chat): Correction race condition + Implémentation TODOs
## Corrections Critiques

### Race Condition - Statuts de Messages
- Fix : Les icônes de statut (✓, ✓✓, ✓✓ bleu) ne s'affichaient pas
- Cause : WebSocket delivery confirmations arrivaient avant messages locaux
- Solution : Pattern Optimistic UI dans chat_bloc.dart
  - Création message temporaire immédiate
  - Ajout à la liste AVANT requête HTTP
  - Remplacement par message serveur à la réponse
- Fichier : lib/presentation/state_management/chat_bloc.dart

## Implémentation TODOs (13/21)

### Social (social_header_widget.dart)
-  Copier lien du post dans presse-papiers
-  Partage natif via Share.share()
-  Dialogue de signalement avec 5 raisons

### Partage (share_post_dialog.dart)
-  Interface sélection d'amis avec checkboxes
-  Partage externe via Share API

### Média (media_upload_service.dart)
-  Parsing JSON réponse backend
-  Méthode deleteMedia() pour suppression
-  Génération miniature vidéo

### Posts (create_post_dialog.dart, edit_post_dialog.dart)
-  Extraction URL depuis uploads
-  Documentation chargement médias

### Chat (conversations_screen.dart)
-  Navigation vers notifications
-  ConversationSearchDelegate pour recherche

## Nouveaux Fichiers

### Configuration
- build-prod.ps1 : Script build production avec dart-define
- lib/core/constants/env_config.dart : Gestion environnements

### Documentation
- TODOS_IMPLEMENTED.md : Documentation complète TODOs

## Améliorations

### Architecture
- Refactoring injection de dépendances
- Amélioration routing et navigation
- Optimisation providers (UserProvider, FriendsProvider)

### UI/UX
- Amélioration thème et couleurs
- Optimisation animations
- Meilleure gestion erreurs

### Services
- Configuration API avec env_config
- Amélioration datasources (events, users)
- Optimisation modèles de données
2026-01-10 10:43:17 +00:00

995 lines
32 KiB
Dart

import 'package:flutter/material.dart';
import '../constants/colors.dart';
import '../constants/design_system.dart';
/// Classe qui définit les thèmes de l'application AfterWork.
///
/// Thème moderne et cohérent avec Material Design 3, optimisé pour:
/// - Border radius: 4-12px (DesignSystem)
/// - Padding: 6-20px (compact)
/// - Typography: 11-17px (lisible et dense)
/// - Élévations: 0.5-3 max (subtil)
class AppTheme {
/// Thème clair - Design moderne Material 3
static final ThemeData lightTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.light,
// =========================================================================
// COULEURS DE BASE
// =========================================================================
primaryColor: AppColors.lightPrimary,
scaffoldBackgroundColor: AppColors.lightBackground,
cardColor: AppColors.lightCardColor,
// =========================================================================
// COLOR SCHEME - Material 3 complet
// =========================================================================
colorScheme: ColorScheme.light(
// Couleurs primaires
primary: AppColors.lightPrimary,
onPrimary: AppColors.lightOnPrimary,
primaryContainer: AppColors.lightPrimary.withOpacity(0.12),
onPrimaryContainer: AppColors.lightPrimary,
// Couleurs secondaires
secondary: AppColors.lightSecondary,
onSecondary: AppColors.lightOnSecondary,
secondaryContainer: AppColors.lightSecondary.withOpacity(0.12),
onSecondaryContainer: AppColors.lightSecondary,
// Couleur tertiaire
tertiary: AppColors.lightAccentColor,
onTertiary: Colors.white,
tertiaryContainer: AppColors.lightAccentColor.withOpacity(0.12),
onTertiaryContainer: AppColors.lightAccentColor,
// Surfaces
surface: AppColors.lightSurface,
onSurface: AppColors.lightTextPrimary,
surfaceVariant: const Color(0xFFF5F5F5),
onSurfaceVariant: AppColors.lightTextSecondary,
// Erreur
error: AppColors.lightError,
onError: AppColors.lightOnPrimary,
errorContainer: AppColors.lightError.withOpacity(0.12),
onErrorContainer: AppColors.lightError,
// Autres
outline: const Color(0xFFE0E0E0),
outlineVariant: const Color(0xFFF5F5F5),
shadow: Colors.black.withOpacity(0.1),
scrim: Colors.black.withOpacity(0.5),
inverseSurface: const Color(0xFF212121),
onInverseSurface: Colors.white,
inversePrimary: AppColors.lightPrimary.withOpacity(0.8),
),
// =========================================================================
// APP BAR
// =========================================================================
appBarTheme: const AppBarTheme(
backgroundColor: Colors.transparent,
foregroundColor: AppColors.lightTextPrimary,
elevation: 0,
scrolledUnderElevation: 2,
centerTitle: false,
iconTheme: IconThemeData(
color: AppColors.lightTextPrimary,
size: 22,
),
titleTextStyle: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 20,
fontWeight: FontWeight.bold,
letterSpacing: -0.5,
),
),
// =========================================================================
// NAVIGATION BAR - Material 3
// =========================================================================
navigationBarTheme: NavigationBarThemeData(
height: 64,
elevation: 0,
backgroundColor: AppColors.lightSurface,
indicatorColor: AppColors.lightPrimary.withOpacity(0.12),
iconTheme: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return const IconThemeData(
color: AppColors.lightPrimary,
size: 26,
);
}
return IconThemeData(
color: AppColors.lightTextSecondary,
size: 24,
);
}),
labelTextStyle: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return const TextStyle(
color: AppColors.lightPrimary,
fontSize: 12,
fontWeight: FontWeight.w600,
);
}
return TextStyle(
color: AppColors.lightTextSecondary,
fontSize: 12,
fontWeight: FontWeight.w500,
);
}),
labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
),
// =========================================================================
// TAB BAR
// =========================================================================
tabBarTheme: TabBarTheme(
indicatorSize: TabBarIndicatorSize.tab,
labelColor: AppColors.lightPrimary,
unselectedLabelColor: AppColors.lightTextSecondary,
labelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
unselectedLabelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: AppColors.lightPrimary,
width: 2,
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(DesignSystem.radiusSm),
),
),
),
// =========================================================================
// TYPOGRAPHY
// =========================================================================
textTheme: const TextTheme(
// Display
displayLarge: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 28,
fontWeight: FontWeight.bold,
letterSpacing: -0.5,
),
displayMedium: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 24,
fontWeight: FontWeight.bold,
letterSpacing: -0.25,
),
displaySmall: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 20,
fontWeight: FontWeight.bold,
),
// Headline
headlineLarge: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 20,
fontWeight: FontWeight.w600,
),
headlineMedium: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 18,
fontWeight: FontWeight.w600,
),
headlineSmall: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 17,
fontWeight: FontWeight.w600,
),
// Title
titleLarge: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 17,
fontWeight: FontWeight.w600,
),
titleMedium: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 15,
fontWeight: FontWeight.w600,
),
titleSmall: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 14,
fontWeight: FontWeight.w600,
),
// Body
bodyLarge: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 15,
height: 1.5,
),
bodyMedium: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 14,
height: 1.5,
),
bodySmall: TextStyle(
color: AppColors.lightTextSecondary,
fontSize: 13,
height: 1.4,
),
// Label
labelLarge: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 14,
fontWeight: FontWeight.w600,
),
labelMedium: TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 13,
fontWeight: FontWeight.w600,
),
labelSmall: TextStyle(
color: AppColors.lightTextSecondary,
fontSize: 11,
fontWeight: FontWeight.w500,
),
),
// =========================================================================
// BUTTONS
// =========================================================================
// ElevatedButton
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.lightPrimary,
foregroundColor: AppColors.lightOnPrimary,
elevation: 1,
shadowColor: Colors.black.withOpacity(0.1),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// FilledButton (Material 3)
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: AppColors.lightPrimary,
foregroundColor: AppColors.lightOnPrimary,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// OutlinedButton
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.lightPrimary,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
side: const BorderSide(color: AppColors.lightPrimary, width: 1.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// TextButton
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColors.lightPrimary,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// =========================================================================
// INPUT DECORATION
// =========================================================================
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.lightSurface,
labelStyle: TextStyle(
color: AppColors.lightTextSecondary,
fontSize: 14,
),
hintStyle: TextStyle(
color: AppColors.lightTextSecondary.withOpacity(0.6),
fontSize: 14,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingMd,
vertical: DesignSystem.spacingSm,
),
border: OutlineInputBorder(
borderSide: BorderSide(color: const Color(0xFFE0E0E0)),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: const Color(0xFFE0E0E0)),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColors.lightPrimary, width: 2),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColors.lightError, width: 1.5),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColors.lightError, width: 2),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
),
// =========================================================================
// FLOATING ACTION BUTTON
// =========================================================================
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: AppColors.lightPrimary,
foregroundColor: AppColors.lightOnPrimary,
elevation: 2,
focusElevation: 4,
hoverElevation: 4,
highlightElevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusLg),
),
),
// =========================================================================
// CARD
// =========================================================================
cardTheme: CardTheme(
color: AppColors.lightCardColor,
elevation: 1,
shadowColor: Colors.black.withOpacity(0.05),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
margin: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingMd,
vertical: DesignSystem.spacingSm,
),
),
// =========================================================================
// DIALOG
// =========================================================================
dialogTheme: DialogTheme(
backgroundColor: AppColors.lightSurface,
elevation: 3,
shadowColor: Colors.black.withOpacity(0.1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
titleTextStyle: const TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 17,
fontWeight: FontWeight.bold,
),
contentTextStyle: const TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 14,
height: 1.5,
),
),
// =========================================================================
// BOTTOM SHEET
// =========================================================================
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: AppColors.lightSurface,
elevation: 3,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(DesignSystem.radiusLg),
),
),
modalElevation: 8,
modalBackgroundColor: AppColors.lightSurface,
),
// =========================================================================
// DIVIDER
// =========================================================================
dividerTheme: DividerThemeData(
color: const Color(0xFFE0E0E0),
thickness: 1,
space: 1,
),
// =========================================================================
// ICON THEME
// =========================================================================
iconTheme: const IconThemeData(
color: AppColors.lightTextPrimary,
size: 22,
),
// =========================================================================
// LIST TILE
// =========================================================================
listTileTheme: ListTileThemeData(
contentPadding: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingMd,
vertical: DesignSystem.spacingSm,
),
iconColor: AppColors.lightTextPrimary,
textColor: AppColors.lightTextPrimary,
titleTextStyle: const TextStyle(
color: AppColors.lightTextPrimary,
fontSize: 14,
fontWeight: FontWeight.w600,
),
subtitleTextStyle: TextStyle(
color: AppColors.lightTextSecondary,
fontSize: 13,
),
),
// =========================================================================
// CHIP
// =========================================================================
chipTheme: ChipThemeData(
backgroundColor: AppColors.lightPrimary.withOpacity(0.12),
deleteIconColor: AppColors.lightPrimary,
labelStyle: const TextStyle(
color: AppColors.lightPrimary,
fontSize: 13,
fontWeight: FontWeight.w500,
),
padding: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingSm,
vertical: 4,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusSm),
),
),
// =========================================================================
// PROGRESS INDICATOR
// =========================================================================
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColors.lightPrimary,
linearTrackColor: Color(0xFFE0E0E0),
circularTrackColor: Color(0xFFE0E0E0),
),
);
/// Thème sombre - Design moderne Material 3
static final ThemeData darkTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
// =========================================================================
// COULEURS DE BASE
// =========================================================================
primaryColor: AppColors.darkPrimary,
scaffoldBackgroundColor: AppColors.darkBackground,
cardColor: AppColors.darkCardColor,
// =========================================================================
// COLOR SCHEME - Material 3 complet
// =========================================================================
colorScheme: ColorScheme.dark(
// Couleurs primaires
primary: AppColors.darkSecondary,
onPrimary: AppColors.darkOnPrimary,
primaryContainer: AppColors.darkSecondary.withOpacity(0.2),
onPrimaryContainer: AppColors.darkSecondary,
// Couleurs secondaires
secondary: AppColors.darkAccentColor,
onSecondary: Colors.black,
secondaryContainer: AppColors.darkAccentColor.withOpacity(0.2),
onSecondaryContainer: AppColors.darkAccentColor,
// Couleur tertiaire
tertiary: const Color(0xFF64B5F6),
onTertiary: Colors.black,
tertiaryContainer: const Color(0xFF64B5F6).withOpacity(0.2),
onTertiaryContainer: const Color(0xFF64B5F6),
// Surfaces
surface: AppColors.darkSurface,
onSurface: AppColors.darkTextPrimary,
surfaceVariant: const Color(0xFF2C2C2C),
onSurfaceVariant: AppColors.darkTextSecondary,
// Erreur
error: AppColors.darkError,
onError: Colors.white,
errorContainer: AppColors.darkError.withOpacity(0.2),
onErrorContainer: AppColors.darkError,
// Autres
outline: const Color(0xFF424242),
outlineVariant: const Color(0xFF2C2C2C),
shadow: Colors.black.withOpacity(0.3),
scrim: Colors.black.withOpacity(0.7),
inverseSurface: Colors.white,
onInverseSurface: Colors.black,
inversePrimary: AppColors.darkSecondary.withOpacity(0.8),
),
// =========================================================================
// APP BAR
// =========================================================================
appBarTheme: const AppBarTheme(
backgroundColor: Colors.transparent,
foregroundColor: AppColors.darkTextPrimary,
elevation: 0,
scrolledUnderElevation: 2,
centerTitle: false,
iconTheme: IconThemeData(
color: AppColors.darkTextPrimary,
size: 22,
),
titleTextStyle: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 20,
fontWeight: FontWeight.bold,
letterSpacing: -0.5,
),
),
// =========================================================================
// NAVIGATION BAR - Material 3
// =========================================================================
navigationBarTheme: NavigationBarThemeData(
height: 64,
elevation: 0,
backgroundColor: AppColors.darkSurface,
indicatorColor: AppColors.darkSecondary.withOpacity(0.2),
iconTheme: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return const IconThemeData(
color: AppColors.darkSecondary,
size: 26,
);
}
return IconThemeData(
color: AppColors.darkTextSecondary,
size: 24,
);
}),
labelTextStyle: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return const TextStyle(
color: AppColors.darkSecondary,
fontSize: 12,
fontWeight: FontWeight.w600,
);
}
return TextStyle(
color: AppColors.darkTextSecondary,
fontSize: 12,
fontWeight: FontWeight.w500,
);
}),
labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
),
// =========================================================================
// TAB BAR
// =========================================================================
tabBarTheme: TabBarTheme(
indicatorSize: TabBarIndicatorSize.tab,
labelColor: AppColors.darkSecondary,
unselectedLabelColor: AppColors.darkTextSecondary,
labelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
unselectedLabelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: AppColors.darkSecondary,
width: 2,
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(DesignSystem.radiusSm),
),
),
),
// =========================================================================
// TYPOGRAPHY
// =========================================================================
textTheme: const TextTheme(
// Display
displayLarge: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 28,
fontWeight: FontWeight.bold,
letterSpacing: -0.5,
),
displayMedium: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 24,
fontWeight: FontWeight.bold,
letterSpacing: -0.25,
),
displaySmall: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 20,
fontWeight: FontWeight.bold,
),
// Headline
headlineLarge: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 20,
fontWeight: FontWeight.w600,
),
headlineMedium: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 18,
fontWeight: FontWeight.w600,
),
headlineSmall: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 17,
fontWeight: FontWeight.w600,
),
// Title
titleLarge: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 17,
fontWeight: FontWeight.w600,
),
titleMedium: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 15,
fontWeight: FontWeight.w600,
),
titleSmall: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 14,
fontWeight: FontWeight.w600,
),
// Body
bodyLarge: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 15,
height: 1.5,
),
bodyMedium: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 14,
height: 1.5,
),
bodySmall: TextStyle(
color: AppColors.darkTextSecondary,
fontSize: 13,
height: 1.4,
),
// Label
labelLarge: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 14,
fontWeight: FontWeight.w600,
),
labelMedium: TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 13,
fontWeight: FontWeight.w600,
),
labelSmall: TextStyle(
color: AppColors.darkTextSecondary,
fontSize: 11,
fontWeight: FontWeight.w500,
),
),
// =========================================================================
// BUTTONS
// =========================================================================
// ElevatedButton
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.darkSecondary,
foregroundColor: AppColors.darkOnPrimary,
elevation: 1,
shadowColor: Colors.black.withOpacity(0.3),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// FilledButton (Material 3)
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: AppColors.darkSecondary,
foregroundColor: AppColors.darkOnPrimary,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// OutlinedButton
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.darkSecondary,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
side: const BorderSide(color: AppColors.darkSecondary, width: 1.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// TextButton
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColors.darkSecondary,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// =========================================================================
// INPUT DECORATION
// =========================================================================
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.darkSurface,
labelStyle: TextStyle(
color: AppColors.darkTextSecondary,
fontSize: 14,
),
hintStyle: TextStyle(
color: AppColors.darkTextSecondary.withOpacity(0.6),
fontSize: 14,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingMd,
vertical: DesignSystem.spacingSm,
),
border: OutlineInputBorder(
borderSide: BorderSide(color: const Color(0xFF424242)),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: const Color(0xFF424242)),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColors.darkSecondary, width: 2),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColors.darkError, width: 1.5),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColors.darkError, width: 2),
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
),
// =========================================================================
// FLOATING ACTION BUTTON
// =========================================================================
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: AppColors.darkSecondary,
foregroundColor: AppColors.darkOnPrimary,
elevation: 2,
focusElevation: 4,
hoverElevation: 4,
highlightElevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusLg),
),
),
// =========================================================================
// CARD
// =========================================================================
cardTheme: CardTheme(
color: AppColors.darkCardColor,
elevation: 1,
shadowColor: Colors.black.withOpacity(0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
margin: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingMd,
vertical: DesignSystem.spacingSm,
),
),
// =========================================================================
// DIALOG
// =========================================================================
dialogTheme: DialogTheme(
backgroundColor: AppColors.darkSurface,
elevation: 3,
shadowColor: Colors.black.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusMd),
),
titleTextStyle: const TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 17,
fontWeight: FontWeight.bold,
),
contentTextStyle: const TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 14,
height: 1.5,
),
),
// =========================================================================
// BOTTOM SHEET
// =========================================================================
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: AppColors.darkSurface,
elevation: 3,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(DesignSystem.radiusLg),
),
),
modalElevation: 8,
modalBackgroundColor: AppColors.darkSurface,
),
// =========================================================================
// DIVIDER
// =========================================================================
dividerTheme: DividerThemeData(
color: const Color(0xFF424242),
thickness: 1,
space: 1,
),
// =========================================================================
// ICON THEME
// =========================================================================
iconTheme: const IconThemeData(
color: AppColors.darkTextPrimary,
size: 22,
),
// =========================================================================
// LIST TILE
// =========================================================================
listTileTheme: ListTileThemeData(
contentPadding: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingMd,
vertical: DesignSystem.spacingSm,
),
iconColor: AppColors.darkTextPrimary,
textColor: AppColors.darkTextPrimary,
titleTextStyle: const TextStyle(
color: AppColors.darkTextPrimary,
fontSize: 14,
fontWeight: FontWeight.w600,
),
subtitleTextStyle: TextStyle(
color: AppColors.darkTextSecondary,
fontSize: 13,
),
),
// =========================================================================
// CHIP
// =========================================================================
chipTheme: ChipThemeData(
backgroundColor: AppColors.darkSecondary.withOpacity(0.2),
deleteIconColor: AppColors.darkSecondary,
labelStyle: const TextStyle(
color: AppColors.darkSecondary,
fontSize: 13,
fontWeight: FontWeight.w500,
),
padding: const EdgeInsets.symmetric(
horizontal: DesignSystem.spacingSm,
vertical: 4,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(DesignSystem.radiusSm),
),
),
// =========================================================================
// PROGRESS INDICATOR
// =========================================================================
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColors.darkSecondary,
linearTrackColor: Color(0xFF424242),
circularTrackColor: Color(0xFF424242),
),
);
}