import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'core/constants/app_constants.dart'; import 'core/cache/cache_refresh_coordinator.dart'; import 'core/di/injection.dart'; import 'core/notifications/local_notification_service.dart'; import 'core/notifications/reminder_notification_callbacks.dart'; import 'core/router/app_router.dart'; import 'core/startup/auth_session_bootstrapper.dart'; import 'core/theme/app_theme.dart'; import 'features/auth/presentation/bloc/auth_bloc.dart'; import 'features/auth/presentation/bloc/auth_event.dart'; import 'features/auth/presentation/bloc/auth_state.dart'; import 'features/calendar/data/services/calendar_service.dart'; import 'features/calendar/data/services/calendar_repository.dart'; import 'features/calendar/reminders/reminder_action_executor.dart'; import 'features/calendar/reminders/ui/reminder_foreground_presenter.dart'; import 'features/calendar/ui/calendar_state_manager.dart'; import 'features/chat/presentation/bloc/chat_bloc.dart'; import 'features/settings/data/services/settings_user_cache.dart'; import 'features/todo/data/todo_repository.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await configureDependencies(); await AppConstants.init(); final rootNavigatorKey = GlobalKey(); final reminderForegroundPresenter = ReminderForegroundPresenter( navigatorKey: rootNavigatorKey, executor: sl(), ); sl().bindActionHandler(({ required action, required payload, }) { return sl().handleAction( action: action, payload: payload, ); }); sl().bindInAppReminderHandler( reminderForegroundPresenter.present, ); await sl().initialize(); final authBloc = sl(); authBloc.add(AuthStarted()); final cacheRefreshCoordinator = CacheRefreshCoordinator( minInterval: const Duration(minutes: 5), onRefresh: () { final selected = sl().selectedDate; unawaited( sl().getDayEvents(selected, forceRefresh: true), ); unawaited( sl().getMonthEvents( DateTime(selected.year, selected.month, 1), forceRefresh: true, ), ); unawaited(sl().getPendingTodos(forceRefresh: true)); unawaited(sl().getProfile(forceRefresh: true)); }, ); WidgetsBinding.instance.addObserver(cacheRefreshCoordinator); runApp( LinksyApp( authBloc: authBloc, rootNavigatorKey: rootNavigatorKey, sessionBootstrapper: AuthSessionBootstrapper( calendarService: sl(), notificationService: sl(), reminderActionExecutor: sl(), ), ), ); WidgetsBinding.instance.addPostFrameCallback((_) { unawaited( ReminderNotificationCallbacks.bindResponseHandler( sl().handleNotificationResponse, ), ); }); } class LinksyApp extends StatelessWidget { final AuthBloc authBloc; final GlobalKey rootNavigatorKey; final AuthSessionBootstrapper sessionBootstrapper; const LinksyApp({ super.key, required this.authBloc, required this.rootNavigatorKey, required this.sessionBootstrapper, }); @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider.value(value: authBloc), BlocProvider(create: (_) => ChatBloc(apiClient: sl())), ], child: BlocListener( listenWhen: (previous, current) => previous != current, listener: (context, state) { unawaited(sessionBootstrapper.syncForAuthState(state)); }, child: MaterialApp.router( title: 'Linksy', debugShowCheckedModeBanner: false, theme: AppTheme.light, routerConfig: createAppRouter(authBloc), ), ), ); } }