Files
umbrix/lib/core/router/app_router.dart
Umbrix Developer 76a374950f feat: mobile-like window size and always-visible stats
- Changed window size to mobile phone format (400x800)
- Removed width condition for ActiveProxyFooter - now always visible
- Added run-umbrix.sh launch script with icon copying
- Stats cards now display on all screen sizes
2026-01-17 13:09:20 +03:00

123 lines
3.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:umbrix/core/preferences/general_preferences.dart';
import 'package:umbrix/core/router/routes.dart';
import 'package:umbrix/features/deep_link/notifier/deep_link_notifier.dart';
import 'package:umbrix/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(
deepLinkNotifierProvider,
(_, 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,
$introRoute,
],
refreshListenable: notifier,
redirect: notifier.redirect,
observers: [
SentryNavigatorObserver(),
],
);
}
final tabLocations = [
const HomeRoute().location, // 0: Главная
const ProxiesRoute().location, // 1: Локации
const PerAppProxyRoute().location, // 2: Исключения
const SettingsRoute().location, // 3: Настройки
const AboutRoute().location, // 4: О программе
];
int getCurrentIndex(BuildContext context) {
final String location = GoRouterState.of(context).uri.path;
// Проверяем точное совпадение для главной
if (location == const HomeRoute().location) return 0;
// Проверяем остальные маршруты по порядку
// ВАЖНО: более длинные пути проверяем раньше!
if (location.startsWith(const PerAppProxyRoute().location)) return 2; // /settings/per-app-proxy
if (location.startsWith(const ProxiesRoute().location)) return 1; // /proxies
if (location.startsWith(const SettingsRoute().location)) return 3; // /settings
if (location.startsWith(const AboutRoute().location)) return 4; // /about
return 0;
}
void switchTab(int index, BuildContext context) {
assert(index >= 0 && index < tabLocations.length);
final location = tabLocations[index];
return context.go(location);
}
@riverpod
class RouterListenable extends _$RouterListenable with AppLogger implements Listenable {
VoidCallback? _routerListener;
bool _introCompleted = false;
@override
Future<void> build() async {
_introCompleted = ref.watch(Preferences.introCompleted);
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;
}
}