| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- import 'dart:io';
- import 'package:flutter/cupertino.dart';
- 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/constants/assets.dart';
- import 'package:nomo/app/dialog/all_dialog.dart';
- import 'package:nomo/app/widgets/click_opacity.dart';
- import 'package:nomo/app/widgets/ix_image.dart';
- import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
- import 'package:nomo/utils/device_manager.dart';
- import 'package:nomo/utils/misc.dart';
- import '../../../constants/enums.dart';
- import '../../../data/sp/ix_sp.dart';
- import '../../../../config/theme/dark_theme_colors.dart';
- import '../../../../config/translations/localization_service.dart';
- import '../../../../config/translations/strings_enum.dart';
- import '../../../../utils/system_helper.dart';
- import '../../../components/ix_snackbar.dart';
- import '../../../constants/iconfont/iconfont.dart';
- import '../../../routes/app_pages.dart';
- import '../../../widgets/ix_app_bar.dart';
- import '../controllers/setting_controller.dart';
- class SettingView extends BaseView<SettingController> {
- const SettingView({super.key});
- @override
- PreferredSizeWidget? get appBar => IXAppBar(title: Strings.settings.tr);
- @override
- Widget buildContent(BuildContext context) {
- return CustomScrollView(
- slivers: [
- // Account Section
- _buildSectionHeader(Strings.account.tr),
- _buildLoginSection(),
- _buildAccountSection(),
- // Network Section
- _buildSectionHeader(Strings.networkSection.tr),
- _buildNetworkSection(),
- // APP Section
- _buildSectionHeader('APP'),
- _buildAppSection(),
- // Security Section
- // _buildSectionHeader(Strings.securitySection.tr),
- // _buildSecuritySection(),
- // 底部间距
- SliverSafeArea(
- sliver: SliverToBoxAdapter(
- child: isDesktop ? 14.verticalSpace : 0.verticalSpace,
- ),
- ),
- ],
- );
- }
- /// 构建分组标题
- Widget _buildSectionHeader(String title) {
- return SliverToBoxAdapter(
- child: Padding(
- padding: EdgeInsets.fromLTRB(14.w, 10.w, 14.w, 10.w),
- child: Text(
- title,
- style: TextStyle(
- fontSize: 16.sp,
- color: Get.reactiveTheme.hintColor,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- );
- }
- /// 构建登录分组
- Widget _buildLoginSection() {
- return SliverToBoxAdapter(
- child: Obx(() {
- if (!controller.apiController.isGuest) {
- return SizedBox.shrink();
- }
- return Container(
- margin: EdgeInsets.only(left: 14.w, right: 14.w, bottom: 10.w),
- decoration: BoxDecoration(
- color: Get.reactiveTheme.highlightColor,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: _buildSettingItem(
- icon: IconFont.icon37,
- iconColor: Get.reactiveTheme.shadowColor,
- title: Strings.login.tr,
- trailing: Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- onTap: () {
- Get.toNamed(Routes.LOGIN);
- },
- ),
- );
- }),
- );
- }
- /// Account 分组
- Widget _buildAccountSection() {
- return SliverToBoxAdapter(
- child: Obx(() {
- return Container(
- margin: EdgeInsets.symmetric(horizontal: 14.w),
- 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(
- 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,
- ),
- 4.horizontalSpace,
- Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- ],
- ),
- 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,
- disableFeedback: 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,
- ),
- ),
- 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(
- disableFeedback: true,
- 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: controller.apiController.remainTimeSeconds > 0
- ? Get.reactiveTheme.primaryColor
- : Colors.red,
- 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);
- // },
- // ),
- ],
- ),
- );
- }),
- );
- }
- /// Network 分组
- Widget _buildNetworkSection() {
- return SliverToBoxAdapter(
- child: Container(
- margin: EdgeInsets.symmetric(horizontal: 14.w),
- decoration: BoxDecoration(
- color: Get.reactiveTheme.highlightColor,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: Column(
- children: [
- _buildSettingItem(
- icon: IconFont.icon34,
- iconColor: Get.reactiveTheme.primaryColor,
- title: Strings.routingMode.tr,
- trailing: Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- onTap: () {
- // TODO: 跳转到路由模式页面
- Get.toNamed(Routes.ROUTINGMODE);
- },
- ),
- _buildDivider(),
- if (Platform.isAndroid) ...[
- _buildSettingItem(
- icon: IconFont.icon32,
- iconColor: Get.reactiveTheme.primaryColor,
- title: Strings.splitTunneling.tr,
- trailing: Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- onTap: () {
- // TODO: 跳转到分流隧道页面
- Get.toNamed(Routes.SPLITTUNNELING);
- },
- ),
- _buildDivider(),
- ],
- // _buildSettingItem(
- // icon: IconFont.icon33,
- // iconColor: Get.reactiveTheme.primaryColor,
- // title: Strings.autoReconnect.tr,
- // trailing: Obx(
- // () => CupertinoSwitch(
- // value: controller.autoReconnect,
- // onChanged: (value) {
- // controller.autoReconnect = value;
- // },
- // activeTrackColor: Get.reactiveTheme.shadowColor,
- // thumbColor: Colors.white,
- // inactiveThumbColor: Colors.white,
- // inactiveTrackColor: Colors.grey,
- // ),
- // ),
- // ),
- // _buildSettingItem(
- // icon: IconFont.icon35,
- // iconColor: Get.reactiveTheme.primaryColor,
- // title: Strings.restoreDefault.tr,
- // trailing: Icon(
- // IconFont.icon02,
- // size: 20.w,
- // color: Get.reactiveTheme.hintColor,
- // ),
- // onTap: () {
- // // TODO: 恢复默认设置
- // },
- // ),
- ],
- ),
- ),
- );
- }
- /// APP 分组
- Widget _buildAppSection() {
- return SliverToBoxAdapter(
- child: Container(
- margin: EdgeInsets.symmetric(horizontal: 14.w),
- decoration: BoxDecoration(
- color: Get.reactiveTheme.highlightColor,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: Column(
- children: [
- _buildSettingItem(
- icon: IconFont.icon36,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.language.tr,
- trailing: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- LocalizationService.getGlobalLanguageTitle(),
- style: TextStyle(
- fontSize: 13.sp,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- 8.horizontalSpace,
- Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- ],
- ),
- onTap: () {
- // TODO: 跳转到语言选择页面
- Get.toNamed(Routes.LANGUAGE);
- },
- ),
- _buildDivider(),
- _buildSettingItem(
- svgPath: Assets.settingsTheme,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.theme.tr,
- trailing: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Obx(
- () => Text(
- controller.themeMode,
- style: TextStyle(
- fontSize: 13.sp,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- ),
- 8.horizontalSpace,
- Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- ],
- ),
- onTap: () {
- Get.toNamed(
- Routes.THEME,
- )?.then((_) => controller.initThemeMode());
- },
- ),
- _buildDivider(),
- _buildSettingItem(
- icon: IconFont.icon37,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.feedback.tr,
- trailing: Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- onTap: () {
- // TODO: 跳转到反馈页面
- Get.toNamed(Routes.FEEDBACK);
- },
- ),
- _buildDivider(),
- _buildSettingItem(
- icon: IconFont.icon38,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.privacyPolicy.tr,
- trailing: Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- onTap: () {
- // TODO: 跳转到隐私政策页面
- SystemHelper.openPrivacyTerms();
- },
- ),
- _buildDivider(),
- _buildSettingItem(
- icon: IconFont.icon38,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.termsOfService.tr,
- trailing: Icon(
- IconFont.icon02,
- size: 20.w,
- color: Get.reactiveTheme.hintColor,
- ),
- onTap: () {
- // TODO: 跳转到服务条款页面
- SystemHelper.openTermsOfService();
- },
- ),
- // 桌面版本不显示通知
- if (!isDesktop) ...[
- _buildDivider(),
- _buildSettingItem(
- svgPath: Assets.pushNotifications,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.pushNotifications.tr,
- trailing: Obx(
- () => CupertinoSwitch(
- value: controller.pushNotifications,
- onChanged: (value) {
- controller.showNotificationConfigPage();
- },
- activeTrackColor: Get.reactiveTheme.shadowColor,
- thumbColor: Colors.white,
- inactiveThumbColor: Colors.white,
- inactiveTrackColor: Colors.grey,
- ),
- ),
- onTap: () {
- controller.showNotificationConfigPage();
- },
- ),
- ],
- _buildDivider(),
- _buildSettingItem(
- icon: IconFont.icon39,
- iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
- iconGradient: LinearGradient(
- colors: [
- DarkThemeColors.settingAppLinearGradientStartColor,
- DarkThemeColors.settingAppLinearGradientEndColor,
- ],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- title: Strings.version.tr,
- trailing: Obx(
- () => Row(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- 'v${controller.version}',
- style: TextStyle(
- fontSize: 13.sp,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- if (controller.hasUpdate)
- Container(
- width: 4.w,
- height: 4.w,
- decoration: BoxDecoration(
- color: Colors.red,
- borderRadius: BorderRadius.circular(2.r),
- ),
- ),
- ],
- ),
- ),
- onTap: () {
- controller.apiController.checkUpdate(isClickCheck: true);
- },
- ),
- ],
- ),
- ),
- );
- }
- /// Security 分组
- Widget _buildSecuritySection() {
- return SliverToBoxAdapter(
- child: Container(
- margin: EdgeInsets.symmetric(horizontal: 14.w),
- 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,
- bool disableFeedback = false,
- }) {
- // 确保至少提供了 icon 或 svgPath 之一
- assert(
- icon != null || svgPath != null,
- 'Must provide either icon or svgPath',
- );
- return ClickOpacity(
- onTap: onTap,
- disableFeedback: disableFeedback,
- 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,
- ],
- ),
- ),
- );
- }
- /// 构建分割线
- Widget _buildDivider() {
- return Padding(
- padding: EdgeInsets.only(left: 60.w),
- child: Divider(
- height: 1,
- color: Get.reactiveTheme.dividerColor.withOpacity(0.3),
- ),
- );
- }
- /// 获取用户账号显示文本
- String _getUserAccount() {
- final user = IXSP.getUser();
- if (user == null) return '';
- if (user.memberLevel == MemberLevel.normal.level) {
- return user.account?.username ?? '';
- }
- return '';
- }
- }
|