RiverPod으로 상태관리를 통해 테마를 조절한다
상태를 watch 해야 하는 Widget은 ConsumerWidget으로 변경해야 되므로
main.dart 를 ConsumerWidget으로 변경해준다.
최상단 main.dart
import 'package:bookbox/core/constants/styles.dart';
import 'package:bookbox/ui/_components/splash_screen.dart';
import 'package:bookbox/ui/admin/admin_page.dart';
import 'package:bookbox/ui/main/main_page.dart';
import 'package:bookbox/ui/user/join/join_page.dart';
import 'package:bookbox/ui/user/login/login_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 테마 상태를 가져옴
final themeMode = ref.watch(themeNotifierProvider);
return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
home: SplashPage(),
//initialRoute: "/login",
//initialRoute: "/home",
routes: {
"/login": (context) => LoginPage(),
"/join": (context) => const JoinPage(),
"/home": (context) => MainPage(),
"/admin": (context) => const AdminPage(),
},
theme: lightTheme(),
darkTheme: ThemeData.dark(),
themeMode: themeMode, // 테마 모드 설정
);
}
}
themeNotifierProvider를 watch하게 만들어서
우리 앱인 MaterialApp()의 themdMode를 설정하게 해 두었다.
themeNotifierProvider는 constants의 styles.dart에 위치한다.
기존에 다크모드가 없을 때는
TextTheme(), IconTheme, AppBarThem 이런 식으로 만들어 놓고 쓰다가
다크모드를 사용할 때는 기본 테마를
lightTextTheme(), lightIconTheme(), lightAppBarTheme() 라는 이름으로 바꿨고
다크모드에 사용할 테마를
darkTextTheme(), darkIconTheme(), darkAppBarTheme() 라는 이름으로 만들었다
이렇게 만들어둔 테마를 종합적으로 모아서
라이트모드, 다크모드에 사용할 ThemeData를 만들었고
그 이름을 lightTheme(), darkTheme() 으로 해서 종합했다.
themeNotifierProvider는 constants의 styles.dart의 종합 테마 코드
// 라이트 모드 테마
ThemeData lightTheme() {
return ThemeData(
scaffoldBackgroundColor: Colors.white,
textTheme: lightTextTheme(),
appBarTheme: lightAppBarTheme(),
bottomNavigationBarTheme: lightBottomNavigatorTheme(),
primarySwatch: Colors.lightBlue,
);
}
// 다크 모드 테마
ThemeData darkTheme() {
return ThemeData(
scaffoldBackgroundColor: Colors.black,
textTheme: darkTextTheme(),
appBarTheme: darkAppBarTheme(),
bottomNavigationBarTheme: darkBottomNavigatorTheme(),
primarySwatch: Colors.lightBlue,
);
}
이제 리버팟 상태관리를 추가해줄 것인데
viewModel은 ThemeNotifier 라는 클래스를 만들었고
Model은 ThemeMode,
Model 관리자는 themeNotifierProvider 라고 만들었다.
여기서 Model이 되는 ThemeMode는 Flutter에 내장된 app.dart에 존재하는 녀석이다. 우리가 따로 만들어줄 필요 없이 ThemeMode의 상태를 변경해주면 main.dart에서 watch하고 있다가 상태변경이 감지되면 변경된 ThemeMode를 통해 테마를 변경하게 된다.
버튼으로 모드를 조절하기 때문에 버튼을 통해 light와 dark모드를 조절했고 이렇게 조절하면 현재 설정을 SharedPreferences 라이브러리를 통해 내부 저장소에 저장해서 앱을 껐다 켜도 항상 마지막에 설정한 모드를 불러올 수 있게 했다.
우리가 수업중에 배울 때 만들었던 Model은 이미 app.dart에 내장된 것을 사용했다고 보면 되고 거기에 SharedPreferences 라이브러리를 사용해서 현재 설정을 내부 저장소에 저장, 불러오기 하는 것을 추가한 것이다.
themeNotifierProvider는 constants의 styles.dart의 상태 변경 코드
// 테마 모드를 관리하는 StateNotifier
class ThemeNotifier extends StateNotifier<ThemeMode> {
static const _themePrefKey = 'theme_mode';
ThemeNotifier() : super(ThemeMode.light) {
_loadTheme(); // 테마 로드
}
// 다크 모드를 토글하는 메서드
void toggleTheme(bool isDarkMode) async {
if (isDarkMode) {
state = ThemeMode.dark;
} else {
state = ThemeMode.light;
}
await _saveTheme(); // 테마 저장
}
// 테마를 SharedPreferences에 저장하는 메서드
Future<void> _saveTheme() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_themePrefKey, state == ThemeMode.dark);
}
// 앱 시작 시 저장된 테마를 불러오는 메서드
Future<void> _loadTheme() async {
final prefs = await SharedPreferences.getInstance();
final isDarkMode = prefs.getBool(_themePrefKey) ?? false; // 기본값은 라이트 모드
state = isDarkMode ? ThemeMode.dark : ThemeMode.light;
}
}
// StateNotifierProvider를 사용하여 테마 상태 제공
final themeNotifierProvider =
StateNotifierProvider<ThemeNotifier, ThemeMode>((ref) {
return ThemeNotifier();
});
Share article