diff --git a/lib/core/di/injection_container.dart b/lib/core/di/injection_container.dart index ff5339d..9a04a08 100644 --- a/lib/core/di/injection_container.dart +++ b/lib/core/di/injection_container.dart @@ -8,13 +8,17 @@ import '../../features/auth/data/datasources/auth_remote_datasource.dart'; import '../../features/auth/data/repositories/auth_repository_impl.dart'; import '../../features/auth/domain/repositories/auth_repository.dart'; import '../../features/auth/presentation/viewmodels/auth_viewmodel.dart'; +import '../../features/settings/data/settings_local_datasource.dart'; +import '../../features/settings/domain/enums/app_mode.dart'; import '../../features/settings/presentation/viewmodels/settings_viewmodel.dart'; +import '../../features/tasks/data/datasources/task_local_datasource.dart'; +import '../../features/tasks/data/datasources/task_remote_datasource.dart'; +import '../../features/tasks/data/repositories/local_task_repository_impl.dart'; +import '../../features/tasks/data/repositories/task_repository_impl.dart'; +import '../../features/tasks/domain/repositories/task_repository.dart'; import '../../features/tasks/presentation/viewmodels/daily_tasks_viewmodel.dart'; import '../../features/tasks/presentation/viewmodels/task_form_viewmodel.dart'; -import '../../features/tasks/domain/repositories/task_repository.dart'; -import '../../features/tasks/data/repositories/task_repository_impl.dart'; -import '../../features/tasks/data/datasources/task_remote_datasource.dart'; -import '../../features/settings/data/settings_local_datasource.dart'; +import '../database/app_database.dart'; import '../logging/app_logger.dart'; import '../network/authenticated_client.dart'; @@ -64,6 +68,14 @@ Future init() async { ), ); + // Settings Data Source (must be registered before SettingsViewModel) + getIt.registerLazySingleton( + () => SettingsLocalDataSourceImpl(sharedPreferences: getIt()), + ); + + // Database (for local mode) + getIt.registerLazySingleton(() => AppDatabase()); + // Task Data sources getIt.registerLazySingleton( () => TaskRemoteDataSourceImpl( @@ -71,14 +83,28 @@ Future init() async { client: getIt(), ), ); - getIt.registerLazySingleton( - () => SettingsLocalDataSourceImpl(sharedPreferences: getIt()), + getIt.registerLazySingleton( + () => TaskLocalDataSourceImpl(database: getIt()), ); - // Repositories - getIt.registerLazySingleton( - () => TaskRepositoryImpl(remoteDataSource: getIt(), logger: getIt()), - ); + // Task Repository (mode-aware) + // We use a factory that checks the current app mode + getIt.registerFactory(() { + final settingsDataSource = getIt(); + final appMode = settingsDataSource.getAppMode(); + + if (appMode == AppMode.local) { + return LocalTaskRepositoryImpl( + localDataSource: getIt(), + logger: getIt(), + ); + } else { + return TaskRepositoryImpl( + remoteDataSource: getIt(), + logger: getIt(), + ); + } + }); // ViewModels getIt.registerFactory( diff --git a/lib/routing/app_router.dart b/lib/routing/app_router.dart index a08835b..be51f80 100644 --- a/lib/routing/app_router.dart +++ b/lib/routing/app_router.dart @@ -1,13 +1,17 @@ +import 'package:flutter/widgets.dart'; import 'package:go_router/go_router.dart'; import '../core/di/injection_container.dart'; import '../features/auth/presentation/pages/login_page.dart'; import '../features/auth/presentation/pages/register_page.dart'; import '../features/auth/presentation/viewmodels/auth_viewmodel.dart'; -import '../features/tasks/presentation/pages/daily_agenda_page.dart'; -import '../features/tasks/presentation/pages/calendar_page.dart'; -import '../features/tasks/presentation/pages/task_form_page.dart'; +import '../features/onboarding/presentation/pages/onboarding_page.dart'; +import '../features/onboarding/presentation/pages/setup_page.dart'; import '../features/settings/presentation/pages/settings_page.dart'; +import '../features/settings/presentation/viewmodels/settings_viewmodel.dart'; +import '../features/tasks/presentation/pages/calendar_page.dart'; +import '../features/tasks/presentation/pages/daily_agenda_page.dart'; +import '../features/tasks/presentation/pages/task_form_page.dart'; class AppRouter { static GoRouter? _router; @@ -18,13 +22,41 @@ class AppRouter { } static GoRouter _createRouter() { + final authViewModel = getIt(); + final settingsViewModel = getIt(); + return GoRouter( initialLocation: '/', redirect: (context, state) { - final authViewModel = getIt(); + final location = state.matchedLocation; + + // 1. Check if setup is completed + if (!settingsViewModel.setupCompleted) { + if (location != '/setup') { + return '/setup'; + } + return null; + } + + // 2. Check if onboarding is shown + if (!settingsViewModel.onboardingShown) { + if (location != '/onboarding') { + return '/onboarding'; + } + return null; + } + + // 3. Local mode - allow access to main app, block auth routes + if (settingsViewModel.isLocalMode) { + if (location == '/login' || location == '/register') { + return '/'; + } + return null; + } + + // 4. Online mode - existing auth logic final isAuthenticated = authViewModel.isAuthenticated; - final isAuthRoute = - state.matchedLocation == '/login' || state.matchedLocation == '/register'; + final isAuthRoute = location == '/login' || location == '/register'; if (authViewModel.state == AuthState.initial) { return null; @@ -40,8 +72,18 @@ class AppRouter { return null; }, - refreshListenable: getIt(), + refreshListenable: Listenable.merge([authViewModel, settingsViewModel]), routes: [ + GoRoute( + path: '/setup', + name: 'setup', + builder: (context, state) => const SetupPage(), + ), + GoRoute( + path: '/onboarding', + name: 'onboarding', + builder: (context, state) => const OnboardingPage(), + ), GoRoute( path: '/login', name: 'login',