Major UI/UX and architecture improvements
- Implemented new navigation system with NavigationProvider and route management - Added adaptive theme system with ThemeProvider for better theme handling - Introduced glassmorphism design elements (app bars, scaffolds, cards) - Added advanced animations (spring animations, page transitions, staggered lists) - Implemented performance optimizations (memory manager, lazy loading) - Refactored Analysis screen into modular components - Added floating navigation bar with haptic feedback - Improved subscription cards with swipe actions - Enhanced skeleton loading with better animations - Added cached network image support - Improved overall app architecture and code organization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
186
lib/providers/theme_provider.dart
Normal file
186
lib/providers/theme_provider.dart
Normal file
@@ -0,0 +1,186 @@
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user