import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:nomo/app/base/base_view.dart'; import 'package:nomo/app/widgets/click_opacity.dart'; import 'package:nomo/app/widgets/ix_app_bar.dart'; import 'package:nomo/app/widgets/submit_btn.dart'; import 'package:nomo/config/theme/theme_extensions/theme_extension.dart'; import '../../../../config/theme/dark_theme_colors.dart'; import '../../../../config/translations/strings_enum.dart'; import '../../../../utils/device_manager.dart'; import '../../../constants/enums.dart'; import '../../../data/sp/ix_sp.dart'; import '../../../components/ix_snackbar.dart'; import '../../../constants/assets.dart'; import '../../../constants/iconfont/iconfont.dart'; import '../../../dialog/all_dialog.dart'; import '../../../routes/app_pages.dart'; import '../../../widgets/ix_image.dart'; import '../controllers/account_controller.dart'; class AccountView extends BaseView { const AccountView({super.key}); @override PreferredSizeWidget? get appBar => IXAppBar(title: Strings.account.tr); @override Widget buildContent(BuildContext context) { return Obx(() { return SingleChildScrollView( padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 10.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Account 信息卡片 // _buildAccountCard(isPremium), _buildAccountSection(), // Security Section if (!controller.apiController.isGuest) _buildSectionHeader(Strings.securitySection.tr), if (!controller.apiController.isGuest) _buildSecuritySection(), 20.verticalSpaceFromWidth, // 底部按钮 _buildBottomButtons(), 20.verticalSpaceFromWidth, ], ), ); }); } /// 构建账户信息卡片 Widget _buildAccountCard(bool isPremium) { return Container( decoration: BoxDecoration( color: Get.reactiveTheme.highlightColor, borderRadius: BorderRadius.circular(12.r), ), child: Column( children: [ // Account 条目 _buildAccountItem(isPremium), _buildDivider(), // UID 条目 _buildUIDItem(), _buildDivider(), // Premium 功能列表 _buildPremiumFeatures(isPremium), ], ), ); } /// Account 条目 Widget _buildAccountItem(bool isPremium) { return Container( height: 56.w, padding: EdgeInsets.symmetric(horizontal: 16.w), child: Row( children: [ // 图标 Container( width: 30.w, height: 30.w, decoration: BoxDecoration( color: Get.reactiveTheme.shadowColor, borderRadius: BorderRadius.circular(8.r), ), child: Icon(IconFont.icon29, size: 20.w, color: Colors.white), ), 10.horizontalSpace, // 标题 Expanded( child: Text( Strings.account.tr, style: TextStyle( fontSize: 14.sp, color: Get.reactiveTheme.textTheme.bodyLarge!.color, fontWeight: FontWeight.w400, ), ), ), // 徽章 IXImage( source: isPremium ? Assets.premium : Assets.free, width: isPremium ? 92.w : 64.w, height: 28.w, sourceType: ImageSourceType.asset, ), ], ), ); } /// UID 条目 Widget _buildUIDItem() { return ClickOpacity( onTap: () { Clipboard.setData(ClipboardData(text: controller.uid)); Get.snackbar(Strings.copied.tr, 'UID ${Strings.copied.tr}'); }, child: Container( height: 56.w, padding: EdgeInsets.symmetric(horizontal: 16.w), child: Row( children: [ // 图标 Container( width: 30.w, height: 30.w, decoration: BoxDecoration( color: Get.reactiveTheme.shadowColor, borderRadius: BorderRadius.circular(8.r), ), child: Icon(IconFont.icon14, size: 20.w, color: Colors.white), ), 10.horizontalSpace, // UID Expanded( child: Text( controller.uid, style: TextStyle( fontSize: 14.sp, color: Get.reactiveTheme.textTheme.bodyLarge!.color, fontWeight: FontWeight.w400, ), ), ), // 复制图标 Icon( IconFont.icon57, size: 20.w, color: Get.reactiveTheme.hintColor, ), ], ), ), ); } Widget _buildPremiumFeatures(bool isPremium) { return Padding( padding: EdgeInsets.symmetric(horizontal: 14.w), child: Column( children: [ _buildFeatureItem(IconFont.icon60, Strings.unlockAllFreeLocations.tr), _buildFeatureItem(IconFont.icon61, Strings.unlockSmartMode.tr), _buildFeatureItem(IconFont.icon62, Strings.unlockMultiHopMode.tr), _buildFeatureItem( IconFont.icon63, Strings.premiumCanShareXDevices.tr, ), _buildFeatureItem( IconFont.icon64, Strings.ownYourOwnPrivateServer.tr, ), _buildFeatureItem(IconFont.icon65, Strings.closeAds.tr), ], ), ); } Widget _buildFeatureItem(IconData icon, String title) { return SizedBox( height: 44.w, child: Row( children: [ Icon(icon, color: DarkThemeColors.subscriptionColor, size: 24.w), 12.horizontalSpace, Expanded( child: Text( title, style: TextStyle( fontSize: 13.sp, color: Get.reactiveTheme.hintColor, ), ), ), Container( width: 20.w, height: 20.w, decoration: BoxDecoration( shape: BoxShape.circle, color: DarkThemeColors.subscriptionSelectColor, ), child: Icon(Icons.check, color: Colors.white, size: 12.w), ), ], ), ); } /// 底部按钮 Widget _buildBottomButtons() { final isLight = ReactiveTheme.isLightTheme; return Column( children: [ if (controller.apiController.isPremium) ...[ if (controller.apiController.isGuest) ...[ SubmitButton( text: Strings.changeSubscription.tr, bgColor: isLight ? Colors.black : Get.reactiveTheme.highlightColor, textColor: DarkThemeColors.subscriptionColor, onPressed: () { controller.toSubscription(); }, ), ] else ...[ _buildSecondaryButton( text: Strings.changeSubscription.tr, icon: IconFont.icon23, onTap: () { controller.toSubscription(); }, ), ], ] else ...[ // Upgrade to Premium 按钮 _buildSecondaryButton( text: Strings.upgradeToPremium.tr, icon: IconFont.icon23, onTap: () { controller.toSubscription(); }, ), ], // 绑定邮箱 按钮 if (controller.apiController.isGuest && controller.apiController.isPremium) ...[ 20.verticalSpaceFromWidth, _buildEmailButton( text: Strings.bindEmailMemberBenefits.tr, icon: IconFont.icon23, onTap: () { // TODO: 绑定邮箱 AllDialog.showBindEmailMemberBenefits(); }, ), 10.verticalSpaceFromWidth, // 提示文字 Text( Strings.bindingAccountEmailProtectsPreRights.tr, textAlign: TextAlign.center, style: TextStyle( fontSize: 12.sp, color: Get.reactiveTheme.hintColor, ), ), ], ], ); } /// 次要按钮(黑色边框) Widget _buildSecondaryButton({ required String text, required IconData icon, required VoidCallback onTap, }) { final isLight = ReactiveTheme.isLightTheme; return ClickOpacity( onTap: onTap, child: Container( height: 52.w, decoration: BoxDecoration( border: isLight ? null : Border.all(color: Get.reactiveTheme.dividerColor, width: 1.w), borderRadius: BorderRadius.circular(12.r), color: isLight ? Colors.black : null, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( text, style: TextStyle( fontSize: 16.sp, color: DarkThemeColors.subscriptionColor, fontWeight: FontWeight.w400, ), ), SizedBox(width: 8.w), Icon(icon, size: 20.w, color: DarkThemeColors.subscriptionColor), ], ), ), ); } /// 次要按钮(黑色边框) Widget _buildEmailButton({ required String text, required IconData icon, required VoidCallback onTap, }) { final isLight = ReactiveTheme.isLightTheme; return ClickOpacity( onTap: onTap, child: Container( height: 52.w, decoration: BoxDecoration( border: isLight ? null : Border.all(color: Get.reactiveTheme.dividerColor, width: 1.w), borderRadius: BorderRadius.circular(12.r), color: isLight ? Get.reactiveTheme.primaryColor : null, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( text, style: TextStyle( fontSize: 16.sp, color: isLight ? Colors.white : DarkThemeColors.subscriptionColor, fontWeight: FontWeight.w400, ), ), SizedBox(width: 8.w), Icon( icon, size: 20.w, color: isLight ? Colors.white : DarkThemeColors.subscriptionColor, ), ], ), ), ); } /// 构建分割线 Widget _buildDivider() { return Divider(height: 1.w, color: Get.reactiveTheme.dividerColor); } /// 构建分组标题 Widget _buildSectionHeader(String title) { return Padding( padding: EdgeInsets.symmetric(vertical: 10.w), child: Text( title, style: TextStyle( fontSize: 16.sp, color: Get.reactiveTheme.hintColor, fontWeight: FontWeight.w500, ), ), ); } /// Account 分组 Widget _buildAccountSection() { return Obx(() { return Container( decoration: BoxDecoration( color: Get.reactiveTheme.highlightColor, borderRadius: BorderRadius.circular(12.r), ), child: Column( children: [ _buildSettingItem( icon: IconFont.icon29, iconColor: Get.reactiveTheme.shadowColor, title: _getUserAccount().isNotEmpty ? _getUserAccount() : Strings.account.tr, trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IXImage( source: controller.apiController.userLevel == 3 ? controller.apiController.remainTimeSeconds > 0 ? Assets.premium : Assets.premiumExpired : controller.apiController.userLevel == 9999 ? Assets.test : Assets.free, width: controller.apiController.userLevel == 3 ? 92.w : 64.w, height: 28.w, sourceType: ImageSourceType.asset, ), ], ), onTap: () { Get.toNamed(Routes.ACCOUNT); }, ), _buildDivider(), _buildSettingItem( icon: IconFont.icon14, iconColor: Get.reactiveTheme.shadowColor, title: 'UID ${DeviceManager.getCacheDeviceId().length > 12 ? '${DeviceManager.getCacheDeviceId().substring(0, 6)}***${DeviceManager.getCacheDeviceId().substring(DeviceManager.getCacheDeviceId().length - 6)}' : DeviceManager.getCacheDeviceId()}', showInfo: true, trailing: ClickOpacity( onTap: () { Clipboard.setData( ClipboardData(text: DeviceManager.getCacheDeviceId()), ); IXSnackBar.showIXSnackBar( title: Strings.copied.tr, message: Strings.copied.tr, ); }, child: Icon( IconFont.icon57, size: 20.w, color: Get.reactiveTheme.hintColor, ), ), onTap: () {}, onInfoTap: () { AllDialog.showUidInfo(); }, ), _buildDivider(), // 根据用户类型显示不同的时间信息 if (controller.apiController.isPremium) ...[ // _buildSettingItem( // icon: IconFont.icon23, // iconColor: Get.reactiveTheme.shadowColor, // title: Strings.myPreCode.tr, // trailing: Row( // mainAxisSize: MainAxisSize.min, // children: [ // Text( // '123***ADZ', // style: TextStyle( // fontSize: 13.sp, // color: Get.reactiveTheme.hintColor, // ), // ), // SizedBox(width: 4.w), // Icon( // IconFont.icon02, // size: 20.w, // color: Get.reactiveTheme.hintColor, // ), // ], // ), // onTap: () { // // TODO: 跳转到Pre Code页面 // Get.toNamed(Routes.PRECODE); // }, // ), // _buildDivider(), _buildSettingItem( icon: IconFont.icon30, iconColor: Get.reactiveTheme.shadowColor, title: Strings.validTerm.tr, trailing: Text( controller.apiController.remainTimeSeconds > 0 ? controller.apiController.validTermText : Strings.expired.tr, style: TextStyle( fontSize: 13.sp, color: Get.reactiveTheme.primaryColor, fontWeight: FontWeight.w500, ), ), onTap: () { // TODO: 跳转到有效期详情页面 }, ), ] else ...[ _buildSettingItem( icon: IconFont.icon30, iconColor: Get.reactiveTheme.shadowColor, title: Strings.freeTime.tr, trailing: Text( '${controller.apiController.remainTimeFormatted} / Days', style: TextStyle( fontSize: 14.sp, color: const Color(0xFFFFCC00), fontWeight: FontWeight.w500, ), ), ), ], // _buildDivider(), // _buildSettingItem( // icon: IconFont.icon31, // iconColor: Get.reactiveTheme.shadowColor, // title: Strings.deviceAuthorization.tr, // trailing: Row( // mainAxisSize: MainAxisSize.min, // children: [ // Text( // isPremium ? '1/4' : '0/1', // style: TextStyle( // fontSize: 13.sp, // color: Get.reactiveTheme.hintColor, // ), // ), // SizedBox(width: 4.w), // Icon( // IconFont.icon02, // size: 20.w, // color: Get.reactiveTheme.hintColor, // ), // ], // ), // onTap: () { // Get.toNamed(Routes.DEVICEAUTH); // }, // ), ], ), ); }); } /// Security 分组 Widget _buildSecuritySection() { return Container( decoration: BoxDecoration( color: Get.reactiveTheme.highlightColor, borderRadius: BorderRadius.circular(12.r), ), child: Column( children: [ _buildSettingItem( icon: IconFont.icon11, iconColor: DarkThemeColors.settingSecurityLinearGradientStartColor, iconGradient: LinearGradient( colors: [ DarkThemeColors.settingSecurityLinearGradientStartColor, DarkThemeColors.settingSecurityLinearGradientEndColor, ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), title: Strings.changePassword.tr, onTap: () { // TODO: 跳转到忘记密码页面 Get.toNamed(Routes.FORGOTPWD); }, ), _buildDivider(), _buildSettingItem( icon: IconFont.icon40, iconColor: DarkThemeColors.settingSecurityLinearGradientStartColor, iconGradient: LinearGradient( colors: [ DarkThemeColors.settingSecurityLinearGradientStartColor, DarkThemeColors.settingSecurityLinearGradientEndColor, ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), title: Strings.deleteAccount.tr, onTap: () { AllDialog.showDeleteAccountConfirm(() { // 退出登录 controller.handleDeleteAccount(); }); }, ), _buildDivider(), _buildSettingItem( icon: IconFont.icon66, iconColor: DarkThemeColors.settingSecurityLinearGradientStartColor, iconGradient: LinearGradient( colors: [ DarkThemeColors.settingSecurityLinearGradientStartColor, DarkThemeColors.settingSecurityLinearGradientEndColor, ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), title: Strings.logout.tr, titleColor: DarkThemeColors.errorColor, onTap: () { AllDialog.showLogoutConfirm(() { // 退出登录 controller.handleLogout(); }); }, ), ], ), ); } /// 构建设置项 Widget _buildSettingItem({ IconData? icon, String? svgPath, required Color iconColor, Gradient? iconGradient, required String title, Color? titleColor, bool showInfo = false, Widget? trailing, VoidCallback? onTap, VoidCallback? onInfoTap, }) { // 确保至少提供了 icon 或 svgPath 之一 assert( icon != null || svgPath != null, 'Must provide either icon or svgPath', ); return ClickOpacity( onTap: onTap, child: Container( height: 56.w, padding: EdgeInsets.symmetric(horizontal: 14.w), child: Row( children: [ // 图标 Container( width: 30.w, height: 30.w, decoration: BoxDecoration( gradient: iconGradient, color: iconGradient == null ? iconColor : null, borderRadius: BorderRadius.circular(8.r), ), child: svgPath != null ? Padding( padding: EdgeInsets.all(5.w), child: SvgPicture.asset( svgPath, width: 20.w, height: 20.w, colorFilter: const ColorFilter.mode( Colors.white, BlendMode.srcIn, ), ), ) : Icon(icon!, size: 20.w, color: Colors.white), ), 10.horizontalSpace, // 标题 Expanded( child: Row( children: [ Text( title, style: TextStyle( fontSize: 14.sp, color: titleColor ?? Get.reactiveTheme.textTheme.bodyLarge!.color, fontWeight: FontWeight.w500, ), ), 4.horizontalSpace, if (showInfo) ClickOpacity( onTap: onInfoTap, child: Icon( IconFont.icon59, size: 20.w, color: Get.reactiveTheme.hintColor, ), ), ], ), ), // 右侧内容 if (trailing != null) trailing, ], ), ), ); } /// 获取用户账号显示文本 String _getUserAccount() { final user = IXSP.getUser(); if (user == null) return ''; if (user.memberLevel == MemberLevel.normal.level) { return user.account?.username ?? ''; } return ''; } }