Files
submanager/lib/providers/theme_provider.dart
2025-09-07 19:33:11 +09:00

187 lines
5.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:provider/provider.dart';
import '../theme/adaptive_theme.dart';
/// 테마 관리 Provider
class ThemeProvider extends ChangeNotifier {
static const String _themeBoxName = 'theme_settings';
static const String _themeKey = 'theme_settings';
late Box<Map> _themeBox;
ThemeSettings _themeSettings = const ThemeSettings();
ThemeSettings get themeSettings => _themeSettings;
AppThemeMode get themeMode => _themeSettings.mode;
bool get useSystemColors => _themeSettings.useSystemColors;
bool get largeText => _themeSettings.largeText;
bool get reduceMotion => _themeSettings.reduceMotion;
bool get highContrast => _themeSettings.highContrast;
/// Provider 초기화
Future<void> initialize() async {
_themeBox = await Hive.openBox<Map>(_themeBoxName);
await _loadThemeSettings();
}
/// 저장된 테마 설정 로드
Future<void> _loadThemeSettings() async {
final savedSettings = _themeBox.get(_themeKey);
if (savedSettings != null) {
_themeSettings = ThemeSettings.fromJson(
Map<String, dynamic>.from(savedSettings),
);
notifyListeners();
}
}
/// 테마 설정 저장
Future<void> _saveThemeSettings() async {
await _themeBox.put(_themeKey, _themeSettings.toJson());
}
/// 테마 모드 변경
Future<void> setThemeMode(AppThemeMode mode) async {
_themeSettings = _themeSettings.copyWith(mode: mode);
await _saveThemeSettings();
notifyListeners();
}
/// 시스템 색상 사용 설정
Future<void> setUseSystemColors(bool value) async {
_themeSettings = _themeSettings.copyWith(useSystemColors: value);
await _saveThemeSettings();
notifyListeners();
}
/// 큰 텍스트 설정
Future<void> setLargeText(bool value) async {
_themeSettings = _themeSettings.copyWith(largeText: value);
await _saveThemeSettings();
notifyListeners();
}
/// 모션 감소 설정
Future<void> setReduceMotion(bool value) async {
_themeSettings = _themeSettings.copyWith(reduceMotion: value);
await _saveThemeSettings();
notifyListeners();
}
/// 고대비 설정
Future<void> setHighContrast(bool value) async {
_themeSettings = _themeSettings.copyWith(highContrast: value);
await _saveThemeSettings();
notifyListeners();
}
/// 현재 설정에 따른 테마 가져오기
ThemeData getTheme(BuildContext context) {
final platformBrightness = MediaQuery.of(context).platformBrightness;
ThemeData baseTheme;
switch (_themeSettings.mode) {
case AppThemeMode.light:
baseTheme = AdaptiveTheme.lightTheme;
break;
case AppThemeMode.dark:
baseTheme = AdaptiveTheme.darkTheme;
break;
case AppThemeMode.oled:
baseTheme = AdaptiveTheme.oledTheme;
break;
case AppThemeMode.system:
baseTheme = platformBrightness == Brightness.dark
? AdaptiveTheme.darkTheme
: AdaptiveTheme.lightTheme;
break;
}
// 접근성 설정 적용
return AdaptiveTheme.getAccessibleTheme(
baseTheme,
largeText: _themeSettings.largeText,
reduceMotion: _themeSettings.reduceMotion,
highContrast: _themeSettings.highContrast,
);
}
/// 현재 테마가 다크 모드인지 확인
bool isDarkMode(BuildContext context) {
final platformBrightness = MediaQuery.of(context).platformBrightness;
switch (_themeSettings.mode) {
case AppThemeMode.light:
return false;
case AppThemeMode.dark:
case AppThemeMode.oled:
return true;
case AppThemeMode.system:
return platformBrightness == Brightness.dark;
}
}
/// 테마 토글 (라이트/다크)
Future<void> toggleTheme() async {
if (_themeSettings.mode == AppThemeMode.light) {
await setThemeMode(AppThemeMode.dark);
} else {
await setThemeMode(AppThemeMode.light);
}
}
}
/// 테마 전환 애니메이션 위젯
class AnimatedThemeBuilder extends StatelessWidget {
final Widget Function(BuildContext, ThemeData) builder;
final Duration duration;
const AnimatedThemeBuilder({
super.key,
required this.builder,
this.duration = const Duration(milliseconds: 300),
});
@override
Widget build(BuildContext context) {
final themeProvider = context.watch<ThemeProvider>();
final theme = themeProvider.getTheme(context);
return AnimatedTheme(
data: theme,
duration: duration,
child: Builder(
builder: (context) => builder(context, theme),
),
);
}
}
/// 테마별 색상 위젯
class ThemedColor extends StatelessWidget {
final Color lightColor;
final Color darkColor;
final Widget child;
const ThemedColor({
super.key,
required this.lightColor,
required this.darkColor,
required this.child,
});
@override
Widget build(BuildContext context) {
final isDark = context.read<ThemeProvider>().isDarkMode(context);
return Theme(
data: Theme.of(context).copyWith(
primaryColor: isDark ? darkColor : lightColor,
),
child: child,
);
}
}