setting_view.dart 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. import 'dart:io';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/services.dart';
  4. import 'package:flutter_screenutil/flutter_screenutil.dart';
  5. import 'package:flutter_svg/flutter_svg.dart';
  6. import 'package:get/get.dart';
  7. import 'package:flashlink/app/base/base_view.dart';
  8. import 'package:flashlink/app/constants/assets.dart';
  9. import 'package:flashlink/app/dialog/all_dialog.dart';
  10. import 'package:flashlink/app/widgets/click_opacity.dart';
  11. import 'package:flashlink/app/widgets/ix_image.dart';
  12. import 'package:flashlink/config/theme/theme_extensions/theme_extension.dart';
  13. import 'package:flashlink/utils/device_manager.dart';
  14. import 'package:flashlink/utils/misc.dart';
  15. import '../../../../utils/formater.dart';
  16. import '../../../constants/enums.dart';
  17. import '../../../data/sp/ix_sp.dart';
  18. import '../../../../config/theme/dark_theme_colors.dart';
  19. // import '../../../../config/translations/localization_service.dart';
  20. import '../../../../config/translations/strings_enum.dart';
  21. import '../../../../utils/system_helper.dart';
  22. import '../../../components/ix_snackbar.dart';
  23. import '../../../constants/iconfont/iconfont.dart';
  24. import '../../../routes/app_pages.dart';
  25. import '../../../widgets/ix_app_bar.dart';
  26. import '../controllers/setting_controller.dart';
  27. class SettingView extends BaseView<SettingController> {
  28. const SettingView({super.key});
  29. @override
  30. PreferredSizeWidget? get appBar => IXAppBar(title: Strings.settings.tr);
  31. @override
  32. Widget buildContent(BuildContext context) {
  33. return CustomScrollView(
  34. slivers: [
  35. // Account Section
  36. _buildSectionHeader(Strings.account.tr),
  37. _buildLoginSection(),
  38. _buildAccountSection(),
  39. // Network Section
  40. _buildSectionHeader(Strings.networkSection.tr),
  41. _buildNetworkSection(),
  42. // APP Section
  43. _buildSectionHeader('APP'),
  44. _buildAppSection(),
  45. // Security Section
  46. // _buildSectionHeader(Strings.securitySection.tr),
  47. // _buildSecuritySection(),
  48. // 底部间距
  49. SliverSafeArea(
  50. sliver: SliverToBoxAdapter(
  51. child: isDesktop ? 14.verticalSpace : 0.verticalSpace,
  52. ),
  53. ),
  54. ],
  55. );
  56. }
  57. /// 构建分组标题
  58. Widget _buildSectionHeader(String title) {
  59. return SliverToBoxAdapter(
  60. child: Padding(
  61. padding: EdgeInsets.fromLTRB(14.w, 10.w, 14.w, 10.w),
  62. child: Text(
  63. title,
  64. style: TextStyle(
  65. fontSize: isDesktop ? 14.sp : 16.sp,
  66. color: Get.reactiveTheme.hintColor,
  67. fontWeight: FontWeight.w500,
  68. ),
  69. ),
  70. ),
  71. );
  72. }
  73. /// 构建登录分组
  74. Widget _buildLoginSection() {
  75. return const SliverToBoxAdapter(child: SizedBox.shrink());
  76. // ignore: dead_code
  77. return SliverToBoxAdapter(
  78. child: Obx(() {
  79. if (!controller.apiController.isGuest) {
  80. return SizedBox.shrink();
  81. }
  82. return Container(
  83. margin: EdgeInsets.only(left: 14.w, right: 14.w, bottom: 10.w),
  84. decoration: BoxDecoration(
  85. color: Get.reactiveTheme.highlightColor,
  86. borderRadius: BorderRadius.circular(12.r),
  87. ),
  88. child: _buildSettingItem(
  89. icon: IconFont.icon37,
  90. iconColor: Get.reactiveTheme.shadowColor,
  91. title: Strings.login.tr,
  92. trailing: Icon(
  93. IconFont.icon02,
  94. size: 20.w,
  95. color: Get.reactiveTheme.hintColor,
  96. ),
  97. onTap: () {
  98. Get.toNamed(Routes.LOGIN);
  99. },
  100. ),
  101. );
  102. }),
  103. );
  104. }
  105. /// Account 分组
  106. Widget _buildAccountSection() {
  107. return SliverToBoxAdapter(
  108. child: Obx(() {
  109. return Container(
  110. margin: EdgeInsets.symmetric(horizontal: 14.w),
  111. decoration: BoxDecoration(
  112. color: Get.reactiveTheme.highlightColor,
  113. borderRadius: BorderRadius.circular(12.r),
  114. ),
  115. child: Column(
  116. children: [
  117. if (!controller.apiController.isGuest ||
  118. controller.apiController.isPremium)
  119. _buildSettingItem(
  120. icon: IconFont.icon29,
  121. iconColor: Get.reactiveTheme.shadowColor,
  122. title: _getUserAccount().isNotEmpty
  123. ? _getUserAccount()
  124. : Strings.currentUser.tr,
  125. trailing: Row(
  126. children: [
  127. IXImage(
  128. source: controller.apiController.userLevel == 3
  129. ? controller.apiController.remainTimeSeconds > 0
  130. ? Assets.premium
  131. : Assets.premiumExpired
  132. : controller.apiController.userLevel == 9999
  133. ? Assets.test
  134. : Assets.free,
  135. width: controller.apiController.userLevel == 3
  136. ? 92.w
  137. : 92.w,
  138. height: 28.w,
  139. sourceType: ImageSourceType.asset,
  140. ),
  141. 4.horizontalSpace,
  142. Icon(
  143. IconFont.icon02,
  144. size: 20.w,
  145. color: Get.reactiveTheme.hintColor,
  146. ),
  147. ],
  148. ),
  149. onTap: () {
  150. Get.toNamed(Routes.ACCOUNT);
  151. },
  152. ),
  153. _buildDivider(),
  154. _buildSettingItem(
  155. icon: IconFont.icon14,
  156. iconColor: Get.reactiveTheme.shadowColor,
  157. title:
  158. 'UID ${formatDeviceId(DeviceManager.getCacheDeviceId())}',
  159. showInfo: true,
  160. disableFeedback: true,
  161. trailing: ClickOpacity(
  162. onTap: () {
  163. Clipboard.setData(
  164. ClipboardData(text: DeviceManager.getCacheDeviceId()),
  165. );
  166. IXSnackBar.showIXSnackBar(
  167. title: Strings.copied.tr,
  168. message: Strings.copied.tr,
  169. );
  170. },
  171. child: Icon(
  172. IconFont.icon57,
  173. size: 20.w,
  174. color: Get.reactiveTheme.hintColor,
  175. ),
  176. ),
  177. onInfoTap: () {
  178. AllDialog.showUidInfo();
  179. },
  180. ),
  181. _buildDivider(),
  182. // 根据用户类型显示不同的时间信息
  183. if (controller.apiController.isPremium) ...[
  184. // _buildSettingItem(
  185. // icon: IconFont.icon23,
  186. // iconColor: Get.reactiveTheme.shadowColor,
  187. // title: Strings.myPreCode.tr,
  188. // trailing: Row(
  189. // mainAxisSize: MainAxisSize.min,
  190. // children: [
  191. // Text(
  192. // '123***ADZ',
  193. // style: TextStyle(
  194. // fontSize: 13.sp,
  195. // color: Get.reactiveTheme.hintColor,
  196. // ),
  197. // ),
  198. // SizedBox(width: 4.w),
  199. // Icon(
  200. // IconFont.icon02,
  201. // size: 20.w,
  202. // color: Get.reactiveTheme.hintColor,
  203. // ),
  204. // ],
  205. // ),
  206. // onTap: () {
  207. // // TODO: 跳转到Pre Code页面
  208. // Get.toNamed(Routes.PRECODE);
  209. // },
  210. // ),
  211. // _buildDivider(),
  212. _buildSettingItem(
  213. disableFeedback: true,
  214. icon: IconFont.icon30,
  215. iconColor: Get.reactiveTheme.shadowColor,
  216. title: Strings.validTerm.tr,
  217. trailing: Text(
  218. controller.apiController.remainTimeSeconds > 0
  219. ? controller.apiController.validTermText
  220. : Strings.expired.tr,
  221. style: TextStyle(
  222. fontSize: 13.sp,
  223. color: controller.apiController.remainTimeSeconds > 0
  224. ? Get.reactiveTheme.primaryColor
  225. : Colors.red,
  226. fontWeight: FontWeight.w500,
  227. ),
  228. ),
  229. onTap: () {
  230. // TODO: 跳转到有效期详情页面
  231. },
  232. ),
  233. ] else ...[
  234. // _buildSettingItem(
  235. // icon: IconFont.icon30,
  236. // iconColor: Get.reactiveTheme.shadowColor,
  237. // title: Strings.freeTime.tr,
  238. // trailing: Text(
  239. // controller.apiController.remainTimeFormatted,
  240. // style: TextStyle(
  241. // fontSize: 14.sp,
  242. // color: controller.apiController.remainTimeSeconds > 0
  243. // ? Get.reactiveTheme.primaryColor
  244. // : Colors.red,
  245. // fontWeight: FontWeight.w500,
  246. // ),
  247. // ),
  248. // ),
  249. ],
  250. // _buildDivider(),
  251. // _buildSettingItem(
  252. // icon: IconFont.icon31,
  253. // iconColor: Get.reactiveTheme.shadowColor,
  254. // title: Strings.deviceAuthorization.tr,
  255. // trailing: Row(
  256. // mainAxisSize: MainAxisSize.min,
  257. // children: [
  258. // Text(
  259. // isPremium ? '1/4' : '0/1',
  260. // style: TextStyle(
  261. // fontSize: 13.sp,
  262. // color: Get.reactiveTheme.hintColor,
  263. // ),
  264. // ),
  265. // SizedBox(width: 4.w),
  266. // Icon(
  267. // IconFont.icon02,
  268. // size: 20.w,
  269. // color: Get.reactiveTheme.hintColor,
  270. // ),
  271. // ],
  272. // ),
  273. // onTap: () {
  274. // Get.toNamed(Routes.DEVICEAUTH);
  275. // },
  276. // ),
  277. ],
  278. ),
  279. );
  280. }),
  281. );
  282. }
  283. /// Network 分组
  284. Widget _buildNetworkSection() {
  285. return SliverToBoxAdapter(
  286. child: Container(
  287. margin: EdgeInsets.symmetric(horizontal: 14.w),
  288. decoration: BoxDecoration(
  289. color: Get.reactiveTheme.highlightColor,
  290. borderRadius: BorderRadius.circular(12.r),
  291. ),
  292. child: Column(
  293. children: [
  294. _buildSettingItem(
  295. icon: IconFont.icon34,
  296. iconColor: Get.reactiveTheme.primaryColor,
  297. title: Strings.routingMode.tr,
  298. trailing: Icon(
  299. IconFont.icon02,
  300. size: 20.w,
  301. color: Get.reactiveTheme.hintColor,
  302. ),
  303. onTap: () {
  304. // TODO: 跳转到路由模式页面
  305. Get.toNamed(Routes.ROUTINGMODE);
  306. },
  307. ),
  308. _buildDivider(),
  309. if (Platform.isAndroid) ...[
  310. _buildSettingItem(
  311. icon: IconFont.icon32,
  312. iconColor: Get.reactiveTheme.primaryColor,
  313. title: Strings.splitTunneling.tr,
  314. trailing: Icon(
  315. IconFont.icon02,
  316. size: 20.w,
  317. color: Get.reactiveTheme.hintColor,
  318. ),
  319. onTap: () {
  320. // TODO: 跳转到分流隧道页面
  321. Get.toNamed(Routes.SPLITTUNNELING);
  322. },
  323. ),
  324. _buildDivider(),
  325. ],
  326. // _buildSettingItem(
  327. // icon: IconFont.icon33,
  328. // iconColor: Get.reactiveTheme.primaryColor,
  329. // title: Strings.autoReconnect.tr,
  330. // trailing: Obx(
  331. // () => CupertinoSwitch(
  332. // value: controller.autoReconnect,
  333. // onChanged: (value) {
  334. // controller.autoReconnect = value;
  335. // },
  336. // activeTrackColor: Get.reactiveTheme.shadowColor,
  337. // thumbColor: Colors.white,
  338. // inactiveThumbColor: Colors.white,
  339. // inactiveTrackColor: Colors.grey,
  340. // ),
  341. // ),
  342. // ),
  343. // _buildSettingItem(
  344. // icon: IconFont.icon35,
  345. // iconColor: Get.reactiveTheme.primaryColor,
  346. // title: Strings.restoreDefault.tr,
  347. // trailing: Icon(
  348. // IconFont.icon02,
  349. // size: 20.w,
  350. // color: Get.reactiveTheme.hintColor,
  351. // ),
  352. // onTap: () {
  353. // // TODO: 恢复默认设置
  354. // },
  355. // ),
  356. ],
  357. ),
  358. ),
  359. );
  360. }
  361. /// APP 分组
  362. Widget _buildAppSection() {
  363. return SliverToBoxAdapter(
  364. child: Container(
  365. margin: EdgeInsets.symmetric(horizontal: 14.w),
  366. decoration: BoxDecoration(
  367. color: Get.reactiveTheme.highlightColor,
  368. borderRadius: BorderRadius.circular(12.r),
  369. ),
  370. child: Column(
  371. children: [
  372. // _buildSettingItem(
  373. // icon: IconFont.icon36,
  374. // iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  375. // iconGradient: LinearGradient(
  376. // colors: [
  377. // DarkThemeColors.settingAppLinearGradientStartColor,
  378. // DarkThemeColors.settingAppLinearGradientEndColor,
  379. // ],
  380. // begin: Alignment.topCenter,
  381. // end: Alignment.bottomCenter,
  382. // ),
  383. // title: Strings.language.tr,
  384. // trailing: Row(
  385. // mainAxisSize: MainAxisSize.min,
  386. // children: [
  387. // Text(
  388. // LocalizationService.getGlobalLanguageTitle(),
  389. // style: TextStyle(
  390. // fontSize: 13.sp,
  391. // color: Get.reactiveTheme.hintColor,
  392. // ),
  393. // ),
  394. // 8.horizontalSpace,
  395. // Icon(
  396. // IconFont.icon02,
  397. // size: 20.w,
  398. // color: Get.reactiveTheme.hintColor,
  399. // ),
  400. // ],
  401. // ),
  402. // onTap: () {
  403. // Get.toNamed(Routes.LANGUAGE);
  404. // },
  405. // ),
  406. // _buildDivider(),
  407. _buildSettingItem(
  408. svgPath: Assets.settingsTheme,
  409. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  410. iconGradient: LinearGradient(
  411. colors: [
  412. DarkThemeColors.settingAppLinearGradientStartColor,
  413. DarkThemeColors.settingAppLinearGradientEndColor,
  414. ],
  415. begin: Alignment.topCenter,
  416. end: Alignment.bottomCenter,
  417. ),
  418. title: Strings.theme.tr,
  419. trailing: Row(
  420. mainAxisSize: MainAxisSize.min,
  421. children: [
  422. Obx(
  423. () => Text(
  424. controller.themeMode,
  425. style: TextStyle(
  426. fontSize: 13.sp,
  427. color: Get.reactiveTheme.hintColor,
  428. ),
  429. ),
  430. ),
  431. 8.horizontalSpace,
  432. Icon(
  433. IconFont.icon02,
  434. size: 20.w,
  435. color: Get.reactiveTheme.hintColor,
  436. ),
  437. ],
  438. ),
  439. onTap: () {
  440. Get.toNamed(
  441. Routes.THEME,
  442. )?.then((_) => controller.initThemeMode());
  443. },
  444. ),
  445. _buildDivider(),
  446. // _buildSettingItem(
  447. // icon: IconFont.icon37,
  448. // iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  449. // iconGradient: LinearGradient(
  450. // colors: [
  451. // DarkThemeColors.settingAppLinearGradientStartColor,
  452. // DarkThemeColors.settingAppLinearGradientEndColor,
  453. // ],
  454. // begin: Alignment.topCenter,
  455. // end: Alignment.bottomCenter,
  456. // ),
  457. // title: Strings.feedback.tr,
  458. // trailing: Icon(
  459. // IconFont.icon02,
  460. // size: 20.w,
  461. // color: Get.reactiveTheme.hintColor,
  462. // ),
  463. // onTap: () {
  464. // Get.toNamed(Routes.FEEDBACK);
  465. // },
  466. // ),
  467. // _buildDivider(),
  468. _buildSettingItem(
  469. icon: IconFont.icon38,
  470. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  471. iconGradient: LinearGradient(
  472. colors: [
  473. DarkThemeColors.settingAppLinearGradientStartColor,
  474. DarkThemeColors.settingAppLinearGradientEndColor,
  475. ],
  476. begin: Alignment.topCenter,
  477. end: Alignment.bottomCenter,
  478. ),
  479. title: Strings.privacyPolicy.tr,
  480. trailing: Icon(
  481. IconFont.icon02,
  482. size: 20.w,
  483. color: Get.reactiveTheme.hintColor,
  484. ),
  485. onTap: () {
  486. // TODO: 跳转到隐私政策页面
  487. SystemHelper.openPrivacyTerms();
  488. },
  489. ),
  490. _buildDivider(),
  491. _buildSettingItem(
  492. icon: IconFont.icon38,
  493. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  494. iconGradient: LinearGradient(
  495. colors: [
  496. DarkThemeColors.settingAppLinearGradientStartColor,
  497. DarkThemeColors.settingAppLinearGradientEndColor,
  498. ],
  499. begin: Alignment.topCenter,
  500. end: Alignment.bottomCenter,
  501. ),
  502. title: Strings.termsOfService.tr,
  503. trailing: Icon(
  504. IconFont.icon02,
  505. size: 20.w,
  506. color: Get.reactiveTheme.hintColor,
  507. ),
  508. onTap: () {
  509. // TODO: 跳转到服务条款页面
  510. SystemHelper.openTermsOfService();
  511. },
  512. ),
  513. // 桌面版本不显示通知
  514. // if (!isDesktop) ...[
  515. // _buildDivider(),
  516. // _buildSettingItem(
  517. // svgPath: Assets.pushNotifications,
  518. // iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  519. // iconGradient: LinearGradient(
  520. // colors: [
  521. // DarkThemeColors.settingAppLinearGradientStartColor,
  522. // DarkThemeColors.settingAppLinearGradientEndColor,
  523. // ],
  524. // begin: Alignment.topCenter,
  525. // end: Alignment.bottomCenter,
  526. // ),
  527. // title: Strings.pushNotifications.tr,
  528. // trailing: Obx(
  529. // () => CupertinoSwitch(
  530. // value: controller.pushNotifications,
  531. // onChanged: (value) {
  532. // controller.showNotificationConfigPage();
  533. // },
  534. // activeTrackColor: Get.reactiveTheme.shadowColor,
  535. // thumbColor: Colors.white,
  536. // inactiveThumbColor: Colors.white,
  537. // inactiveTrackColor: Colors.grey,
  538. // ),
  539. // ),
  540. // onTap: () {
  541. // controller.showNotificationConfigPage();
  542. // },
  543. // ),
  544. // ],
  545. _buildDivider(),
  546. _buildSettingItem(
  547. icon: IconFont.icon39,
  548. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  549. iconGradient: LinearGradient(
  550. colors: [
  551. DarkThemeColors.settingAppLinearGradientStartColor,
  552. DarkThemeColors.settingAppLinearGradientEndColor,
  553. ],
  554. begin: Alignment.topCenter,
  555. end: Alignment.bottomCenter,
  556. ),
  557. title: Strings.version.tr,
  558. trailing: Obx(
  559. () => Row(
  560. mainAxisAlignment: MainAxisAlignment.center,
  561. crossAxisAlignment: CrossAxisAlignment.start,
  562. children: [
  563. Text(
  564. 'v${controller.version}',
  565. style: TextStyle(
  566. fontSize: 13.sp,
  567. color: Get.reactiveTheme.hintColor,
  568. ),
  569. ),
  570. if (controller.hasUpdate)
  571. Container(
  572. width: 4.w,
  573. height: 4.w,
  574. decoration: BoxDecoration(
  575. color: Colors.red,
  576. borderRadius: BorderRadius.circular(2.r),
  577. ),
  578. ),
  579. ],
  580. ),
  581. ),
  582. onTap: () {
  583. controller.apiController.checkUpdate(isClickCheck: true);
  584. },
  585. ),
  586. ],
  587. ),
  588. ),
  589. );
  590. }
  591. /// Security 分组
  592. Widget _buildSecuritySection() {
  593. return SliverToBoxAdapter(
  594. child: Container(
  595. margin: EdgeInsets.symmetric(horizontal: 14.w),
  596. decoration: BoxDecoration(
  597. color: Get.reactiveTheme.highlightColor,
  598. borderRadius: BorderRadius.circular(12.r),
  599. ),
  600. child: Column(
  601. children: [
  602. _buildSettingItem(
  603. icon: IconFont.icon11,
  604. iconColor:
  605. DarkThemeColors.settingSecurityLinearGradientStartColor,
  606. iconGradient: LinearGradient(
  607. colors: [
  608. DarkThemeColors.settingSecurityLinearGradientStartColor,
  609. DarkThemeColors.settingSecurityLinearGradientEndColor,
  610. ],
  611. begin: Alignment.topCenter,
  612. end: Alignment.bottomCenter,
  613. ),
  614. title: Strings.changePassword.tr,
  615. onTap: () {
  616. // TODO: 跳转到忘记密码页面
  617. Get.toNamed(Routes.FORGOTPWD);
  618. },
  619. ),
  620. _buildDivider(),
  621. _buildSettingItem(
  622. icon: IconFont.icon40,
  623. iconColor:
  624. DarkThemeColors.settingSecurityLinearGradientStartColor,
  625. iconGradient: LinearGradient(
  626. colors: [
  627. DarkThemeColors.settingSecurityLinearGradientStartColor,
  628. DarkThemeColors.settingSecurityLinearGradientEndColor,
  629. ],
  630. begin: Alignment.topCenter,
  631. end: Alignment.bottomCenter,
  632. ),
  633. title: Strings.deleteAccount.tr,
  634. onTap: () {
  635. AllDialog.showDeleteAccountConfirm(() {
  636. // 退出登录
  637. controller.handleDeleteAccount();
  638. });
  639. },
  640. ),
  641. _buildDivider(),
  642. _buildSettingItem(
  643. icon: IconFont.icon66,
  644. iconColor:
  645. DarkThemeColors.settingSecurityLinearGradientStartColor,
  646. iconGradient: LinearGradient(
  647. colors: [
  648. DarkThemeColors.settingSecurityLinearGradientStartColor,
  649. DarkThemeColors.settingSecurityLinearGradientEndColor,
  650. ],
  651. begin: Alignment.topCenter,
  652. end: Alignment.bottomCenter,
  653. ),
  654. title: Strings.logout.tr,
  655. titleColor: DarkThemeColors.errorColor,
  656. onTap: () {
  657. AllDialog.showLogoutConfirm(() {
  658. // 退出登录
  659. controller.handleLogout();
  660. });
  661. },
  662. ),
  663. ],
  664. ),
  665. ),
  666. );
  667. }
  668. /// 构建设置项
  669. Widget _buildSettingItem({
  670. IconData? icon,
  671. String? svgPath,
  672. required Color iconColor,
  673. Gradient? iconGradient,
  674. required String title,
  675. Color? titleColor,
  676. bool showInfo = false,
  677. Widget? trailing,
  678. VoidCallback? onTap,
  679. VoidCallback? onInfoTap,
  680. bool disableFeedback = false,
  681. }) {
  682. // 确保至少提供了 icon 或 svgPath 之一
  683. assert(
  684. icon != null || svgPath != null,
  685. 'Must provide either icon or svgPath',
  686. );
  687. return ClickOpacity(
  688. onTap: onTap,
  689. disableFeedback: disableFeedback,
  690. child: Container(
  691. height: 56.w,
  692. padding: EdgeInsets.symmetric(horizontal: 14.w),
  693. child: Row(
  694. children: [
  695. // 图标
  696. Container(
  697. width: 30.w,
  698. height: 30.w,
  699. decoration: BoxDecoration(
  700. gradient: iconGradient,
  701. color: iconGradient == null ? iconColor : null,
  702. borderRadius: BorderRadius.circular(8.r),
  703. ),
  704. child: svgPath != null
  705. ? Padding(
  706. padding: EdgeInsets.all(5.w),
  707. child: SvgPicture.asset(
  708. svgPath,
  709. width: 20.w,
  710. height: 20.w,
  711. colorFilter: const ColorFilter.mode(
  712. Colors.white,
  713. BlendMode.srcIn,
  714. ),
  715. ),
  716. )
  717. : Icon(icon!, size: 20.w, color: Colors.white),
  718. ),
  719. 10.horizontalSpace,
  720. // 标题
  721. Expanded(
  722. child: Row(
  723. children: [
  724. Text(
  725. title,
  726. style: TextStyle(
  727. fontSize: 14.sp,
  728. color:
  729. titleColor ??
  730. Get.reactiveTheme.textTheme.bodyLarge!.color,
  731. fontWeight: FontWeight.w500,
  732. ),
  733. ),
  734. 4.horizontalSpace,
  735. if (showInfo)
  736. ClickOpacity(
  737. onTap: onInfoTap,
  738. child: Icon(
  739. IconFont.icon59,
  740. size: 20.w,
  741. color: Get.reactiveTheme.hintColor,
  742. ),
  743. ),
  744. ],
  745. ),
  746. ),
  747. // 右侧内容
  748. if (trailing != null) trailing,
  749. ],
  750. ),
  751. ),
  752. );
  753. }
  754. /// 构建分割线
  755. Widget _buildDivider() {
  756. return Padding(
  757. padding: EdgeInsets.only(left: 60.w),
  758. child: Divider(
  759. height: 1,
  760. color: Get.reactiveTheme.dividerColor.withValues(alpha: 0.3),
  761. ),
  762. );
  763. }
  764. /// 获取用户账号显示文本
  765. String _getUserAccount() {
  766. final user = IXSP.getUser();
  767. if (user == null) return '';
  768. if (user.memberLevel == MemberLevel.normal.level) {
  769. return user.account?.username ?? '';
  770. }
  771. return '';
  772. }
  773. }