import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:nomo/config/theme/theme_extensions/theme_extension.dart'; import 'package:nomo/utils/misc.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import '../config/theme/ix_theme.dart'; import '../config/translations/localization_service.dart'; import '../config/translations/strings_enum.dart'; import '../utils/developer/ix_developer_tools.dart'; import '../utils/device_manager.dart'; import '../utils/ix_back_button_dispatcher.dart'; import 'components/ix_snackbar.dart'; import 'constants/configs.dart'; import 'data/sp/ix_sp.dart'; import 'routes/app_pages.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'widgets/click_opacity.dart'; import 'widgets/gradient_circle_header.dart'; import 'widgets/triple_tap_detector.dart'; class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return ScreenUtilInit( // 适配桌面版高度 designSize: isDesktop ? const Size(340, 640) : const Size(375, 812), minTextAdapt: true, splitScreenMode: true, useInheritedMediaQuery: true, // 只在屏幕尺寸真正变化时才重建(如旋转屏幕),而不是每次 MediaQuery 变化都重建 rebuildFactor: (old, data) => old.size != data.size, builder: (context, widget) => RefreshConfiguration( headerBuilder: () => GradientCircleHeader(), // 配置默认页眉指示器。如果您每个页面都有相同的页眉指示器,您需要设置此 footerBuilder: () => ClassicFooter(), // 配置默认底部指示器 headerTriggerDistance: 80.0, // 标题触发刷新触发距离 springDescription: SpringDescription( mass: 1, stiffness: 1000, damping: 100, ), // 设置没有回弹动画,属性含义请参阅Flutter API maxOverScrollExtent: 40, //头部最大拖动范围。如果发生超出视图区域的情况,请设置此属性 maxUnderScrollExtent: 0, // 底部最大拖动范围 enableScrollWhenRefreshCompleted: true, //此属性与PageView和TabBarView不兼容。如果您需要TabBarView左右滑动,则需要将其设置为true。 enableLoadingWhenFailed: true, //在负载失败的情况下,用户仍然可以通过手势下拉触发更多负载。 hideFooterWhenNotFull: false, //禁用上拉加载更多功能,当视口小于一屏时 enableBallisticLoad: true, //触发通过BallisticScrollActivity加载更多 child: _buildMaterialApp(), ), ); } Widget _buildMaterialApp() { return GetMaterialApp.router( title: 'ixVPN', useInheritedMediaQuery: true, debugShowCheckedModeBanner: Configs.debug, backButtonDispatcher: IXBackButtonDispatcher(), getPages: AppPages.routes, theme: IXTheme.getThemeData(isLight: true), darkTheme: IXTheme.getThemeData(isLight: false), themeMode: ReactiveTheme.initialThemeMode, fallbackLocale: LocalizationService.defaultLanguage, locale: IXSP.getCurrentLocal(), translations: LocalizationService.getInstance(), builder: (context, widget) => _buildThemedApp(context, widget), ); } Widget _buildThemedApp(BuildContext context, Widget? widget) { return MediaQuery( data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling), child: Stack( children: [ widget!, Positioned( top: 0, right: 0, width: 100, height: 100, child: TripleTapDetector( requiredTaps: 10, onTripleTap: () async { Clipboard.setData( ClipboardData(text: await DeviceManager.getDeviceId()), ); IXSnackBar.showIXSnackBar( title: Strings.copied.tr, message: await DeviceManager.getDeviceId(), ); }, child: const SizedBox.shrink(), // 不显示任何东西 ), ), if (Configs.debug) Positioned( bottom: 100, right: 10, child: ClickOpacity( child: Container( width: 40, height: 40, decoration: BoxDecoration( color: Get.reactiveTheme.primaryColor.withValues( alpha: 0.5, ), borderRadius: BorderRadius.circular(40), ), child: Icon(Icons.adb, color: Get.reactiveTheme.primaryColor), ), onTap: () { // 使用简化版开发者工具 IXDeveloperTools.show(); }, ), ), ], ), ); } }