120 lines
3.4 KiB
Dart
120 lines
3.4 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:hiddify/core/preferences/general_preferences.dart';
|
|
import 'package:hiddify/core/router/routes.dart';
|
|
import 'package:hiddify/services/deep_link_service.dart';
|
|
import 'package:hiddify/utils/utils.dart';
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
|
|
|
part 'app_router.g.dart';
|
|
|
|
bool _debugMobileRouter = false;
|
|
|
|
final useMobileRouter =
|
|
!PlatformUtils.isDesktop || (kDebugMode && _debugMobileRouter);
|
|
final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
|
|
|
|
// TODO: test and improve handling of deep link
|
|
@riverpod
|
|
GoRouter router(RouterRef ref) {
|
|
final notifier = ref.watch(routerListenableProvider.notifier);
|
|
final deepLink = ref.listen(
|
|
deepLinkServiceProvider,
|
|
(_, next) async {
|
|
if (next case AsyncData(value: final link?)) {
|
|
await ref.state.push(AddProfileRoute(url: link.url).location);
|
|
}
|
|
},
|
|
);
|
|
final initialLink = deepLink.read();
|
|
String initialLocation = const HomeRoute().location;
|
|
if (initialLink case AsyncData(value: final link?)) {
|
|
initialLocation = AddProfileRoute(url: link.url).location;
|
|
}
|
|
|
|
return GoRouter(
|
|
navigatorKey: rootNavigatorKey,
|
|
initialLocation: initialLocation,
|
|
debugLogDiagnostics: true,
|
|
routes: [
|
|
if (useMobileRouter) $mobileWrapperRoute else $desktopWrapperRoute,
|
|
],
|
|
refreshListenable: notifier,
|
|
redirect: notifier.redirect,
|
|
observers: [
|
|
SentryNavigatorObserver(),
|
|
],
|
|
);
|
|
}
|
|
|
|
int getCurrentIndex(BuildContext context) {
|
|
final String location = GoRouterState.of(context).uri.path;
|
|
if (location == const HomeRoute().location) return 0;
|
|
if (location.startsWith(const ProxiesRoute().location)) return 1;
|
|
if (location.startsWith(const LogsOverviewRoute().location)) return 2;
|
|
if (location.startsWith(const SettingsRoute().location)) return 3;
|
|
if (location.startsWith(const AboutRoute().location)) return 4;
|
|
return 0;
|
|
}
|
|
|
|
void switchTab(int index, BuildContext context) {
|
|
switch (index) {
|
|
case 0:
|
|
const HomeRoute().go(context);
|
|
case 1:
|
|
const ProxiesRoute().go(context);
|
|
case 2:
|
|
const LogsOverviewRoute().go(context);
|
|
case 3:
|
|
const SettingsRoute().go(context);
|
|
case 4:
|
|
const AboutRoute().go(context);
|
|
}
|
|
}
|
|
|
|
@riverpod
|
|
class RouterListenable extends _$RouterListenable
|
|
with AppLogger
|
|
implements Listenable {
|
|
VoidCallback? _routerListener;
|
|
bool _introCompleted = false;
|
|
|
|
@override
|
|
Future<void> build() async {
|
|
_introCompleted = ref.watch(introCompletedProvider);
|
|
|
|
ref.listenSelf((_, __) {
|
|
if (state.isLoading) return;
|
|
loggy.debug("triggering listener");
|
|
_routerListener?.call();
|
|
});
|
|
}
|
|
|
|
// ignore: avoid_build_context_in_providers
|
|
String? redirect(BuildContext context, GoRouterState state) {
|
|
// if (this.state.isLoading || this.state.hasError) return null;
|
|
|
|
final isIntro = state.uri.path == const IntroRoute().location;
|
|
|
|
if (!_introCompleted) {
|
|
return const IntroRoute().location;
|
|
} else if (isIntro) {
|
|
return const HomeRoute().location;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
void addListener(VoidCallback listener) {
|
|
_routerListener = listener;
|
|
}
|
|
|
|
@override
|
|
void removeListener(VoidCallback listener) {
|
|
_routerListener = null;
|
|
}
|
|
}
|