st4*_*tic 0 dart flutter bloc flutter-bloc
我在 main.dart 中使用 Flutter bloc 来检查用户身份验证。现在我的应用程序中没有主题选择,它是根据设备上的主题以编程方式选择的。我希望我的 AuthBloc 检查并设置用户在应用程序启动时设置的主题。我有一个主题选择页面,用户可以在其中选择一个主题,默认情况下应该是系统主题,您也可以选择浅色和深色。\n我如何在我的 AuthBloc 中实现此功能?\n我的 main.dart
\n return BlocProvider(\n create: (context) => AuthBloc(authRepo: AuthRepo()),\n child: BlocBuilder<AuthBloc, AuthState>(\n builder: (context, state) {\n print(state);\n return MaterialApp(\n navigatorKey: navKey,\n title: 'YiwuMart',\n debugShowCheckedModeBanner: false,\n theme: lightTheme,\n darkTheme: darkTheme,\n home: MainScreen(\n key: scakey,\n ),\n );\n },\n ),\n );\nRun Code Online (Sandbox Code Playgroud)\n我的主题更改屏幕
\nbool isSystemTheme = true;\n bool isLightTheme = false;\n bool isDarkTheme = false;\n\n Row _buildThemeRow(String themeName, bool isSelected) {\n return Row(\n mainAxisAlignment: MainAxisAlignment.start,\n children: [\n SizedBox(width: 5.h),\n Text(themeName, style: TextStyles.bodyStyle),\n const Spacer(),\n if (isSelected)\n const Icon(\n Icons.check,\n color: Colors.grey,\n size: 15,\n ),\n ],\n );\n }\n\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n appBar: AppBar(\n title: const Text('\xd0\x92\xd1\x8b\xd0\xb1\xd0\xbe\xd1\x80 \xd1\x82\xd0\xb5\xd0\xbc\xd1\x8b'),\n ),\n body: Container(\n width: double.infinity,\n margin: REdgeInsets.all(8.0),\n decoration: BoxDecoration(\n color: Theme.of(context).colorScheme.secondary,\n borderRadius: BorderRadius.circular(8.0),\n ),\n child: Column(\n crossAxisAlignment: CrossAxisAlignment.start,\n mainAxisSize: MainAxisSize.min,\n children: [\n Container(\n width: double.infinity,\n padding: REdgeInsets.all(8.0),\n decoration: BoxDecoration(\n color: Theme.of(context).colorScheme.secondary,\n borderRadius: BorderRadius.circular(8.0),\n ),\n child: Column(\n children: [\n GestureDetector(\n onTap: () {\n setState(() {\n isSystemTheme = true;\n isLightTheme = false;\n isDarkTheme = false;\n });\n },\n child: _buildThemeRow('\xd0\xa1\xd0\xb8\xd1\x81\xd1\x82\xd0\xb5\xd0\xbc\xd0\xbd\xd0\xb0\xd1\x8f', isSystemTheme),\n ),\n const Divider(),\n GestureDetector(\n onTap: () {\n setState(() {\n isSystemTheme = false;\n isLightTheme = true;\n isDarkTheme = false;\n });\n },\n child: _buildThemeRow('\xd0\xa1\xd0\xb2\xd0\xb5\xd1\x82\xd0\xbb\xd0\xb0\xd1\x8f', isLightTheme),\n ),\n const Divider(),\n GestureDetector(\n onTap: () {\n setState(() {\n isSystemTheme = false;\n isLightTheme = false;\n isDarkTheme = true;\n });\n },\n child: _buildThemeRow('\xd0\xa2\xd0\xb5\xd0\xbc\xd0\xbd\xd0\xb0\xd1\x8f', isDarkTheme),\n ),\n ],\n ),\n ),\n ],\n ),\n ));\n }\nRun Code Online (Sandbox Code Playgroud)\n我的 AuthBloc:
\nclass AuthBloc extends Bloc<AuthEvent, AuthState> {\n final AbstractAuth authRepo;\n late StreamSubscription _authenticationStatusSubscription;\n\n AuthBloc({required this.authRepo}) : super(AuthInitial()) {\n authRepo.getCookie();\n authRepo.getFirebaseToken();\n _checkAuthenticationStatus();\n on<LoggedIn>((event, emit) {\n emit(Authenticated(token: event.token));\n });\n on<LogoutEvent>((event, emit) async {});\n on<LoginEvent>((event, emit) async {});\n on<RegistrationEvent>((event, emit) async {});\n }\n\n void _checkAuthenticationStatus() async {\n final isAuthenticated = await authRepo.getToken();\n final isAuth = await Func().getInitParams();\n if (isAuth.statusCode == 200) {\n add(LoggedIn(token: isAuthenticated));\n } else {\n add(LogoutEvent());\n }\n _authenticationStatusSubscription =\n Stream.periodic(const Duration(seconds: 30)).listen((_) async {\n final isAuthenticated = await authRepo.getToken();\n final isAuth = await Func().getInitParams();\n Func().getUnreadCount();\n if (isAuth.statusCode == 200) {\n add(LoggedIn(token: isAuthenticated));\n } else {\n add(LogoutEvent());\n }\n });\n }\n\n @override\n Future<void> close() {\n _authenticationStatusSubscription.cancel();\n return super.close();\n }\n\n Stream<AuthState> mapEventToState(AuthEvent event) async* {\n if (event is AppStarted) {\n final isAuthenticated = await authRepo.getToken();\n if (isAuthenticated != '') {\n yield Authenticated(token: isAuthenticated.toString());\n } else {\n yield Unauthenticated(token: isAuthenticated.toString());\n }\n } else if (event is LoggedIn) {\n yield Authenticated(token: event.token);\n } else if (event is LogoutEvent) {\n yield Unauthenticated(token: '');\n } else if (event is LoginEvent) {\n final data =\n await authRepo.login(event.email, event.password, event.context);\n if (data['api_token'] != '') {\n yield Authenticated(token: data['api_token']);\n } else {\n yield Unauthenticated(token: 'token');\n }\n }\n }\n}\n// event \nabstract class AuthEvent {}\n\nclass AppStarted extends AuthEvent {}\n\nclass LoggedIn extends AuthEvent {\n final String token;\n\n LoggedIn({required this.token});\n}\n\nclass LogoutEvent extends AuthEvent {}\n\nclass LoginEvent extends AuthEvent {\n final BuildContext context;\n final String email;\n final String password;\n\n LoginEvent({required this.email, required this.password, required this.context});\n\n List<Object> get props => [email, password, context];\n}\n\nclass RegistrationEvent extends AuthEvent {\n final BuildContext context;\n final String email;\n final String password;\n final String name;\n final String surname;\n\n RegistrationEvent(\n {required this.email,\n required this.password,\n required this.name,\n required this.surname,\n required this.context});\n\n List<Object> get props => [email, password, name, surname, context];\n}\n\nRun Code Online (Sandbox Code Playgroud)\n
这里有几件事。
首先,我将创建一个单独的 Bloc/Cubit 来处理系统主题,因为这与身份验证无关。
mapEventToState其次,当前的 Bloc API 和已经弃用一年多的 API的奇怪组合。
因此,尽管它与您的问题无关,但我建议按照其预期的方式使用 Bloc,以充分利用它。这将需要实际使用您拥有的所有on<Event>((event, emit) async {})空事件处理程序并摆脱mapEventToState.
该转换的快速示例。
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc({required this.authRepo}) : super(AuthInitial()) {
authRepo.getCookie();
authRepo.getFirebaseToken();
_checkAuthenticationStatus();
on<LoggedIn>((event, emit) {
emit(Authenticated(token: event.token));
});
on<AppStarted>(_onAppStarted); // added this event handler
// you should use the rest of these event handlers and remove the mapEventToState method
on<LogoutEvent>((event, emit) async {});
on<LoginEvent>((event, emit) async {});
on<RegistrationEvent>((event, emit) async {});
}
/// Example event handler method based on what you had in your mapEventToState
Future<void> _onAppStarted(AppStarted event, Emitter<AuthState> emit) async {
final isAuthenticated = await authRepo.getToken();
if (isAuthenticated != '') {
emit(Authenticated(token: isAuthenticated.toString()));
} else {
emit(Unauthenticated(token: isAuthenticated.toString()));
}
}
}
Run Code Online (Sandbox Code Playgroud)
至于主题方面。我建议使用Hydrod_bloc,这样它就可以在重新启动后持续存在,而无需付出最小的努力。如果您已经有另一个存储解决方案,那么这也可以。
您可以创建一个非常简单的 ThemeCubit 类。它所做的只是更新并存储ThemeModeFlutter SDK 中的枚举。通过这种方式,您可以跟踪单个布尔值enum与 3 个单独的布尔值。
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
class ThemeCubit extends HydratedCubit<ThemeMode> {
ThemeCubit() : super(ThemeMode.system);
void updateTheme(ThemeMode themeMode) => emit(themeMode);
// This handles the restoration of the theme mode when the app is restarted.
@override
ThemeMode? fromJson(Map<String, dynamic> json) {
final theme = json['themeMode'];
switch (theme) {
case 'ThemeMode.system':
return ThemeMode.system;
case 'ThemeMode.light':
return ThemeMode.light;
case 'ThemeMode.dark':
return ThemeMode.dark;
}
return ThemeMode.system;
}
// This stores the ThemeMode anytime its changed
@override
Map<String, dynamic>? toJson(ThemeMode state) {
return {
'themeMode': state.toString(),
};
}
}
Run Code Online (Sandbox Code Playgroud)
那么你的材料应用程序可能看起来像这样
class BlocProviderWrapper extends StatelessWidget {
const BlocProviderWrapper({super.key});
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => ThemeCubit(),
),
BlocProvider<AuthBloc>(
create: (context) => AuthBloc(),
),
],
child: const App(),
);
}
}
class App extends StatelessWidget {
const App({
super.key,
});
ThemeData _getTheme(ThemeMode themeMode) {
switch (themeMode) {
case ThemeMode.system:
/// Checks system brightness when user selects system theme mode
final brightness =
SchedulerBinding.instance.platformDispatcher.platformBrightness;
return brightness == Brightness.light
? ThemeData.light()
: ThemeData.dark();
case ThemeMode.light:
return ThemeData.light();
case ThemeMode.dark:
return ThemeData.dark();
}
}
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeCubit, ThemeMode>(
builder: (context, state) {
return MaterialApp(
theme: _getTheme(state),
// ... rest of your Material App
);
},
);
}
}
Run Code Online (Sandbox Code Playgroud)
HydratedBloc 持久性的最后一件事是在 main 函数之前初始化存储runApp。这需要path_provider包来获取设备存储目录。
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final directory = await getApplicationDocumentsDirectory(); // from path provider
HydratedBloc.storage = await HydratedStorage.build(
storageDirectory: directory,
);
// ...the rest of your startup logic
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1678 次 |
| 最近记录: |