import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart'; import 'package:appflowy/startup/tasks/prelude.dart'; import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_editor/appflowy_editor.dart' hide Log; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../user/application/user_settings_service.dart'; import '../../workspace/application/appearance.dart'; import '../startup.dart'; class InitAppWidgetTask extends LaunchTask { const InitAppWidgetTask(); @override LaunchTaskType get type => LaunchTaskType.appLauncher; @override Future initialize(LaunchContext context) async { final widget = context.getIt().create(context.config); final appearanceSetting = await UserSettingsBackendService().getAppearanceSetting(); // If the passed-in context is not the same as the context of the // application widget, the application widget will be rebuilt. final app = ApplicationWidget( key: ValueKey(context), appearanceSetting: appearanceSetting, appTheme: await appTheme(appearanceSetting.theme), child: widget, ); Bloc.observer = ApplicationBlocObserver(); runApp( EasyLocalization( supportedLocales: const [ // In alphabetical order Locale('ar', 'SA'), Locale('ca', 'ES'), Locale('de', 'DE'), Locale('en'), Locale('es', 'VE'), Locale('eu', 'ES'), Locale('fr', 'FR'), Locale('fr', 'CA'), Locale('hu', 'HU'), Locale('id', 'ID'), Locale('it', 'IT'), Locale('ja', 'JP'), Locale('ko', 'KR'), Locale('pl', 'PL'), Locale('pt', 'BR'), Locale('ru', 'RU'), Locale('sv'), Locale('tr', 'TR'), Locale('ur'), Locale('zh', 'CN'), Locale('zh', 'TW'), Locale('fa'), ], path: 'assets/translations', fallbackLocale: const Locale('en'), useFallbackTranslations: true, saveLocale: false, child: app, ), ); return Future(() => {}); } } class ApplicationWidget extends StatefulWidget { final Widget child; final AppearanceSettingsPB appearanceSetting; final AppTheme appTheme; const ApplicationWidget({ Key? key, required this.child, required this.appTheme, required this.appearanceSetting, }) : super(key: key); @override State createState() => _ApplicationWidgetState(); } class _ApplicationWidgetState extends State { late final GoRouter routerConfig; @override void initState() { super.initState(); // avoid rebuild routerConfig when the appTheme is changed. routerConfig = generateRouter(widget.child); } @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider( create: (_) => AppearanceSettingsCubit( widget.appearanceSetting, widget.appTheme, )..readLocaleWhenAppLaunch(context), ), BlocProvider( create: (_) => DocumentAppearanceCubit()..fetch(), ), ], child: BlocBuilder( builder: (context, state) => MaterialApp.router( builder: overlayManagerBuilder(), debugShowCheckedModeBanner: false, theme: state.lightTheme, darkTheme: state.darkTheme, themeMode: state.themeMode, localizationsDelegates: context.localizationDelegates + [AppFlowyEditorLocalizations.delegate], supportedLocales: context.supportedLocales, locale: state.locale, routerConfig: routerConfig, ), ), ); } } class AppGlobals { static GlobalKey rootNavKey = GlobalKey(); static NavigatorState get nav => rootNavKey.currentState!; } class ApplicationBlocObserver extends BlocObserver { @override // ignore: unnecessary_overrides void onTransition(Bloc bloc, Transition transition) { // Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}"); // Log.debug("${transition.nextState}"); super.onTransition(bloc, transition); } @override void onError(BlocBase bloc, Object error, StackTrace stackTrace) { Log.debug(error); super.onError(bloc, error, stackTrace); } // @override // void onEvent(Bloc bloc, Object? event) { // Log.debug("$event"); // super.onEvent(bloc, event); // } } Future appTheme(String themeName) async { if (themeName.isEmpty) { return AppTheme.fallback; } else { try { return await AppTheme.fromName(themeName); } catch (e) { return AppTheme.fallback; } } }