import 'dart:async'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/controller.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/manager/window_manager.dart'; import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; class AppStateManager extends ConsumerStatefulWidget { final Widget child; const AppStateManager({super.key, required this.child}); @override ConsumerState createState() => _AppStateManagerState(); } class _AppStateManagerState extends ConsumerState with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); ref.listenManual(checkIpProvider, (prev, next) { if (prev != next && next.a && next.c) { ref.read(networkDetectionProvider.notifier).startCheck(); } }); ref.listenManual(configProvider, (prev, next) { if (prev != next) { appController.savePreferencesDebounce(); } }); ref.listenManual(needUpdateGroupsProvider, (prev, next) { if (prev != next) { appController.updateGroupsDebounce(); } }); if (window == null) { return; } ref.listenManual(autoSetSystemDnsStateProvider, (prev, next) async { if (prev == next) { return; } if (next.a == true && next.b == true) { macOS?.updateDns(false); } else { macOS?.updateDns(true); } }); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Future didChangeAppLifecycleState(AppLifecycleState state) async { commonPrint.log('$state'); if (state == AppLifecycleState.resumed) { render?.resume(); WidgetsBinding.instance.addPostFrameCallback((_) { appController.tryCheckIp(); if (system.isAndroid) { appController.tryStartCore(); } }); } } @override void didChangePlatformBrightness() { appController.updateBrightness(); } @override Widget build(BuildContext context) { return Listener( onPointerHover: (_) { render?.resume(); }, child: widget.child, ); } } class AppEnvManager extends StatelessWidget { final Widget child; const AppEnvManager({super.key, required this.child}); @override Widget build(BuildContext context) { if (kDebugMode) { if (globalState.isPre) { return Banner( message: 'DEBUG', location: BannerLocation.topEnd, child: child, ); } } if (globalState.isPre) { return Banner( message: 'PRE', location: BannerLocation.topEnd, child: child, ); } return child; } } class AppSidebarContainer extends ConsumerWidget { final Widget child; const AppSidebarContainer({super.key, required this.child}); // Widget _buildLoading() { // return Consumer( // builder: (_, ref, _) { // final loading = ref.watch(loadingProvider); // final isMobileView = ref.watch(isMobileViewProvider); // return loading && !isMobileView // ? RotatedBox( // quarterTurns: 1, // child: const LinearProgressIndicator(), // ) // : Container(); // }, // ); // } Widget _buildBackground({ required BuildContext context, required Widget child, }) { return Material(color: context.colorScheme.surfaceContainer, child: child); // if (!system.isMacOS) { // return Material( // color: context.colorScheme.surfaceContainer, // child: child, // ); // } // return child; // return TransparentMacOSSidebar( // child: Material(color: Colors.transparent, child: child), // ); } void _updateSideBarWidth(WidgetRef ref, double contentWidth) { WidgetsBinding.instance.addPostFrameCallback((_) { ref.read(sideWidthProvider.notifier).value = ref.read(viewSizeProvider.select((state) => state.width)) - contentWidth; }); } @override Widget build(BuildContext context, WidgetRef ref) { final navigationState = ref.watch(navigationStateProvider); final navigationItems = navigationState.navigationItems; final isMobileView = navigationState.viewMode == ViewMode.mobile; if (isMobileView) { return child; } final currentIndex = navigationState.currentIndex; final showLabel = ref.watch(appSettingProvider).showLabel; return Row( children: [ _buildBackground( context: context, child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ if (system.isMacOS) SizedBox(height: 22), SizedBox(height: 10), if (!system.isMacOS) ...[ ClipRect(child: AppIcon()), SizedBox(height: 12), ], Expanded( child: ScrollConfiguration( behavior: HiddenBarScrollBehavior(), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: NavigationRail( scrollable: true, minExtendedWidth: 200, backgroundColor: Colors.transparent, selectedLabelTextStyle: context .textTheme .labelLarge! .copyWith(color: context.colorScheme.onSurface), unselectedLabelTextStyle: context .textTheme .labelLarge! .copyWith(color: context.colorScheme.onSurface), destinations: navigationItems .map( (e) => NavigationRailDestination( icon: e.icon, label: Text(Intl.message(e.label.name)), ), ) .toList(), onDestinationSelected: (index) { appController.toPage( navigationItems[index].label, ); }, extended: false, selectedIndex: currentIndex, labelType: showLabel ? NavigationRailLabelType.all : NavigationRailLabelType.none, ), ), ], ), ), ), const SizedBox(height: 16), IconButton( onPressed: () { ref .read(appSettingProvider.notifier) .update( (state) => state.copyWith(showLabel: !state.showLabel), ); }, icon: Icon( Icons.menu, color: context.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 16), ], ), ), ), Expanded( flex: 1, child: ClipRect( child: LayoutBuilder( builder: (_, constraints) { _updateSideBarWidth(ref, constraints.maxWidth); return child; }, ), ), ), ], ); } }