feat: Implement color theme persistence and toggle functionality in ThemeCustomizer and ThemeEditorWidget

This commit is contained in:
Vaibhav Surve 2025-10-31 10:54:56 +05:30
parent d208648350
commit 3c89b4ddbb
2 changed files with 57 additions and 5 deletions

View File

@ -1,5 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:marco/helpers/services/json_decoder.dart';
import 'package:marco/helpers/services/localizations/language.dart';
import 'package:marco/helpers/services/localizations/translator.dart';
@ -7,8 +7,8 @@ import 'package:marco/helpers/services/navigation_services.dart';
import 'package:marco/helpers/theme/admin_theme.dart';
import 'package:marco/helpers/theme/app_notifier.dart';
import 'package:marco/helpers/theme/app_theme.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
typedef ThemeChangeCallback = void Function(
ThemeCustomizer oldVal, ThemeCustomizer newVal);
@ -33,6 +33,8 @@ class ThemeCustomizer {
static Future<void> init() async {
await initLanguage();
await _loadColorTheme();
_notify();
}
static initLanguage() async {
@ -40,7 +42,7 @@ class ThemeCustomizer {
}
String toJSON() {
return jsonEncode({'theme': theme.name});
return jsonEncode({'theme': theme.name, 'colorTheme': colorTheme.name});
}
static ThemeCustomizer fromJSON(String? json) {
@ -49,6 +51,8 @@ class ThemeCustomizer {
JSONDecoder decoder = JSONDecoder(json);
instance.theme =
decoder.getEnum('theme', ThemeMode.values, ThemeMode.light);
instance.colorTheme = decoder.getEnum(
'colorTheme', ColorThemeType.values, ColorThemeType.red);
}
return instance;
}
@ -117,12 +121,46 @@ class ThemeCustomizer {
tc.topBarTheme = topBarTheme;
tc.rightBarOpen = rightBarOpen;
tc.leftBarCondensed = leftBarCondensed;
tc.colorTheme = colorTheme;
tc.currentLanguage = currentLanguage.clone();
return tc;
}
@override
String toString() {
return 'ThemeCustomizer{theme: $theme}';
return 'ThemeCustomizer{theme: $theme, colorTheme: $colorTheme}';
}
// ---------------------------------------------------------------------------
// 🟢 Color Theme Persistence
// ---------------------------------------------------------------------------
static const _colorThemeKey = 'color_theme_type';
/// Save selected color theme
static Future<void> saveColorTheme(ColorThemeType type) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_colorThemeKey, type.name);
instance.colorTheme = type;
_notify();
}
/// Load saved color theme (called at startup)
static Future<void> _loadColorTheme() async {
final prefs = await SharedPreferences.getInstance();
final savedType = prefs.getString(_colorThemeKey);
if (savedType != null) {
instance.colorTheme = ColorThemeType.values.firstWhere(
(e) => e.name == savedType,
orElse: () => ColorThemeType.red,
);
}
}
/// Change color theme & persist
static Future<void> changeColorTheme(ColorThemeType type) async {
oldInstance = instance.clone();
instance.colorTheme = type;
await saveColorTheme(type);
}
}

View File

@ -4,6 +4,7 @@ import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/wave_background.dart';
import 'package:marco/helpers/theme/admin_theme.dart';
import 'package:marco/helpers/theme/theme_customizer.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
class ThemeOption {
final String label;
@ -105,7 +106,20 @@ class _ThemeEditorWidgetState extends State<ThemeEditorWidget> {
],
),
const SizedBox(height: 12),
InkWell(
onTap: () {
ThemeCustomizer.setTheme(
ThemeCustomizer.instance.theme == ThemeMode.dark
? ThemeMode.light
: ThemeMode.dark);
},
child: Icon(
ThemeCustomizer.instance.theme == ThemeMode.dark
? LucideIcons.sun
: LucideIcons.moon,
size: 18,
),
),
// Theme cards wrapped in reactive Obx widget
Center(
child: Obx(