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
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
|
||||
import 'package:hiddify/gen/assets.gen.dart';
|
||||
import 'package:hiddify/core/localization/translations.dart';
|
||||
import 'package:hiddify/core/router/router.dart';
|
||||
import 'package:hiddify/features/stats/widget/side_bar_stats_overview.dart';
|
||||
import 'package:hiddify/core/router/routes.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:umbrix/gen/assets.gen.dart';
|
||||
import 'package:umbrix/core/localization/translations.dart';
|
||||
import 'package:umbrix/core/router/router.dart';
|
||||
import 'package:umbrix/features/stats/widget/side_bar_stats_overview.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:hiddify/core/theme/theme_preferences.dart';
|
||||
import 'package:hiddify/core/theme/app_theme_mode.dart';
|
||||
import 'package:hiddify/core/localization/locale_preferences.dart';
|
||||
import 'package:hiddify/core/localization/locale_extensions.dart';
|
||||
import 'package:umbrix/core/theme/theme_preferences.dart';
|
||||
import 'package:umbrix/core/theme/app_theme_mode.dart';
|
||||
import 'package:umbrix/core/localization/locale_preferences.dart';
|
||||
import 'package:umbrix/core/localization/locale_extensions.dart';
|
||||
import 'package:umbrix/utils/utils.dart';
|
||||
|
||||
abstract interface class RootScaffold {
|
||||
static final stateKey = GlobalKey<ScaffoldState>();
|
||||
@@ -27,6 +28,10 @@ class AdaptiveRootScaffold extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final t = ref.watch(translationsProvider);
|
||||
|
||||
final interceptBackToHome = !PlatformUtils.isDesktop;
|
||||
final proxiesLocation = const ProxiesRoute().location;
|
||||
final perAppProxyLocation = const PerAppProxyRoute().location;
|
||||
|
||||
final selectedIndex = getCurrentIndex(context);
|
||||
|
||||
final destinations = [
|
||||
@@ -63,8 +68,8 @@ class AdaptiveRootScaffold extends HookConsumerWidget {
|
||||
switchTab(index, context);
|
||||
},
|
||||
destinations: destinations,
|
||||
drawerDestinationRange: useMobileRouter ? (3, null) : (0, null),
|
||||
bottomDestinationRange: (0, 3),
|
||||
drawerDestinationRange: (3, null), // Настройки и О программе всегда в drawer
|
||||
bottomDestinationRange: (0, 3), // Первые 3 пункта в bottom nav
|
||||
useBottomSheet: useMobileRouter,
|
||||
sidebarTrailing: const Expanded(
|
||||
child: Align(
|
||||
@@ -72,7 +77,27 @@ class AdaptiveRootScaffold extends HookConsumerWidget {
|
||||
child: SideBarStatsOverview(),
|
||||
),
|
||||
),
|
||||
body: navigator,
|
||||
body: BackButtonListener(
|
||||
onBackButtonPressed: () async {
|
||||
if (!interceptBackToHome) return false;
|
||||
final location = GoRouterState.of(context).uri.path;
|
||||
final shouldGoHome = location.startsWith(proxiesLocation) || location.startsWith(perAppProxyLocation);
|
||||
|
||||
assert(() {
|
||||
debugPrint(
|
||||
'BACK_INTERCEPT AdaptiveRootScaffold location=$location shouldGoHome=$shouldGoHome',
|
||||
);
|
||||
return true;
|
||||
}());
|
||||
|
||||
if (shouldGoHome) {
|
||||
const HomeRoute().go(context);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: navigator,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -111,43 +136,42 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return Scaffold(
|
||||
key: RootScaffold.stateKey,
|
||||
drawer: Breakpoints.small.isActive(context)
|
||||
? Drawer(
|
||||
width: (MediaQuery.sizeOf(context).width * 0.88).clamp(1, 304),
|
||||
drawer: Drawer(
|
||||
width: (MediaQuery.sizeOf(context).width * 0.88).clamp(1, 304),
|
||||
child: Column(
|
||||
children: [
|
||||
// Логотип и название приложения
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Column(
|
||||
children: [
|
||||
// Логотип и название приложения
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
child: Assets.images.umbrixLogo.image(
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Umbrix',
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
width: 80,
|
||||
height: 80,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
child: Assets.images.umbrixLogo.image(
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
// Список пунктов меню
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Umbrix',
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Список пунктов меню
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
children: [
|
||||
// О программе
|
||||
Builder(
|
||||
builder: (context) {
|
||||
@@ -190,29 +214,11 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
body: AdaptiveLayout(
|
||||
primaryNavigation: SlotLayout(
|
||||
config: <Breakpoint, SlotLayoutConfig>{
|
||||
Breakpoints.medium: SlotLayout.from(
|
||||
key: const Key('primaryNavigation'),
|
||||
builder: (_) => AdaptiveScaffold.standardNavigationRail(
|
||||
selectedIndex: selectedIndex,
|
||||
destinations: destinations.map((dest) => AdaptiveScaffold.toRailDestination(dest)).toList(),
|
||||
onDestinationSelected: onSelectedIndexChange,
|
||||
),
|
||||
),
|
||||
Breakpoints.large: SlotLayout.from(
|
||||
key: const Key('primaryNavigation1'),
|
||||
builder: (_) => AdaptiveScaffold.standardNavigationRail(
|
||||
extended: true,
|
||||
selectedIndex: selectedIndex,
|
||||
destinations: destinations.map((dest) => AdaptiveScaffold.toRailDestination(dest)).toList(),
|
||||
onDestinationSelected: onSelectedIndexChange,
|
||||
trailing: sidebarTrailing,
|
||||
),
|
||||
),
|
||||
// Убираем боковую навигацию для Desktop
|
||||
},
|
||||
),
|
||||
body: SlotLayout(
|
||||
@@ -226,14 +232,12 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
// AdaptiveLayout bottom sheet has accessibility issues
|
||||
bottomNavigationBar: useBottomSheet && Breakpoints.small.isActive(context)
|
||||
? NavigationBar(
|
||||
selectedIndex: selectedWithOffset(bottomDestinationRange) ?? 0,
|
||||
destinations: destinationsSlice(bottomDestinationRange),
|
||||
onDestinationSelected: (index) => selectWithOffset(index, bottomDestinationRange),
|
||||
)
|
||||
: null,
|
||||
// Нижняя навигация - первые 3 пункта для всех платформ
|
||||
bottomNavigationBar: NavigationBar(
|
||||
selectedIndex: selectedWithOffset(bottomDestinationRange) ?? 0,
|
||||
destinations: destinationsSlice(bottomDestinationRange),
|
||||
onDestinationSelected: (index) => selectWithOffset(index, bottomDestinationRange),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddify/core/analytics/analytics_controller.dart';
|
||||
import 'package:hiddify/core/localization/locale_extensions.dart';
|
||||
import 'package:hiddify/core/localization/locale_preferences.dart';
|
||||
import 'package:hiddify/core/localization/translations.dart';
|
||||
import 'package:hiddify/core/model/region.dart';
|
||||
import 'package:hiddify/core/preferences/actions_at_closing.dart';
|
||||
import 'package:hiddify/core/preferences/general_preferences.dart';
|
||||
import 'package:hiddify/core/theme/app_theme_mode.dart';
|
||||
import 'package:hiddify/core/theme/theme_preferences.dart';
|
||||
import 'package:hiddify/features/config_option/data/config_option_repository.dart';
|
||||
import 'package:umbrix/core/analytics/analytics_controller.dart';
|
||||
import 'package:umbrix/core/localization/locale_extensions.dart';
|
||||
import 'package:umbrix/core/localization/locale_preferences.dart';
|
||||
import 'package:umbrix/core/localization/translations.dart';
|
||||
import 'package:umbrix/core/model/region.dart';
|
||||
import 'package:umbrix/core/preferences/actions_at_closing.dart';
|
||||
import 'package:umbrix/core/preferences/general_preferences.dart';
|
||||
import 'package:umbrix/core/theme/app_theme_mode.dart';
|
||||
import 'package:umbrix/core/theme/theme_preferences.dart';
|
||||
import 'package:umbrix/features/config_option/data/config_option_repository.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
class LocalePrefTile extends ConsumerWidget {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hiddify/core/router/router.dart';
|
||||
import 'package:hiddify/features/common/adaptive_root_scaffold.dart';
|
||||
import 'package:hiddify/utils/utils.dart';
|
||||
import 'package:umbrix/core/router/router.dart';
|
||||
import 'package:umbrix/features/common/adaptive_root_scaffold.dart';
|
||||
import 'package:umbrix/utils/utils.dart';
|
||||
|
||||
bool showDrawerButton(BuildContext context) {
|
||||
if (!useMobileRouter) return true;
|
||||
|
||||
@@ -4,8 +4,8 @@ import 'package:dartx/dartx.dart';
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_easy_permission/easy_permissions.dart';
|
||||
import 'package:hiddify/core/localization/translations.dart';
|
||||
import 'package:hiddify/utils/utils.dart';
|
||||
import 'package:umbrix/core/localization/translations.dart';
|
||||
import 'package:umbrix/utils/utils.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
// import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
Reference in New Issue
Block a user