import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart' hide ConnectionState; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:nomo/app/constants/iconfont/iconfont.dart'; import '../../../../config/theme/theme_extensions/theme_extension.dart'; import '../../../base/base_view.dart'; import '../../../constants/assets.dart'; import '../../../routes/app_pages.dart'; import '../../../widgets/click_opacity.dart'; import '../../../widgets/ix_image.dart'; import '../widgets/connection_button.dart'; import '../controllers/home_controller.dart'; import 'package:flutter_svg/flutter_svg.dart'; import '../widgets/menu_list.dart'; class HomeView extends BaseView { const HomeView({super.key}); @override bool get isPopScope => true; @override Widget buildContent(BuildContext context) { return Container( width: double.maxFinite, margin: EdgeInsets.symmetric(horizontal: 14.w), child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Obx( () => ClickOpacity( onTap: () => Get.toNamed(Routes.SUBSCRIPTION), child: IXImage( source: controller.isPremium ? Assets.premium : Assets.free, width: controller.isPremium ? 92.w : 64.w, height: 28.w, sourceType: ImageSourceType.asset, ), ), ), ClickOpacity( child: Padding( padding: EdgeInsets.only( left: 10.w, right: 0.w, top: 10.w, bottom: 10.w, ), child: Icon( IconFont.icon09, size: 26.w, color: Get.reactiveTheme.hintColor, ), ), onTap: () { Get.toNamed(Routes.SETTING); // ErrorDialog.show( // message: // "The VPN was disconnected unexpectedly. Would you like to reconnect now to stay protected?", // ); }, ), ], ), // 80.verticalSpaceFromWidth, Padding( padding: EdgeInsets.symmetric(vertical: 20.w), child: CarouselSlider( options: CarouselOptions(height: 80.w, viewportFraction: 1.0), items: [1, 2, 3, 4, 5].map((i) { return Builder( builder: (BuildContext context) { return IXImage( source: Assets.bannerTest, width: double.infinity, height: 80.w, sourceType: ImageSourceType.asset, borderRadius: 14.r, ); }, ); }).toList(), ), ), Text( "Active time", style: TextStyle( fontSize: 18.sp, height: 1.3, color: Get.reactiveTheme.hintColor, ), ), 2.verticalSpaceFromWidth, Obx( () => Text( controller.coreController.timer, style: TextStyle( fontSize: 28.sp, height: 1.2, color: Get.reactiveTheme.primaryColor, ), ), ), 20.verticalSpaceFromWidth, // 位置选择按钮和最近位置(叠在一起的效果) Stack( children: [ Container( alignment: Alignment.center, margin: EdgeInsets.only(top: 138.w), child: _buildConnectionButton(), ), _buildLocationStack(), ], ), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [MenuList()], ), ), ], ), ), ); } Widget _buildConnectionButton() { return Obx( () => ConnectionButton( state: controller.coreController.state, onTap: () { controller.coreController.handleConnection(); }, ), ); } /// 构建位置堆叠效果(选中位置 + 最近位置) Widget _buildLocationStack() { return Obx(() { if (controller.selectedLocation == null) { return const SizedBox.shrink(); } return Stack( children: [ // 最近位置列表(背景层) if (controller.recentLocations.isNotEmpty) _buildRecentLocationsCard(), // 选中位置(前景层) _buildSelectedLocationCard(), ], ); }); } /// 构建选中位置卡片 Widget _buildSelectedLocationCard() { return GestureDetector( onTap: () { Get.toNamed(Routes.NODE); }, child: Obx(() { return Container( height: 56.w, width: double.maxFinite, padding: EdgeInsets.only(left: 16.w, right: 10.w), decoration: BoxDecoration( color: Get.reactiveTheme.highlightColor, borderRadius: BorderRadius.circular(12.r), ), child: Row( children: [ // 国旗图标 ClipRRect( borderRadius: BorderRadius.circular(4.r), // 设置圆角 child: SvgPicture.asset( Assets.getCountryFlagImage( controller.selectedLocation?.country ?? '', ), width: 32.w, height: 24.w, fit: BoxFit.cover, // placeholderBuilder: (context) => Container( // width: 32.w, // height: 24.w, // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(4.r), // color: Colors.grey[200], // ), // alignment: Alignment.center, // child: Icon( // Icons.flag, // size: 16.w, // color: Colors.grey[400], // ), // ), ), ), 10.horizontalSpace, // 位置名称 Expanded( child: Text( '${controller.selectedLocation?.code ?? ''} - ${controller.selectedLocation?.name ?? ''}', style: TextStyle( fontSize: 16.sp, height: 1.5, fontWeight: FontWeight.w500, color: Get.reactiveTheme.textTheme.bodyLarge!.color, ), ), ), // 箭头图标 Icon( IconFont.icon02, size: 20.w, color: Get.reactiveTheme.textTheme.bodyLarge!.color, ), ], ), ); }), ); } /// 构建最近位置卡片(支持展开/收缩) Widget _buildRecentLocationsCard() { return Obx(() { return Container( margin: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 56.w, bottom: 0), decoration: BoxDecoration( color: Get.reactiveTheme.cardColor, borderRadius: BorderRadius.circular(12.r), ), child: Column( children: [ GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { controller.isRecentLocationsExpanded = !controller.isRecentLocationsExpanded; }, child: SizedBox( height: 44.w, child: Row( children: [ Icon( IconFont.icon68, size: 16.w, color: Get.reactiveTheme.hintColor, ), SizedBox(width: 4.w), Text( 'Recent', style: TextStyle( fontSize: 12.sp, height: 1.2, color: Get.reactiveTheme.hintColor, ), ), const Spacer(), // 最近三个节点的国旗图标(收缩状态)或箭头(展开状态) Obx(() { return AnimatedOpacity( opacity: controller.isRecentLocationsExpanded ? 0.0 : 1.0, duration: const Duration(milliseconds: 300), child: IgnorePointer( ignoring: controller.isRecentLocationsExpanded, child: Row( mainAxisSize: MainAxisSize.min, children: [ ...controller.recentLocations.take(3).map(( location, ) { return Container( margin: EdgeInsets.only(right: 4.w), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5.r), border: Border.all( color: Get.reactiveTheme.canvasColor, width: 0.4, ), ), child: ClipRRect( borderRadius: BorderRadius.circular(4.r), child: SvgPicture.asset( Assets.getCountryFlagImage( location.country ?? '', ), width: 24.w, height: 16.w, fit: BoxFit.cover, // placeholderBuilder: (context) => // Container( // width: 24.w, // height: 16.w, // decoration: BoxDecoration( // borderRadius: // BorderRadius.circular(4.r), // color: Colors.grey[200], // ), // alignment: Alignment.center, // child: Icon( // Icons.flag, // size: 10.w, // color: Colors.grey[400], // ), // ), ), ), ); }), ], ), ), ); }), Obx(() { return AnimatedRotation( turns: controller.isRecentLocationsExpanded ? 0.25 : 0.0, duration: const Duration(milliseconds: 300), child: Icon( IconFont.icon02, size: 20.w, color: Get.reactiveTheme.hintColor, ), ); }), ], ), ), ), // 最近位置列表(可折叠) Obx(() { return ClipRect( child: AnimatedAlign( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, heightFactor: controller.isRecentLocationsExpanded ? 1.0 : 0.0, alignment: Alignment.topLeft, child: AnimatedOpacity( opacity: controller.isRecentLocationsExpanded ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), child: Column( children: controller.recentLocations.map((location) { return ClickOpacity( onTap: () { controller.isRecentLocationsExpanded = !controller.isRecentLocationsExpanded; controller.selectLocation(location); controller.handleConnect(); }, child: Column( children: [ Divider( height: 1, color: Get.reactiveTheme.dividerColor, ), Container( margin: EdgeInsets.symmetric(vertical: 12.h), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // 国旗图标 ClipRRect( borderRadius: BorderRadius.circular( 4.r, ), // 设置圆角 child: SvgPicture.asset( Assets.getCountryFlagImage( location.country ?? '', ), width: 28.w, height: 21.w, fit: BoxFit.cover, // placeholderBuilder: (context) => // Container( // color: Colors.grey[200], // child: Icon( // Icons.flag, // size: 12.w, // color: Colors.grey[400], // ), // ), ), ), SizedBox(width: 10.w), // 位置信息 Expanded( child: Text( '${location.code} - ${location.name}', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, color: Get.reactiveTheme.hintColor, ), ), ), ], ), ), ], ), ); }).toList(), ), ), ), ); }), ], ), ); }); } }