feat: implement dynamic theme palette selection
- Introduced a new feature allowing users to select from multiple accent color palettes for buttons, cards, and chat bubbles. - Added `AppThemePalette` provider to manage the current theme palette and persist user selections. - Updated the `AppTheme` class to utilize the selected palette for light and dark themes, enhancing visual customization. - Enhanced the `AppCustomizationPage` to include a palette selector, improving user experience and personalization options. - Updated localization files to support new palette selection UI elements in multiple languages.
This commit is contained in:
@@ -18,6 +18,7 @@ final class PreferenceKeys {
|
||||
static const String rememberCredentials = 'remember_credentials';
|
||||
static const String activeServerId = 'active_server_id';
|
||||
static const String themeMode = 'theme_mode';
|
||||
static const String themePalette = 'theme_palette_v1';
|
||||
static const String localeCode = 'locale_code_v1';
|
||||
static const String onboardingSeen = 'onboarding_seen_v1';
|
||||
static const String reviewerMode = 'reviewer_mode_v1';
|
||||
|
||||
@@ -89,6 +89,7 @@ class PersistenceMigrator {
|
||||
copyBool(PreferenceKeys.rememberCredentials);
|
||||
copyString(PreferenceKeys.activeServerId);
|
||||
copyString(PreferenceKeys.themeMode);
|
||||
copyString(PreferenceKeys.themePalette);
|
||||
copyString(PreferenceKeys.localeCode);
|
||||
copyBool(PreferenceKeys.onboardingSeen);
|
||||
copyBool(PreferenceKeys.reviewerMode);
|
||||
@@ -194,6 +195,7 @@ class PersistenceMigrator {
|
||||
PreferenceKeys.rememberCredentials,
|
||||
PreferenceKeys.activeServerId,
|
||||
PreferenceKeys.themeMode,
|
||||
PreferenceKeys.themePalette,
|
||||
PreferenceKeys.localeCode,
|
||||
PreferenceKeys.onboardingSeen,
|
||||
PreferenceKeys.reviewerMode,
|
||||
|
||||
@@ -23,6 +23,8 @@ import '../services/optimized_storage_service.dart';
|
||||
import '../services/socket_service.dart';
|
||||
import '../utils/debug_logger.dart';
|
||||
import '../models/socket_event.dart';
|
||||
import '../../shared/theme/color_palettes.dart';
|
||||
import '../../shared/theme/app_theme.dart';
|
||||
|
||||
part 'app_providers.g.dart';
|
||||
|
||||
@@ -78,6 +80,42 @@ class AppThemeMode extends _$AppThemeMode {
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class AppThemePalette extends _$AppThemePalette {
|
||||
late final OptimizedStorageService _storage;
|
||||
|
||||
@override
|
||||
AppColorPalette build() {
|
||||
_storage = ref.watch(optimizedStorageServiceProvider);
|
||||
final storedId = _storage.getThemePaletteId();
|
||||
return AppColorPalettes.byId(storedId);
|
||||
}
|
||||
|
||||
Future<void> setPalette(String paletteId) async {
|
||||
final palette = AppColorPalettes.byId(paletteId);
|
||||
state = palette;
|
||||
await _storage.setThemePaletteId(palette.id);
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class AppLightTheme extends _$AppLightTheme {
|
||||
@override
|
||||
ThemeData build() {
|
||||
final palette = ref.watch(appThemePaletteProvider);
|
||||
return AppTheme.light(palette);
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class AppDarkTheme extends _$AppDarkTheme {
|
||||
@override
|
||||
ThemeData build() {
|
||||
final palette = ref.watch(appThemePaletteProvider);
|
||||
return AppTheme.dark(palette);
|
||||
}
|
||||
}
|
||||
|
||||
// Locale provider
|
||||
@Riverpod(keepAlive: true)
|
||||
class AppLocale extends _$AppLocale {
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'dart:math' as math;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/semantics.dart';
|
||||
import '../../shared/theme/app_theme.dart';
|
||||
import '../../shared/theme/color_palettes.dart';
|
||||
import '../../shared/theme/theme_extensions.dart';
|
||||
|
||||
/// Enhanced accessibility service for WCAG 2.2 AA compliance
|
||||
@@ -349,9 +349,7 @@ class EnhancedAccessibilityService {
|
||||
return BoxDecoration(
|
||||
border: hasFocus
|
||||
? Border.all(
|
||||
color:
|
||||
focusColor ??
|
||||
AppTheme.brandPrimary, // Brand primary as fallback
|
||||
color: focusColor ?? AppColorPalettes.auroraViolet.light.primary,
|
||||
width: borderWidth,
|
||||
)
|
||||
: null,
|
||||
|
||||
@@ -35,6 +35,7 @@ class OptimizedStorageService {
|
||||
static const String _rememberCredentialsKey =
|
||||
PreferenceKeys.rememberCredentials;
|
||||
static const String _themeModeKey = PreferenceKeys.themeMode;
|
||||
static const String _themePaletteKey = PreferenceKeys.themePalette;
|
||||
static const String _localeCodeKey = PreferenceKeys.localeCode;
|
||||
static const String _localConversationsKey = HiveStoreKeys.localConversations;
|
||||
static const String _onboardingSeenKey = PreferenceKeys.onboardingSeen;
|
||||
@@ -261,6 +262,14 @@ class OptimizedStorageService {
|
||||
await _preferencesBox.put(_themeModeKey, mode);
|
||||
}
|
||||
|
||||
String? getThemePaletteId() {
|
||||
return _preferencesBox.get(_themePaletteKey) as String?;
|
||||
}
|
||||
|
||||
Future<void> setThemePaletteId(String paletteId) async {
|
||||
await _preferencesBox.put(_themePaletteKey, paletteId);
|
||||
}
|
||||
|
||||
String? getLocaleCode() {
|
||||
return _preferencesBox.get(_localeCodeKey) as String?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user