import 'dart:async'; import 'package:bot_toast/bot_toast.dart'; import 'package:be_happy/core/app_colors.dart'; import 'package:be_happy/di/service_locator.dart'; import 'package:be_happy/domain/entities/user_profile.dart'; import 'package:be_happy/domain/usecase/get_available_subscriptions_usecase.dart'; import 'package:be_happy/domain/usecase/get_certificates_usecase.dart'; import 'package:be_happy/domain/usecase/get_client_subscriptions_usecase.dart'; import 'package:be_happy/domain/usecase/get_profile_usecase.dart'; import 'package:be_happy/domain/usecase/get_scooter_by_title_usecase.dart'; import 'package:be_happy/domain/usecase/get_subscription_by_id_usecase.dart'; import 'package:be_happy/domain/usecase/is_pin_set_usecase.dart'; import 'package:be_happy/domain/usecase/purchase_certificate_usecase.dart'; import 'package:be_happy/presentation/event/payment_confirm_event.dart'; import 'package:be_happy/presentation/event/pin_event.dart'; import 'package:be_happy/presentation/event/subscription_list_event.dart'; import 'package:be_happy/presentation/screens/block_screen.dart'; import 'package:be_happy/presentation/screens/documents_screen.dart'; import 'package:be_happy/presentation/screens/edit_profile_screen.dart'; import 'package:be_happy/presentation/screens/map_screen.dart'; import 'package:be_happy/presentation/screens/news_screen.dart'; import 'package:be_happy/presentation/screens/onboarding_screen.dart'; import 'package:be_happy/presentation/screens/order_history_detail_screen.dart'; import 'package:be_happy/presentation/screens/payment_confirm_screen.dart'; import 'package:be_happy/presentation/screens/profile_screen.dart'; import 'package:be_happy/presentation/screens/promo_code_screen.dart'; import 'package:be_happy/presentation/screens/qr_scan_info_screen.dart'; import 'package:be_happy/presentation/screens/scooter_code_input_screen.dart'; import 'package:be_happy/presentation/screens/scooter_detail_screen.dart'; import 'package:be_happy/presentation/screens/send_photo_screen.dart'; import 'package:be_happy/presentation/screens/subscription_list_screen.dart'; import 'package:be_happy/presentation/screens/support_screen.dart'; import 'package:be_happy/presentation/screens/top_up_screen.dart'; import 'package:be_happy/presentation/viewmodel/splash_bloc.dart'; import 'package:be_happy/presentation/viewmodel/susbcription_details_bloc.dart'; import 'package:be_happy/presentation/viewmodel/top_up_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:geolocator/geolocator.dart'; import 'package:go_router/go_router.dart'; import 'package:path/path.dart'; import '../../domain/entities/scooter.dart'; import '../../domain/usecase/activate_subscription_usecase.dart'; import '../../domain/usecase/book_scooter_usecase.dart'; import '../../domain/usecase/create_pin_usecase.dart'; import '../../domain/usecase/get_address_by_point_usecase.dart'; import '../../domain/usecase/get_available_tariffs_usecase.dart'; import '../../domain/usecase/get_client_orders_usecase.dart'; import '../../domain/usecase/get_map_settings_usecase.dart'; import '../../domain/usecase/get_payment_cards_usecase.dart'; import '../../domain/usecase/get_pedestrian_routes_usecase.dart'; import '../../domain/usecase/get_scooter_order_by_id_usecase.dart'; import '../../domain/usecase/get_scooter_usecase.dart'; import '../../domain/usecase/pay_ride_usecase.dart'; import '../../domain/usecase/remove_payment_card_usecase.dart'; import '../../domain/usecase/save_map_settings_usecase.dart'; import '../../domain/usecase/set_main_payment_card_usecase.dart'; import '../../domain/usecase/verify_pin_usecase.dart'; import '../components/scooter_bottom_sheet.dart'; import '../components/sheet/current_rides_sheet.dart'; import '../components/sheet/map_settings_sheet.dart'; import '../components/sheet/payment_method_sheet.dart'; import '../components/sheet/reserved_ride_sheet.dart'; import '../components/sheet/tariff_sheet.dart'; import '../event/current_rides_event.dart'; import '../event/edit_profile_event.dart'; import '../event/map_settings_modal_event.dart'; import '../event/payment_methods_event.dart'; import '../event/profile_event.dart'; import '../event/scooter_detail_modal_event.dart'; import '../event/subscription_details_event.dart'; import '../event/tariff_sheet_event.dart'; import '../event/top_up_event.dart'; import '../screens/add_card_screen.dart'; // ← новый импорт import '../screens/license_agreement_screen.dart'; import '../screens/notifications_screen.dart'; import '../screens/order_history_screen.dart'; import '../screens/payment_methods_screen.dart'; import '../screens/phone_login_screen.dart'; import '../screens/phone_screen.dart'; import '../screens/pin_login_screen.dart'; import '../screens/privacy_policy_screen.dart'; import '../screens/qr_scan_screen.dart'; import '../screens/splash_screen.dart'; import '../screens/subscription_details_screen.dart'; import '../state/splash_state.dart'; import '../viewmodel/add_card_bloc.dart'; import '../viewmodel/current_rides_bloc.dart'; import '../viewmodel/edit_profile_bloc.dart'; import '../viewmodel/map_settings_modal_bloc.dart'; import '../viewmodel/payment_confirm_bloc.dart'; import '../viewmodel/payment_method_sheet_bloc.dart'; import '../viewmodel/payment_methods_bloc.dart'; import '../viewmodel/pin_bloc.dart'; import '../viewmodel/profile_bloc.dart'; import '../viewmodel/scooter_code_bloc.dart'; import '../viewmodel/scooter_detail_bloc.dart'; import '../viewmodel/scooter_detail_modal_bloc.dart'; import '../viewmodel/subscription_list_bloc.dart'; import '../viewmodel/tariff_sheet_bloc.dart'; // ← новый импорт class AppRouter { final SplashBloc splashBloc; AppRouter(this.splashBloc); late final GoRouter router = GoRouter( debugLogDiagnostics: true, initialLocation: '/splash', routes: [ GoRoute( path: '/splash', builder: (context, state) => const SplashScreen(), ), GoRoute(path: '/login', builder: (context, state) => const PhoneScreen()), GoRoute( path: '/verify', builder: (context, state) { final phone = state.uri.queryParameters['phone']; if (phone != null) { return PhoneLoginScreen(phoneNumber: phone, tempToken: ''); } throw Exception("Incorrect phone"); }, ), GoRoute( path: '/block', builder: (context, state) => const BlockedScreen(), ), GoRoute( path: '/pin', builder: (context, state) => BlocProvider( create: (context) => PinBloc( createPinUseCase: getIt(), verifyPinUsecase: getIt(), isPinSetUsecase: getIt(), )..add(PinScreenStarted()), child: const PinLoginScreen(), ) ), GoRoute( path: '/privacy-policy', builder: (context, state) => const PrivacyPolicyScreen(), ), GoRoute( path: '/license-agreement', builder: (context, state) => const LicenseAgreementScreen(), ), GoRoute( path: '/home', builder: (context, state) => const MapScreen(), routes: [ //Modal Bottom Sheets GoRoute( path: 'scooter-sheet', pageBuilder: (context, state) { final data = state.extra as Map; final scooters = data['scooters'] as List; final location = data['currentLocation'] as Position; return modalPage( state: state, child: Material( type: MaterialType.transparency, child: BlocProvider( create: (context) => ScooterDetailModalBloc( getIt(), getIt(), getIt(), ) ..add( ScooterDetailModalStarted( scooters, location.latitude, location.longitude, ), ), child: ScooterBottomSheet(), ), ), ); }, ), GoRoute( path: 'tarif-sheet', pageBuilder: (context, state) { final scooter = state.extra as Scooter; return modalPage( state: state, child: Material( type: MaterialType.transparency, child: BlocProvider( create: (context) => TariffSheetBloc( getIt(), getIt(), getIt(), getIt(), ), child: TariffSheet(scooter: scooter), ), ), ); }, ), GoRoute( path: 'current-rides-sheet', pageBuilder: (context, state) { return modalPage( state: state, child: Material( type: MaterialType.transparency, child: BlocProvider( create: (context) => CurrentRidesBloc(getIt()) ..add(LoadClientOrders()), child: CurrentRidesSheet(), ), ), ); }, ), GoRoute( path: 'payment-method-sheet', pageBuilder: (context, state) { return modalPage( state: state, child: Material( type: MaterialType.transparency, child: BlocProvider( create: (context) => PaymentMethodSheetBloc(getIt()), child: PaymentMethodSheet(), ), ), ); }, ), GoRoute( path: 'map-settings-sheet', pageBuilder: (context, state) { return modalPage( state: state, child: Material( type: MaterialType.transparency, child: BlocProvider( create: (context) => MapSettingsModalBloc( getIt(), getIt(), ) ..add(MapSettingsModalStarted()), child: MapSettingsSheet(), ), ), ); }, ), //Sub screens GoRoute( path: 'profile', builder: (context, state) => BlocProvider( create: (context) => getIt() ..add(ProfileStarted()), child: ProfileScreen(), ), routes: [ GoRoute( path: 'edit', builder: (context, state) => BlocProvider( create: (context) => getIt() ..add(EditProfileStarted()), child: EditProfileScreen( profile: UserProfile( name: '', birthDate: '', phone: '', balance: 23, email: '', ), ), ), ), ], ), GoRoute( path: 'scooter/:id', builder: (context, state) => BlocProvider( create: (context) => getIt(), child: ScooterDetailScreen(), ), ), GoRoute( path: 'order-photos/:orderId', builder: (context, state) { int orderId = int.parse(state.pathParameters['orderId']!); return SendPhotoScreen(orderId: orderId); }, ), GoRoute( path: 'checkout/:orderId', builder: (context, state) { int orderId = int.parse(state.pathParameters['orderId']!); List photoIds = []; if (state.extra != null) { photoIds = state.extra as List; } return BlocProvider( create: (context) => PaymentConfirmBloc( getIt(), getIt(), getIt(), getIt(), ) ..add(PaymentConfirmStarted(orderId)), child: PaymentConfirmScreen( orderId: orderId, photoIds: photoIds, ), ); }, ), GoRoute( path: 'support', builder: (context, state) => const SupportScreen(), ), GoRoute( path: 'documents', builder: (context, state) => const DocumentsScreen(), ), GoRoute( path: 'promo', builder: (context, state) => const PromoCodeScreen(), ), GoRoute( path: 'subscriptions', builder: (context, state) { return BlocProvider( create: (context) => SubscriptionListBloc( getAvailableSubscriptionsUsecase: getIt(), getClientSubscriptionsUsecase: getIt(), ) ..add(LoadSubscriptionsEvent()), child: SubscriptionsListScreen(), ); }, routes: [ GoRoute( path: ':id', builder: (context, state) { return BlocProvider( create: (context) => SubscriptionDetailsBloc( getIt(), getIt(), getIt(), ) ..add( LoadDetailsEvent( int.parse(state.pathParameters['id']!), ), ), child: SubscriptionDetailsScreen(subscriptionId: 1), ); }, ), ], ), GoRoute( path: 'rules', builder: (context, state) => const OnboardingScreen(), ), GoRoute( path: 'news', builder: (context, state) => const NewsScreen(), ), GoRoute( path: 'qr-info', builder: (context, state) => const QRScanInfoScreen(), routes: [ GoRoute( path: 'qr-scan', builder: (context, state) => const QrScanScreen(), ), GoRoute( path: 'qr-input', builder: (context, state) => BlocProvider( create: (context) => ScooterCodeBloc( getScooterByTitleUsecase: getIt(), ), child: ScooterCodeInputScreen(), ), ), ] ), GoRoute( path: 'payment-methods', builder: (context, state) => BlocProvider( create: (context) => PaymentMethodsBloc( getIt(), getIt(), getIt(), getIt(), ) ..add(PaymentMethodsStarted()), child: PaymentMethodsScreen(), ), routes: [ GoRoute( path: 'add-card', builder: (context, state) => BlocProvider( create: (context) => getIt(), child: const AddCardScreen(), ), ), GoRoute( path: 'top-up', builder: (context, state) => BlocProvider( create: (context) => TopUpBloc( getCertificatesUsecase: getIt(), purchaseCertificateUsecase: getIt(), getUserCards: getIt(), ) ..add(LoadTopUpData()), child: TopUpScreen(), ), ), ], ), GoRoute( path: 'order-history', builder: (context, state) => const OrderHistoryScreen(), routes: [] ), GoRoute( path: 'notifications', builder: (context, state) => const NotificationsScreen(), ), ], ), ], observers: [BotToastNavigatorObserver()], redirect: (BuildContext context, GoRouterState state) { final authState = splashBloc.state; final currentLocation = state.uri.toString(); print("inside redirect"); print(splashBloc.state); print(state.uri.toString()); if (authState is AuthInitial && currentLocation != '/splash') { print("splash"); return '/splash'; } if (authState is AuthFirstLaunch && currentLocation != '/login' && currentLocation != '/privacy-policy' && currentLocation != '/license-agreement') { print("login"); return '/login'; } if (authState is AuthUnauthenticated && currentLocation != '/login' && currentLocation != '/privacy-policy' && currentLocation != '/license-agreement') { print("login2"); return '/login'; } if (authState is AuthAuthenticated) { final isComingFromStart = currentLocation == '/splash' || currentLocation == '/login' || currentLocation == '/phone'; if (isComingFromStart) { print("redirecting to pin check"); return '/pin'; } } if (authState is AuthPinVerified) { if (currentLocation == '/splash' || currentLocation == '/login' || currentLocation == '/pin') { return '/home'; } } return null; }, refreshListenable: GoRouterRefreshStream(splashBloc.stream), ); CustomTransitionPage modalPage({ required GoRouterState state, required Widget child, }) { return CustomTransitionPage( key: state.pageKey, opaque: false, barrierDismissible: true, barrierColor: Colors.black54, transitionsBuilder: (context, animation, secondaryAnimation, child) { return SlideTransition( position: animation.drive( Tween( begin: const Offset(0, 1), end: Offset.zero, ).chain(CurveTween(curve: Curves.easeOutCubic)), ), child: child, ); }, child: child, ); } } class GoRouterRefreshStream extends ChangeNotifier { late final StreamSubscription _subscription; GoRouterRefreshStream(Stream stream) { notifyListeners(); _subscription = stream.asBroadcastStream().listen((dynamic _) { print("Stream updated"); notifyListeners(); }); } @override void dispose() { _subscription.cancel(); super.dispose(); } }