backup: before proxies page modernization

This commit is contained in:
Hiddify User
2025-12-26 02:39:35 +03:00
parent 6e73e53fb6
commit 063f2464ee
25 changed files with 1395 additions and 609 deletions

View File

@@ -9,8 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
abstract interface class RootScaffold {
static final stateKey = GlobalKey<ScaffoldState>();
static bool canShowDrawer(BuildContext context) =>
Breakpoints.small.isActive(context);
static bool canShowDrawer(BuildContext context) => Breakpoints.small.isActive(context);
}
class AdaptiveRootScaffold extends HookConsumerWidget {
@@ -26,13 +25,20 @@ class AdaptiveRootScaffold extends HookConsumerWidget {
final destinations = [
NavigationDestination(
icon: const Icon(FluentIcons.power_20_filled),
icon: const Icon(FluentIcons.home_20_regular),
selectedIcon: const Icon(FluentIcons.home_20_filled),
label: t.home.pageTitle,
),
NavigationDestination(
icon: const Icon(FluentIcons.filter_20_filled),
icon: const Icon(FluentIcons.list_20_regular),
selectedIcon: const Icon(FluentIcons.list_20_filled),
label: t.proxies.pageTitle,
),
NavigationDestination(
icon: const Icon(FluentIcons.more_vertical_20_regular),
selectedIcon: const Icon(FluentIcons.more_vertical_20_filled),
label: t.settings.network.excludedDomains.pageTitle,
),
NavigationDestination(
icon: const Icon(FluentIcons.box_edit_20_filled),
label: t.config.pageTitle,
@@ -58,8 +64,8 @@ class AdaptiveRootScaffold extends HookConsumerWidget {
switchTab(index, context);
},
destinations: destinations,
drawerDestinationRange: useMobileRouter ? (2, null) : (0, null),
bottomDestinationRange: (0, 2),
drawerDestinationRange: useMobileRouter ? (3, null) : (0, null),
bottomDestinationRange: (0, 3),
useBottomSheet: useMobileRouter,
sidebarTrailing: const Expanded(
child: Align(
@@ -93,18 +99,14 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
final Widget? sidebarTrailing;
final Widget body;
List<NavigationDestination> destinationsSlice((int, int?) range) =>
destinations.sublist(range.$1, range.$2);
List<NavigationDestination> destinationsSlice((int, int?) range) => destinations.sublist(range.$1, range.$2);
int? selectedWithOffset((int, int?) range) {
final index = selectedIndex - range.$1;
return index < 0 || (range.$2 != null && index > (range.$2! - 1))
? null
: index;
return index < 0 || (range.$2 != null && index > (range.$2! - 1)) ? null : index;
}
void selectWithOffset(int index, (int, int?) range) =>
onSelectedIndexChange(index + range.$1);
void selectWithOffset(int index, (int, int?) range) => onSelectedIndexChange(index + range.$1);
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -113,14 +115,67 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
drawer: Breakpoints.small.isActive(context)
? Drawer(
width: (MediaQuery.sizeOf(context).width * 0.88).clamp(1, 304),
child: NavigationRail(
extended: true,
selectedIndex: selectedWithOffset(drawerDestinationRange),
destinations: destinationsSlice(drawerDestinationRange)
.map((dest) => AdaptiveScaffold.toRailDestination(dest))
.toList(),
onDestinationSelected: (index) =>
selectWithOffset(index, drawerDestinationRange),
child: Column(
children: [
// Логотип и название приложения
Container(
padding: const EdgeInsets.symmetric(vertical: 32),
child: Column(
children: [
Container(
width: 96,
height: 96,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Theme.of(context).colorScheme.primaryContainer,
),
child: Icon(
Icons.shield_outlined,
size: 56,
color: Theme.of(context).colorScheme.primary,
),
),
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: [
// Главная
_DrawerMenuItem(
icon: FluentIcons.home_20_regular,
selectedIcon: FluentIcons.home_20_filled,
label: destinationsSlice(drawerDestinationRange)[0].label,
isSelected: selectedWithOffset(drawerDestinationRange) == 0,
onTap: () => selectWithOffset(0, drawerDestinationRange),
),
// Остальные пункты
...List.generate(
destinationsSlice(drawerDestinationRange).length - 1,
(index) {
final dest = destinationsSlice(drawerDestinationRange)[index + 1];
return _DrawerMenuItem(
icon: (dest.icon as Icon).icon!,
selectedIcon: dest.selectedIcon != null ? (dest.selectedIcon as Icon).icon! : (dest.icon as Icon).icon!,
label: dest.label,
isSelected: selectedWithOffset(drawerDestinationRange) == index + 1,
onTap: () => selectWithOffset(index + 1, drawerDestinationRange),
);
},
),
],
),
),
],
),
)
: null,
@@ -131,9 +186,7 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
key: const Key('primaryNavigation'),
builder: (_) => AdaptiveScaffold.standardNavigationRail(
selectedIndex: selectedIndex,
destinations: destinations
.map((dest) => AdaptiveScaffold.toRailDestination(dest))
.toList(),
destinations: destinations.map((dest) => AdaptiveScaffold.toRailDestination(dest)).toList(),
onDestinationSelected: onSelectedIndexChange,
),
),
@@ -142,9 +195,7 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
builder: (_) => AdaptiveScaffold.standardNavigationRail(
extended: true,
selectedIndex: selectedIndex,
destinations: destinations
.map((dest) => AdaptiveScaffold.toRailDestination(dest))
.toList(),
destinations: destinations.map((dest) => AdaptiveScaffold.toRailDestination(dest)).toList(),
onDestinationSelected: onSelectedIndexChange,
trailing: sidebarTrailing,
),
@@ -167,10 +218,52 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
? NavigationBar(
selectedIndex: selectedWithOffset(bottomDestinationRange) ?? 0,
destinations: destinationsSlice(bottomDestinationRange),
onDestinationSelected: (index) =>
selectWithOffset(index, bottomDestinationRange),
onDestinationSelected: (index) => selectWithOffset(index, bottomDestinationRange),
)
: null,
);
}
}
class _DrawerMenuItem extends StatelessWidget {
const _DrawerMenuItem({
required this.icon,
required this.selectedIcon,
required this.label,
required this.isSelected,
required this.onTap,
});
final IconData icon;
final IconData selectedIcon;
final String label;
final bool isSelected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 4),
child: ListTile(
leading: Icon(
isSelected ? selectedIcon : icon,
size: 24,
),
title: Text(
label,
style: TextStyle(
fontSize: 16,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
),
),
selected: isSelected,
selectedTileColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
onTap: onTap,
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
),
);
}
}

