import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../core/constants/enums.dart'; import '../../../../core/theme/branding_config.dart'; import '../../../../core/theme/theme_provider.dart'; import '../../../../shared/widgets/app_button.dart'; import '../providers/settings_provider.dart'; import '../widgets/settings_widgets.dart'; import '../../../../shared/widgets/app_toast.dart'; class _BrandThemePreset { const _BrandThemePreset({ required this.name, required this.primary, required this.secondary, }); final String name; final int primary; final int secondary; bool matches(BrandingConfig branding) => branding.primaryColorValue == primary && branding.secondaryColorValue == secondary; } const _brandThemePresets = <_BrandThemePreset>[ _BrandThemePreset( name: 'Ocean Blue', primary: 0xFF2563EB, secondary: 0xFF0891B2, ), _BrandThemePreset( name: 'Royal Purple', primary: 0xFF6D28D9, secondary: 0xFF0F766E, ), _BrandThemePreset( name: 'Emerald Green', primary: 0xFF15803D, secondary: 0xFF0F766E, ), _BrandThemePreset( name: 'Sunset Orange', primary: 0xFFEA580C, secondary: 0xFFD97706, ), _BrandThemePreset( name: 'Crimson Red', primary: 0xFFDC2626, secondary: 0xFFB45309, ), _BrandThemePreset( name: 'Indigo Sky', primary: 0xFF4F46E5, secondary: 0xFF0284C7, ), _BrandThemePreset( name: 'Slate Blue', primary: 0xFF334155, secondary: 0xFF2563EB, ), _BrandThemePreset( name: 'Teal Mint', primary: 0xFF0F766E, secondary: 0xFF059669, ), _BrandThemePreset( name: 'Rose Pink', primary: 0xFFDB2777, secondary: 0xFF7C3AED, ), _BrandThemePreset( name: 'Charcoal Gold', primary: 0xFF374151, secondary: 0xFFD97706, ), ]; class AppearanceSettingsScreen extends ConsumerWidget { const AppearanceSettingsScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final themeMode = ref.watch(themeModeProvider); final branding = ref.watch(brandingProvider); final uiPrefs = ref.watch(appSettingsProvider).uiPreferences; final selectedPreset = _brandThemePresets .where((preset) => preset.matches(branding)) .firstOrNull; return SettingsPageLayout( title: 'Appearance', subtitle: 'Theme, branding, and UI preferences', child: Column( children: [ SettingsFormCard( title: 'Theme', children: [ ...ThemeModeOption.values.map( (mode) => RadioListTile( title: Text(_themeLabel(mode)), value: mode, groupValue: themeMode, onChanged: (v) { if (v != null) { ref.read(themeModeProvider.notifier).setThemeMode(v); } }, ), ), ], ), const SizedBox(height: 16), SettingsFormCard( title: 'Branding', subtitle: 'Professionally curated primary and secondary color pairs', children: [ _BrandingPreviewCard( primary: branding.primaryColor, secondary: branding.secondaryColor, themeName: selectedPreset?.name ?? 'Custom', primaryHex: _hex(branding.primaryColorValue), secondaryHex: _hex(branding.secondaryColorValue), ), const SizedBox(height: 20), Text( 'Color themes', style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Text( 'Choose a cohesive pair optimized for light and dark modes.', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 12), LayoutBuilder( builder: (context, constraints) { final width = constraints.maxWidth; final crossAxisCount = width >= 720 ? 3 : width >= 480 ? 2 : 1; final spacing = 12.0; final itemWidth = (width - spacing * (crossAxisCount - 1)) / crossAxisCount; return Wrap( spacing: spacing, runSpacing: spacing, children: [ for (final preset in _brandThemePresets) SizedBox( width: itemWidth, child: _ThemePresetCard( preset: preset, selected: preset.matches(branding), onTap: () { ref.read(brandingProvider.notifier).updateBranding( branding.copyWith( primaryColorValue: preset.primary, secondaryColorValue: preset.secondary, ), ); }, ), ), ], ); }, ), ], ), const SizedBox(height: 16), SettingsFormCard( title: 'Navigation Layout', subtitle: 'Choose how the main menu is displayed', children: [ ...NavigationLayout.values.map( (layout) => RadioListTile( title: Text(layout.label), subtitle: Text( layout == NavigationLayout.sidebar ? 'Vertical sidebar on the left (default)' : 'Horizontal menu bar at the top', ), value: layout, groupValue: NavigationLayout.fromValue(uiPrefs.navigationLayout), onChanged: (v) { if (v != null) { ref .read(appSettingsProvider.notifier) .updateUiPreferences( uiPrefs.copyWith(navigationLayout: v.value), ); } }, ), ), ], ), const SizedBox(height: 16), SettingsFormCard( title: 'UI Preferences', children: [ SettingsSwitchTile( title: 'Sidebar Expanded By Default', subtitle: 'Show full sidebar labels on login', value: uiPrefs.sidebarExpanded, onChanged: (v) => ref .read(appSettingsProvider.notifier) .updateUiPreferences(uiPrefs.copyWith(sidebarExpanded: v)), ), SettingsDropdownField( label: 'Dashboard Layout', value: uiPrefs.dashboardLayout, items: const ['default', 'compact', 'analytics'], itemLabel: (v) => v[0].toUpperCase() + v.substring(1), onChanged: (v) { if (v != null) { ref.read(appSettingsProvider.notifier).updateUiPreferences( uiPrefs.copyWith(dashboardLayout: v), ); } }, ), const SizedBox(height: 16), SettingsDropdownField( label: 'Table Density', value: uiPrefs.tableDensity, items: const ['compact', 'comfortable', 'spacious'], itemLabel: (v) => v[0].toUpperCase() + v.substring(1), onChanged: (v) { if (v != null) { ref.read(appSettingsProvider.notifier).updateUiPreferences( uiPrefs.copyWith(tableDensity: v), ); } }, ), const SizedBox(height: 16), SettingsDropdownField( label: 'Pagination Size', value: uiPrefs.paginationSize, items: const [10, 20, 50, 100], itemLabel: (v) => '$v rows', onChanged: (v) { if (v != null) { ref.read(appSettingsProvider.notifier).updateUiPreferences( uiPrefs.copyWith(paginationSize: v), ); } }, ), ], ), const SizedBox(height: 24), AppButton( label: 'Settings Auto-Saved', onPressed: () { showAppToastFromSnackBar( context, const SnackBar( content: Text('Appearance settings are saved automatically'), ), ); }, ), ], ), ); } String _themeLabel(ThemeModeOption mode) => switch (mode) { ThemeModeOption.light => 'Light Theme', ThemeModeOption.dark => 'Dark Theme', ThemeModeOption.system => 'System Theme', }; static String _hex(int value) => '#${value.toRadixString(16).padLeft(8, '0').substring(2).toUpperCase()}'; } class _BrandingPreviewCard extends StatelessWidget { const _BrandingPreviewCard({ required this.primary, required this.secondary, required this.themeName, required this.primaryHex, required this.secondaryHex, }); final Color primary; final Color secondary; final String themeName; final String primaryHex; final String secondaryHex; @override Widget build(BuildContext context) { final theme = Theme.of(context); final onPrimary = ThemeData.estimateBrightnessForColor(primary) == Brightness.dark ? Colors.white : Colors.black87; return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: theme.colorScheme.outline.withValues(alpha: 0.2), ), color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.35), ), clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), color: primary, child: Row( children: [ Icon(Icons.dashboard_outlined, color: onPrimary, size: 18), const SizedBox(width: 8), Expanded( child: Text( 'Bharat ERP · $themeName', style: theme.textTheme.labelLarge?.copyWith( color: onPrimary, fontWeight: FontWeight.w700, ), ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: secondary, borderRadius: BorderRadius.circular(999), ), child: Text( 'Accent', style: theme.textTheme.labelSmall?.copyWith( color: ThemeData.estimateBrightnessForColor(secondary) == Brightness.dark ? Colors.white : Colors.black87, fontWeight: FontWeight.w600, ), ), ), ], ), ), Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Live preview', style: theme.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w700, ), ), const SizedBox(height: 4), Text( 'How headers, primary actions, and secondary accents will look.', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 14), Row( children: [ Expanded( child: FilledButton.icon( onPressed: () {}, style: FilledButton.styleFrom( backgroundColor: primary, foregroundColor: onPrimary, ), icon: const Icon(Icons.add, size: 18), label: const Text('Add'), ), ), const SizedBox(width: 10), Expanded( child: OutlinedButton( onPressed: () {}, style: OutlinedButton.styleFrom( foregroundColor: secondary, side: BorderSide( color: secondary.withValues(alpha: 0.55), ), ), child: const Text('Export'), ), ), ], ), const SizedBox(height: 14), Row( children: [ _ColorSwatchLabel( color: primary, label: 'Primary', hex: primaryHex, ), const SizedBox(width: 16), _ColorSwatchLabel( color: secondary, label: 'Secondary', hex: secondaryHex, ), ], ), ], ), ), ], ), ); } } class _ColorSwatchLabel extends StatelessWidget { const _ColorSwatchLabel({ required this.color, required this.label, required this.hex, }); final Color color; final String label; final String hex; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Row( children: [ Container( width: 36, height: 36, decoration: BoxDecoration( color: color, shape: BoxShape.circle, border: Border.all( color: theme.colorScheme.outline.withValues(alpha: 0.25), ), boxShadow: [ BoxShadow( color: color.withValues(alpha: 0.28), blurRadius: 8, offset: const Offset(0, 2), ), ], ), ), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: theme.textTheme.labelLarge?.copyWith( fontWeight: FontWeight.w600, ), ), Text( hex, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), ], ); } } class _ThemePresetCard extends StatelessWidget { const _ThemePresetCard({ required this.preset, required this.selected, required this.onTap, }); final _BrandThemePreset preset; final bool selected; final VoidCallback onTap; @override Widget build(BuildContext context) { final theme = Theme.of(context); final primary = Color(preset.primary); final secondary = Color(preset.secondary); final borderColor = selected ? primary : theme.colorScheme.outline.withValues(alpha: 0.28); return Material( color: selected ? primary.withValues(alpha: 0.06) : theme.colorScheme.surface, borderRadius: BorderRadius.circular(12), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: AnimatedContainer( duration: const Duration(milliseconds: 180), curve: Curves.easeOut, padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: borderColor, width: selected ? 2 : 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ _StackedColorCircles( primary: primary, secondary: secondary, ), const Spacer(), if (selected) Container( width: 22, height: 22, decoration: BoxDecoration( color: primary, shape: BoxShape.circle, ), child: Icon( Icons.check, size: 14, color: ThemeData.estimateBrightnessForColor(primary) == Brightness.dark ? Colors.white : Colors.black87, ), ), ], ), const SizedBox(height: 12), Text( preset.name, style: theme.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w700, ), ), const SizedBox(height: 2), Text( '${AppearanceSettingsScreen._hex(preset.primary)} · ' '${AppearanceSettingsScreen._hex(preset.secondary)}', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), ), ), ); } } class _StackedColorCircles extends StatelessWidget { const _StackedColorCircles({ required this.primary, required this.secondary, }); final Color primary; final Color secondary; @override Widget build(BuildContext context) { final outline = Theme.of(context) .colorScheme .outline .withValues(alpha: 0.2); return SizedBox( width: 56, height: 32, child: Stack( children: [ Positioned( left: 0, child: Container( width: 32, height: 32, decoration: BoxDecoration( color: primary, shape: BoxShape.circle, border: Border.all(color: outline, width: 2), ), ), ), Positioned( left: 22, child: Container( width: 32, height: 32, decoration: BoxDecoration( color: secondary, shape: BoxShape.circle, border: Border.all(color: outline, width: 2), ), ), ), ], ), ); } }