forked from eatvio/eatvio_app
162 lines
6.3 KiB
Dart
162 lines
6.3 KiB
Dart
import 'dart:developer' as developer;
|
||
import 'package:eatvio_app/core/routing/auth_routes.dart';
|
||
import 'package:eatvio_app/core/routing/content_routes.dart';
|
||
import 'package:eatvio_app/core/routing/main_navigation_routes.dart';
|
||
import 'package:eatvio_app/core/routing/other_routes.dart';
|
||
import 'package:eatvio_app/core/routing/route_constants.dart';
|
||
import 'package:eatvio_app/core/routing/settings_routes.dart';
|
||
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
|
||
/// Главный роутер приложения
|
||
class AppRouter {
|
||
static GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||
|
||
// Домены для deep links
|
||
static const List<String> _deepLinkHosts = ['eatvio.ru', 'www.eatvio.ru'];
|
||
|
||
static GoRouter appRouter = GoRouter(
|
||
initialLocation: RouteConstants.updateScreen,
|
||
navigatorKey: navigatorKey,
|
||
redirect: _handleRedirect,
|
||
routes: [
|
||
...AuthRoutes.createRoutes(),
|
||
...MainNavigationRoutes.createRoutes(),
|
||
...ContentRoutes.createRoutes(),
|
||
...SettingsRoutes.createRoutes(),
|
||
...OtherRoutes.createRoutes(),
|
||
],
|
||
);
|
||
|
||
/// Обработка редиректов для deep links
|
||
/// Возвращает null для обычной навигации, чтобы не мешать внутренним переходам
|
||
static String? _handleRedirect(BuildContext context, GoRouterState state) {
|
||
final uri = state.uri;
|
||
final host = uri.host.toLowerCase();
|
||
final segments = uri.pathSegments;
|
||
|
||
// Проверяем, является ли это deep link по домену
|
||
final isDeepLink = _deepLinkHosts.contains(host);
|
||
|
||
// Если это не deep link, не мешаем обычной навигации
|
||
if (!isDeepLink) {
|
||
return null;
|
||
}
|
||
|
||
// Логирование для отладки
|
||
developer.log(
|
||
'Deep link detected: host=$host, path=${uri.path}, segments=$segments',
|
||
name: 'AppRouter',
|
||
);
|
||
|
||
// Проверка на пустой путь или некорректный формат
|
||
if (segments.isEmpty) {
|
||
developer.log('Empty segments in deep link, redirecting to feed', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.feedScreen;
|
||
}
|
||
|
||
// Проверка языка (первый сегмент должен быть ru или en)
|
||
if (segments[0] != 'ru' && segments[0] != 'en') {
|
||
developer.log(
|
||
'Invalid language segment: ${segments[0]}, redirecting to feed',
|
||
name: 'AppRouter',
|
||
);
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.feedScreen;
|
||
}
|
||
|
||
// Обработка deep links с учетом языка
|
||
// Формат: /{lang}/{type}/{identifier?}
|
||
if (segments.length == 4) {
|
||
// Формат: /{lang}/diary/{...}
|
||
final type = segments[1];
|
||
|
||
if (type == 'diary') {
|
||
developer.log('Deep link: diary, redirecting to diary-screen', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.diaryScreen;
|
||
}
|
||
|
||
developer.log(
|
||
'Unknown deep link type for 4 segments: $type, redirecting to feed',
|
||
name: 'AppRouter',
|
||
);
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.feedScreen;
|
||
} else if (segments.length == 3) {
|
||
// Формат: /{lang}/{type}/{identifier}
|
||
final type = segments[1];
|
||
final contentIdentifier = segments[2];
|
||
|
||
switch (type) {
|
||
case 'recipe':
|
||
developer.log('Deep link: recipe/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return '/about-recipes-screen?slug=$contentIdentifier';
|
||
case 'blog_post':
|
||
developer.log('Deep link: blog_post/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return '/blog-post-screen?id=$contentIdentifier';
|
||
case 'plan':
|
||
developer.log('Deep link: plan/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return '/about-plan-screen?slug=$contentIdentifier';
|
||
case 'diet':
|
||
developer.log('Deep link: diet/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return '/about-diet-screen?slug=$contentIdentifier';
|
||
case 'chat':
|
||
developer.log('Deep link: chat/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.chatSelectScreen;
|
||
case 'profile':
|
||
developer.log('Deep link: profile/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return '/profile-screen?slug=$contentIdentifier';
|
||
case 'diary':
|
||
developer.log('Deep link: diary/$contentIdentifier', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.diaryScreen;
|
||
default:
|
||
developer.log(
|
||
'Unknown deep link type: $type, redirecting to feed',
|
||
name: 'AppRouter',
|
||
);
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.feedScreen;
|
||
}
|
||
} else if (segments.length == 2) {
|
||
// Формат: /{lang}/{type} - только для chat
|
||
final type = segments[1];
|
||
|
||
if (type == 'chat') {
|
||
developer.log('Deep link: chat', name: 'AppRouter');
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.chatSelectScreen;
|
||
} else {
|
||
developer.log(
|
||
'Unknown deep link type for 2 segments: $type, redirecting to feed',
|
||
name: 'AppRouter',
|
||
);
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.feedScreen;
|
||
}
|
||
} else {
|
||
// Неизвестный формат deep link
|
||
developer.log(
|
||
'Unknown deep link format: ${segments.length} segments, redirecting to feed',
|
||
name: 'AppRouter',
|
||
);
|
||
FlutterNativeSplash.remove();
|
||
return RouteConstants.feedScreen;
|
||
}
|
||
}
|
||
|
||
static void navigateToRegisterViaSocial({required AuthResultEntity authResult, required String provider}) {
|
||
appRouter.pushNamed('registerViaSocialScreen', extra: {'authResult': authResult, 'provider': provider});
|
||
}
|
||
}
|