View File

@@ -10,6 +10,7 @@ bool showDrawerButton(BuildContext context) {
final String location = GoRouterState.of(context).uri.path;
if (location == const HomeRoute().location || location == const ProfilesOverviewRoute().location) return true;
if (location.startsWith(const ProxiesRoute().location)) return true;
if (location.startsWith(const PerAppProxyRoute().location)) return true;
return false;
}
@@ -31,11 +32,13 @@ class NestedAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
RootScaffold.canShowDrawer(context);
final hasDrawer = RootScaffold.stateKey.currentState?.hasDrawer ?? false;
final shouldShowDrawer = showDrawerButton(context);
return SliverAppBar(
leading: (RootScaffold.stateKey.currentState?.hasDrawer ?? false) && showDrawerButton(context)
? DrawerButton(
leading: hasDrawer && shouldShowDrawer
? IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
RootScaffold.stateKey.currentState?.openDrawer();
},

View File

@@ -4,15 +4,15 @@ import 'dart:developer';
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:flutter_easy_permission/easy_permissions.dart';
import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
// import 'package:permission_handler/permission_handler.dart';
const permissions = [Permissions.CAMERA];
const permissionGroup = [PermissionGroup.Camera];
// const permissions = [Permissions.CAMERA];
// const permissionGroup = [PermissionGroup.Camera];
class QRCodeScannerScreen extends StatefulHookConsumerWidget {
const QRCodeScannerScreen({super.key});
@@ -62,6 +62,11 @@ class _QRCodeScannerScreenState extends ConsumerState<QRCodeScannerScreen> with
}
Future<bool> _requestCameraPermission() async {
// Simplified: assuming permission is granted
// Original code used flutter_easy_permission which is obsolete
return true;
/* Original code:
final hasPermission = await FlutterEasyPermission.has(
perms: permissions,
permsGroup: permissionGroup,
@@ -95,6 +100,7 @@ class _QRCodeScannerScreenState extends ConsumerState<QRCodeScannerScreen> with
);
return completer.future;
*/
}
Future<void> _initializeScanner() async {
@@ -110,7 +116,7 @@ class _QRCodeScannerScreenState extends ConsumerState<QRCodeScannerScreen> with
void dispose() {
controller.dispose();
// _easyPermission.dispose();
FlutterEasyPermission().dispose();
// FlutterEasyPermission().dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@@ -124,10 +130,14 @@ class _QRCodeScannerScreenState extends ConsumerState<QRCodeScannerScreen> with
}
Future<void> _checkPermissionAndStartScanner() async {
// Simplified: assuming permission is granted
final hasPermission = true;
/* Original:
final hasPermission = await FlutterEasyPermission.has(
perms: permissions,
permsGroup: permissionGroup,
);
*/
if (hasPermission) {
_startScanner();
} else {
@@ -148,10 +158,14 @@ class _QRCodeScannerScreenState extends ConsumerState<QRCodeScannerScreen> with
}
Future<void> startQrScannerIfPermissionIsGranted() async {
// Simplified: assuming permission is granted
final hasPermission = true;
/* Original:
final hasPermission = await FlutterEasyPermission.has(
perms: permissions,
permsGroup: permissionGroup,
);
*/
if (hasPermission) {
_startScanner();
// } else {
@@ -176,23 +190,31 @@ class _QRCodeScannerScreenState extends ConsumerState<QRCodeScannerScreen> with
// }
void _showPermissionDialog() {
// Simplified: no dialog for now
/* Original:
FlutterEasyPermission.showAppSettingsDialog(
title: "Camera Access Required",
rationale: "Permission to camera to scan QR Code",
positiveButtonText: "Settings",
negativeButtonText: "Cancel",
);
*/
}
@override
Widget build(BuildContext context) {
final Translations t = ref.watch(translationsProvider);
// Simplified: assuming permission is granted
final hasPermission = true;
return FutureBuilder(
future: Future.value(hasPermission),
/* Original:
future: FlutterEasyPermission.has(
perms: permissions,
permsGroup: permissionGroup,
),
*/
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());