diff --git a/lib/core/router/app_router.dart b/lib/core/router/app_router.dart index 951e1611..6970a580 100644 --- a/lib/core/router/app_router.dart +++ b/lib/core/router/app_router.dart @@ -50,26 +50,26 @@ GoRouter router(RouterRef ref) { } final tabLocations = [ - const HomeRoute().location, // 0: Главная - const ProxiesRoute().location, // 1: Локации - const PerAppProxyRoute().location, // 2: Исключения - const SettingsRoute().location, // 3: Настройки - const AboutRoute().location, // 4: О программе + 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 - + 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; } diff --git a/lib/features/common/adaptive_root_scaffold.dart b/lib/features/common/adaptive_root_scaffold.dart index cffaf4e3..8dd95328 100644 --- a/lib/features/common/adaptive_root_scaffold.dart +++ b/lib/features/common/adaptive_root_scaffold.dart @@ -172,49 +172,49 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget { child: ListView( padding: const EdgeInsets.symmetric(horizontal: 16), children: [ - // О программе - Builder( - builder: (context) { - final t = ref.watch(translationsProvider); - return _DrawerMenuItem( - icon: FluentIcons.info_24_regular, - selectedIcon: FluentIcons.info_24_filled, - label: t.about.pageTitle, - isSelected: false, - onTap: () { - RootScaffold.stateKey.currentState?.closeDrawer(); - const AboutRoute().push(context); - }, - ); - }, - ), - // Настройки - Builder( - builder: (context) { - final t = ref.watch(translationsProvider); - return _DrawerMenuItem( - icon: FluentIcons.settings_24_regular, - selectedIcon: FluentIcons.settings_24_filled, - label: t.settings.pageTitle, - isSelected: false, - onTap: () { - RootScaffold.stateKey.currentState?.closeDrawer(); - const SettingsRoute().push(context); - }, - ); - }, - ), - const SizedBox(height: 16), - const Divider(), - const _DrawerThemeItem(), - const _DrawerLanguageItem(), - const _DrawerLicensesItem(), - ], - ), + // О программе + Builder( + builder: (context) { + final t = ref.watch(translationsProvider); + return _DrawerMenuItem( + icon: FluentIcons.info_24_regular, + selectedIcon: FluentIcons.info_24_filled, + label: t.about.pageTitle, + isSelected: false, + onTap: () { + RootScaffold.stateKey.currentState?.closeDrawer(); + const AboutRoute().push(context); + }, + ); + }, ), + // Настройки + Builder( + builder: (context) { + final t = ref.watch(translationsProvider); + return _DrawerMenuItem( + icon: FluentIcons.settings_24_regular, + selectedIcon: FluentIcons.settings_24_filled, + label: t.settings.pageTitle, + isSelected: false, + onTap: () { + RootScaffold.stateKey.currentState?.closeDrawer(); + const SettingsRoute().push(context); + }, + ); + }, + ), + const SizedBox(height: 16), + const Divider(), + const _DrawerThemeItem(), + const _DrawerLanguageItem(), + const _DrawerLicensesItem(), ], ), ), + ], + ), + ), body: AdaptiveLayout( primaryNavigation: SlotLayout( config: { diff --git a/lib/features/per_app_proxy/overview/per_app_proxy_page.dart b/lib/features/per_app_proxy/overview/per_app_proxy_page.dart index 34464200..88c7f035 100644 --- a/lib/features/per_app_proxy/overview/per_app_proxy_page.dart +++ b/lib/features/per_app_proxy/overview/per_app_proxy_page.dart @@ -67,16 +67,16 @@ class PerAppProxyPage extends HookConsumerWidget with PresLogger { tooltip: localizations.searchFieldLabel, ), ], - bottom: PlatformUtils.isDesktop - ? null // На Desktop только вкладка "Домены" - : TabBar( - controller: tabController, - onTap: (index) => currentTab.value = index, - tabs: [ - Tab(text: t.settings.network.excludedDomains.domainsTab), - Tab(text: t.settings.network.excludedDomains.appsTab), - ], - ), + bottom: PlatformUtils.isDesktop + ? null // На Desktop только вкладка "Домены" + : TabBar( + controller: tabController, + onTap: (index) => currentTab.value = index, + tabs: [ + Tab(text: t.settings.network.excludedDomains.domainsTab), + Tab(text: t.settings.network.excludedDomains.appsTab), + ], + ), ); final searchAppBar = SliverAppBar( diff --git a/lib/features/window/notifier/window_notifier.dart b/lib/features/window/notifier/window_notifier.dart index a834212a..ddf4354b 100644 --- a/lib/features/window/notifier/window_notifier.dart +++ b/lib/features/window/notifier/window_notifier.dart @@ -19,11 +19,6 @@ class WindowNotifier extends _$WindowNotifier with AppLogger { Future build() async { if (!PlatformUtils.isDesktop) return; - // if (Platform.isWindows) { - // loggy.debug("ensuring single instance"); - // await WindowsSingleInstance.ensureSingleInstance([], "Hiddify"); - // } - await windowManager.ensureInitialized(); await windowManager.setMinimumSize(minimumWindowSize); await windowManager.setSize(defaultWindowSize); diff --git a/lib/main.dart b/lib/main.dart index 915b363b..2ce831bd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,70 +1,9 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:umbrix/bootstrap.dart'; import 'package:umbrix/core/model/environment.dart'; -final lockFile = File('/tmp/umbrix.lock'); - -Future _activateExistingWindow() async { - // Try to activate existing window via wmctrl - try { - final result = await Process.run('wmctrl', ['-a', 'Umbrix']); - if (result.exitCode == 0) return; - } catch (e) { - // wmctrl not available, try xdotool - try { - await Process.run('xdotool', ['search', '--name', 'Umbrix', 'windowactivate']); - } catch (e) { - // No window activation possible - } - } -} - -void _cleanupLockFile() { - try { - if (lockFile.existsSync()) { - lockFile.deleteSync(); - } - } catch (e) { - // Ignore cleanup errors - } -} - void main() async { - // Single instance check - BEFORE Flutter initialization - if (Platform.isLinux || Platform.isWindows) { - if (await lockFile.exists()) { - // Check if process is still alive - try { - final pidString = await lockFile.readAsString(); - final pid = int.tryParse(pidString.trim()); - if (pid != null) { - final result = await Process.run('ps', ['-p', pid.toString()]); - if (result.exitCode != 0) { - // Process dead, remove stale lock - await lockFile.delete(); - } else { - // Process alive - activate window and exit - await _activateExistingWindow(); - exit(0); - } - } - } catch (e) { - // Error reading lock, remove it - try { await lockFile.delete(); } catch (e) {} - } - } - - // Create lock file - try { - await lockFile.create(); - await lockFile.writeAsString(pid.toString()); - } catch (e) { - // If can't create, continue anyway - } - } - final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); diff --git a/linux/my_application.cc b/linux/my_application.cc index c0678b67..50977fad 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -14,7 +14,7 @@ struct _MyApplication }; G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) -#define ICON_PATH "./umbrix.png" +#define ICON_PATH "/usr/share/icons/hicolor/256x256/apps/umbrix.png" // Implements GApplication::activate. static void my_application_activate(GApplication *application) diff --git a/linux/packaging/deb/make_config.yaml b/linux/packaging/deb/make_config.yaml index 8b7244b0..deb29855 100644 --- a/linux/packaging/deb/make_config.yaml +++ b/linux/packaging/deb/make_config.yaml @@ -11,6 +11,7 @@ essential: false icon: ./logo/ic_launcher_playstore.png postinstall_scripts: + - chmod 644 /usr/share/icons/hicolor/256x256/apps/umbrix.png - echo "Installed Umbrix VPN" postuninstall_scripts: - echo "Uninstalled Umbrix"