setting_view.dart 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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: 92.w,
  136. // height: 28.w,
  137. // sourceType: ImageSourceType.asset,
  138. // ),
  139. // 4.horizontalSpace,
  140. // Icon(
  141. // IconFont.icon02,
  142. // size: 20.w,
  143. // color: Get.reactiveTheme.hintColor,
  144. // ),
  145. // ],
  146. // ),
  147. // onTap: () {
  148. // Get.toNamed(Routes.ACCOUNT);
  149. // },
  150. // ),
  151. const SizedBox.shrink(),
  152. _buildDivider(),
  153. _buildSettingItem(
  154. icon: IconFont.icon14,
  155. iconColor: Get.reactiveTheme.shadowColor,
  156. title:
  157. 'UID ${formatDeviceId(DeviceManager.getCacheDeviceId())}',
  158. showInfo: true,
  159. disableFeedback: true,
  160. trailing: ClickOpacity(
  161. onTap: () {
  162. Clipboard.setData(
  163. ClipboardData(text: DeviceManager.getCacheDeviceId()),
  164. );
  165. IXSnackBar.showIXSnackBar(
  166. title: Strings.copied.tr,
  167. message: Strings.copied.tr,
  168. );
  169. },
  170. child: Icon(
  171. IconFont.icon57,
  172. size: 20.w,
  173. color: Get.reactiveTheme.hintColor,
  174. ),
  175. ),
  176. onInfoTap: () {
  177. AllDialog.showUidInfo();
  178. },
  179. ),
  180. _buildDivider(),
  181. // 根据用户类型显示不同的时间信息
  182. if (controller.apiController.isPremium) ...[
  183. // _buildSettingItem(
  184. // disableFeedback: true,
  185. // icon: IconFont.icon30,
  186. // iconColor: Get.reactiveTheme.shadowColor,
  187. // title: Strings.validTerm.tr,
  188. // trailing: Text(
  189. // controller.apiController.remainTimeSeconds > 0
  190. // ? controller.apiController.validTermText
  191. // : Strings.expired.tr,
  192. // style: TextStyle(
  193. // fontSize: 13.sp,
  194. // color: controller.apiController.remainTimeSeconds > 0
  195. // ? Get.reactiveTheme.primaryColor
  196. // : Colors.red,
  197. // fontWeight: FontWeight.w500,
  198. // ),
  199. // ),
  200. // onTap: () {},
  201. // ),
  202. ] else ...[
  203. // _buildSettingItem(
  204. // icon: IconFont.icon30,
  205. // iconColor: Get.reactiveTheme.shadowColor,
  206. // title: Strings.freeTime.tr,
  207. // trailing: Text(
  208. // controller.apiController.remainTimeFormatted,
  209. // style: TextStyle(
  210. // fontSize: 14.sp,
  211. // color: controller.apiController.remainTimeSeconds > 0
  212. // ? Get.reactiveTheme.primaryColor
  213. // : Colors.red,
  214. // fontWeight: FontWeight.w500,
  215. // ),
  216. // ),
  217. // ),
  218. ],
  219. // _buildDivider(),
  220. // _buildSettingItem(
  221. // icon: IconFont.icon31,
  222. // iconColor: Get.reactiveTheme.shadowColor,
  223. // title: Strings.deviceAuthorization.tr,
  224. // trailing: Row(
  225. // mainAxisSize: MainAxisSize.min,
  226. // children: [
  227. // Text(
  228. // isPremium ? '1/4' : '0/1',
  229. // style: TextStyle(
  230. // fontSize: 13.sp,
  231. // color: Get.reactiveTheme.hintColor,
  232. // ),
  233. // ),
  234. // SizedBox(width: 4.w),
  235. // Icon(
  236. // IconFont.icon02,
  237. // size: 20.w,
  238. // color: Get.reactiveTheme.hintColor,
  239. // ),
  240. // ],
  241. // ),
  242. // onTap: () {
  243. // Get.toNamed(Routes.DEVICEAUTH);
  244. // },
  245. // ),
  246. ],
  247. ),
  248. );
  249. }),
  250. );
  251. }
  252. /// Network 分组
  253. Widget _buildNetworkSection() {
  254. return SliverToBoxAdapter(
  255. child: Container(
  256. margin: EdgeInsets.symmetric(horizontal: 14.w),
  257. decoration: BoxDecoration(
  258. color: Get.reactiveTheme.highlightColor,
  259. borderRadius: BorderRadius.circular(12.r),
  260. ),
  261. child: Column(
  262. children: [
  263. _buildSettingItem(
  264. icon: IconFont.icon34,
  265. iconColor: Get.reactiveTheme.primaryColor,
  266. title: Strings.routingMode.tr,
  267. trailing: Icon(
  268. IconFont.icon02,
  269. size: 20.w,
  270. color: Get.reactiveTheme.hintColor,
  271. ),
  272. onTap: () {
  273. // TODO: 跳转到路由模式页面
  274. Get.toNamed(Routes.ROUTINGMODE);
  275. },
  276. ),
  277. _buildDivider(),
  278. if (Platform.isAndroid) ...[
  279. _buildSettingItem(
  280. icon: IconFont.icon32,
  281. iconColor: Get.reactiveTheme.primaryColor,
  282. title: Strings.splitTunneling.tr,
  283. trailing: Icon(
  284. IconFont.icon02,
  285. size: 20.w,
  286. color: Get.reactiveTheme.hintColor,
  287. ),
  288. onTap: () {
  289. // TODO: 跳转到分流隧道页面
  290. Get.toNamed(Routes.SPLITTUNNELING);
  291. },
  292. ),
  293. _buildDivider(),
  294. ],
  295. // _buildSettingItem(
  296. // icon: IconFont.icon33,
  297. // iconColor: Get.reactiveTheme.primaryColor,
  298. // title: Strings.autoReconnect.tr,
  299. // trailing: Obx(
  300. // () => CupertinoSwitch(
  301. // value: controller.autoReconnect,
  302. // onChanged: (value) {
  303. // controller.autoReconnect = value;
  304. // },
  305. // activeTrackColor: Get.reactiveTheme.shadowColor,
  306. // thumbColor: Colors.white,
  307. // inactiveThumbColor: Colors.white,
  308. // inactiveTrackColor: Colors.grey,
  309. // ),
  310. // ),
  311. // ),
  312. // _buildSettingItem(
  313. // icon: IconFont.icon35,
  314. // iconColor: Get.reactiveTheme.primaryColor,
  315. // title: Strings.restoreDefault.tr,
  316. // trailing: Icon(
  317. // IconFont.icon02,
  318. // size: 20.w,
  319. // color: Get.reactiveTheme.hintColor,
  320. // ),
  321. // onTap: () {
  322. // // TODO: 恢复默认设置
  323. // },
  324. // ),
  325. ],
  326. ),
  327. ),
  328. );
  329. }
  330. /// APP 分组
  331. Widget _buildAppSection() {
  332. return SliverToBoxAdapter(
  333. child: Container(
  334. margin: EdgeInsets.symmetric(horizontal: 14.w),
  335. decoration: BoxDecoration(
  336. color: Get.reactiveTheme.highlightColor,
  337. borderRadius: BorderRadius.circular(12.r),
  338. ),
  339. child: Column(
  340. children: [
  341. // _buildSettingItem(
  342. // icon: IconFont.icon36,
  343. // iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  344. // iconGradient: LinearGradient(
  345. // colors: [
  346. // DarkThemeColors.settingAppLinearGradientStartColor,
  347. // DarkThemeColors.settingAppLinearGradientEndColor,
  348. // ],
  349. // begin: Alignment.topCenter,
  350. // end: Alignment.bottomCenter,
  351. // ),
  352. // title: Strings.language.tr,
  353. // trailing: Row(
  354. // mainAxisSize: MainAxisSize.min,
  355. // children: [
  356. // Text(
  357. // LocalizationService.getGlobalLanguageTitle(),
  358. // style: TextStyle(
  359. // fontSize: 13.sp,
  360. // color: Get.reactiveTheme.hintColor,
  361. // ),
  362. // ),
  363. // 8.horizontalSpace,
  364. // Icon(
  365. // IconFont.icon02,
  366. // size: 20.w,
  367. // color: Get.reactiveTheme.hintColor,
  368. // ),
  369. // ],
  370. // ),
  371. // onTap: () {
  372. // Get.toNamed(Routes.LANGUAGE);
  373. // },
  374. // ),
  375. // _buildDivider(),
  376. _buildSettingItem(
  377. svgPath: Assets.settingsTheme,
  378. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  379. iconGradient: LinearGradient(
  380. colors: [
  381. DarkThemeColors.settingAppLinearGradientStartColor,
  382. DarkThemeColors.settingAppLinearGradientEndColor,
  383. ],
  384. begin: Alignment.topCenter,
  385. end: Alignment.bottomCenter,
  386. ),
  387. title: Strings.theme.tr,
  388. trailing: Row(
  389. mainAxisSize: MainAxisSize.min,
  390. children: [
  391. Obx(
  392. () => Text(
  393. controller.themeMode,
  394. style: TextStyle(
  395. fontSize: 13.sp,
  396. color: Get.reactiveTheme.hintColor,
  397. ),
  398. ),
  399. ),
  400. 8.horizontalSpace,
  401. Icon(
  402. IconFont.icon02,
  403. size: 20.w,
  404. color: Get.reactiveTheme.hintColor,
  405. ),
  406. ],
  407. ),
  408. onTap: () {
  409. Get.toNamed(
  410. Routes.THEME,
  411. )?.then((_) => controller.initThemeMode());
  412. },
  413. ),
  414. _buildDivider(),
  415. // _buildSettingItem(
  416. // icon: IconFont.icon37,
  417. // iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  418. // iconGradient: LinearGradient(
  419. // colors: [
  420. // DarkThemeColors.settingAppLinearGradientStartColor,
  421. // DarkThemeColors.settingAppLinearGradientEndColor,
  422. // ],
  423. // begin: Alignment.topCenter,
  424. // end: Alignment.bottomCenter,
  425. // ),
  426. // title: Strings.feedback.tr,
  427. // trailing: Icon(
  428. // IconFont.icon02,
  429. // size: 20.w,
  430. // color: Get.reactiveTheme.hintColor,
  431. // ),
  432. // onTap: () {
  433. // Get.toNamed(Routes.FEEDBACK);
  434. // },
  435. // ),
  436. // _buildDivider(),
  437. _buildSettingItem(
  438. icon: IconFont.icon38,
  439. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  440. iconGradient: LinearGradient(
  441. colors: [
  442. DarkThemeColors.settingAppLinearGradientStartColor,
  443. DarkThemeColors.settingAppLinearGradientEndColor,
  444. ],
  445. begin: Alignment.topCenter,
  446. end: Alignment.bottomCenter,
  447. ),
  448. title: Strings.privacyPolicy.tr,
  449. trailing: Icon(
  450. IconFont.icon02,
  451. size: 20.w,
  452. color: Get.reactiveTheme.hintColor,
  453. ),
  454. onTap: () {
  455. // TODO: 跳转到隐私政策页面
  456. SystemHelper.openPrivacyTerms();
  457. },
  458. ),
  459. _buildDivider(),
  460. _buildSettingItem(
  461. icon: IconFont.icon38,
  462. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  463. iconGradient: LinearGradient(
  464. colors: [
  465. DarkThemeColors.settingAppLinearGradientStartColor,
  466. DarkThemeColors.settingAppLinearGradientEndColor,
  467. ],
  468. begin: Alignment.topCenter,
  469. end: Alignment.bottomCenter,
  470. ),
  471. title: Strings.termsOfService.tr,
  472. trailing: Icon(
  473. IconFont.icon02,
  474. size: 20.w,
  475. color: Get.reactiveTheme.hintColor,
  476. ),
  477. onTap: () {
  478. // TODO: 跳转到服务条款页面
  479. SystemHelper.openTermsOfService();
  480. },
  481. ),
  482. // 桌面版本不显示通知
  483. // if (!isDesktop) ...[
  484. // _buildDivider(),
  485. // _buildSettingItem(
  486. // svgPath: Assets.pushNotifications,
  487. // iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  488. // iconGradient: LinearGradient(
  489. // colors: [
  490. // DarkThemeColors.settingAppLinearGradientStartColor,
  491. // DarkThemeColors.settingAppLinearGradientEndColor,
  492. // ],
  493. // begin: Alignment.topCenter,
  494. // end: Alignment.bottomCenter,
  495. // ),
  496. // title: Strings.pushNotifications.tr,
  497. // trailing: Obx(
  498. // () => CupertinoSwitch(
  499. // value: controller.pushNotifications,
  500. // onChanged: (value) {
  501. // controller.showNotificationConfigPage();
  502. // },
  503. // activeTrackColor: Get.reactiveTheme.shadowColor,
  504. // thumbColor: Colors.white,
  505. // inactiveThumbColor: Colors.white,
  506. // inactiveTrackColor: Colors.grey,
  507. // ),
  508. // ),
  509. // onTap: () {
  510. // controller.showNotificationConfigPage();
  511. // },
  512. // ),
  513. // ],
  514. _buildDivider(),
  515. _buildSettingItem(
  516. icon: IconFont.icon39,
  517. iconColor: DarkThemeColors.settingAppLinearGradientStartColor,
  518. iconGradient: LinearGradient(
  519. colors: [
  520. DarkThemeColors.settingAppLinearGradientStartColor,
  521. DarkThemeColors.settingAppLinearGradientEndColor,
  522. ],
  523. begin: Alignment.topCenter,
  524. end: Alignment.bottomCenter,
  525. ),
  526. title: Strings.version.tr,
  527. trailing: Obx(
  528. () => Row(
  529. mainAxisAlignment: MainAxisAlignment.center,
  530. crossAxisAlignment: CrossAxisAlignment.start,
  531. children: [
  532. Text(
  533. 'v${controller.version}',
  534. style: TextStyle(
  535. fontSize: 13.sp,
  536. color: Get.reactiveTheme.hintColor,
  537. ),
  538. ),
  539. if (controller.hasUpdate)
  540. Container(
  541. width: 4.w,
  542. height: 4.w,
  543. decoration: BoxDecoration(
  544. color: Colors.red,
  545. borderRadius: BorderRadius.circular(2.r),
  546. ),
  547. ),
  548. ],
  549. ),
  550. ),
  551. onTap: () {
  552. controller.apiController.checkUpdate(isClickCheck: true);
  553. },
  554. ),
  555. ],
  556. ),
  557. ),
  558. );
  559. }
  560. /// Security 分组
  561. Widget _buildSecuritySection() {
  562. return SliverToBoxAdapter(
  563. child: Container(
  564. margin: EdgeInsets.symmetric(horizontal: 14.w),
  565. decoration: BoxDecoration(
  566. color: Get.reactiveTheme.highlightColor,
  567. borderRadius: BorderRadius.circular(12.r),
  568. ),
  569. child: Column(
  570. children: [
  571. _buildSettingItem(
  572. icon: IconFont.icon11,
  573. iconColor:
  574. DarkThemeColors.settingSecurityLinearGradientStartColor,
  575. iconGradient: LinearGradient(
  576. colors: [
  577. DarkThemeColors.settingSecurityLinearGradientStartColor,
  578. DarkThemeColors.settingSecurityLinearGradientEndColor,
  579. ],
  580. begin: Alignment.topCenter,
  581. end: Alignment.bottomCenter,
  582. ),
  583. title: Strings.changePassword.tr,
  584. onTap: () {
  585. // TODO: 跳转到忘记密码页面
  586. Get.toNamed(Routes.FORGOTPWD);
  587. },
  588. ),
  589. _buildDivider(),
  590. _buildSettingItem(
  591. icon: IconFont.icon40,
  592. iconColor:
  593. DarkThemeColors.settingSecurityLinearGradientStartColor,
  594. iconGradient: LinearGradient(
  595. colors: [
  596. DarkThemeColors.settingSecurityLinearGradientStartColor,
  597. DarkThemeColors.settingSecurityLinearGradientEndColor,
  598. ],
  599. begin: Alignment.topCenter,
  600. end: Alignment.bottomCenter,
  601. ),
  602. title: Strings.deleteAccount.tr,
  603. onTap: () {
  604. AllDialog.showDeleteAccountConfirm(() {
  605. // 退出登录
  606. controller.handleDeleteAccount();
  607. });
  608. },
  609. ),
  610. _buildDivider(),
  611. _buildSettingItem(
  612. icon: IconFont.icon66,
  613. iconColor:
  614. DarkThemeColors.settingSecurityLinearGradientStartColor,
  615. iconGradient: LinearGradient(
  616. colors: [
  617. DarkThemeColors.settingSecurityLinearGradientStartColor,
  618. DarkThemeColors.settingSecurityLinearGradientEndColor,
  619. ],
  620. begin: Alignment.topCenter,
  621. end: Alignment.bottomCenter,
  622. ),
  623. title: Strings.logout.tr,
  624. titleColor: DarkThemeColors.errorColor,
  625. onTap: () {
  626. AllDialog.showLogoutConfirm(() {
  627. // 退出登录
  628. controller.handleLogout();
  629. });
  630. },
  631. ),
  632. ],
  633. ),
  634. ),
  635. );
  636. }
  637. /// 构建设置项
  638. Widget _buildSettingItem({
  639. IconData? icon,
  640. String? svgPath,
  641. required Color iconColor,
  642. Gradient? iconGradient,
  643. required String title,
  644. Color? titleColor,
  645. bool showInfo = false,
  646. Widget? trailing,
  647. VoidCallback? onTap,
  648. VoidCallback? onInfoTap,
  649. bool disableFeedback = false,
  650. }) {
  651. // 确保至少提供了 icon 或 svgPath 之一
  652. assert(
  653. icon != null || svgPath != null,
  654. 'Must provide either icon or svgPath',
  655. );
  656. return ClickOpacity(
  657. onTap: onTap,
  658. disableFeedback: disableFeedback,
  659. child: Container(
  660. height: 56.w,
  661. padding: EdgeInsets.symmetric(horizontal: 14.w),
  662. child: Row(
  663. children: [
  664. // 图标
  665. Container(
  666. width: 30.w,
  667. height: 30.w,
  668. decoration: BoxDecoration(
  669. gradient: iconGradient,
  670. color: iconGradient == null ? iconColor : null,
  671. borderRadius: BorderRadius.circular(8.r),
  672. ),
  673. child: svgPath != null
  674. ? Padding(
  675. padding: EdgeInsets.all(5.w),
  676. child: SvgPicture.asset(
  677. svgPath,
  678. width: 20.w,
  679. height: 20.w,
  680. colorFilter: const ColorFilter.mode(
  681. Colors.white,
  682. BlendMode.srcIn,
  683. ),
  684. ),
  685. )
  686. : Icon(icon!, size: 20.w, color: Colors.white),
  687. ),
  688. 10.horizontalSpace,
  689. // 标题
  690. Expanded(
  691. child: Row(
  692. children: [
  693. Text(
  694. title,
  695. style: TextStyle(
  696. fontSize: 14.sp,
  697. color:
  698. titleColor ??
  699. Get.reactiveTheme.textTheme.bodyLarge!.color,
  700. fontWeight: FontWeight.w500,
  701. ),
  702. ),
  703. 4.horizontalSpace,
  704. if (showInfo)
  705. ClickOpacity(
  706. onTap: onInfoTap,
  707. child: Icon(
  708. IconFont.icon59,
  709. size: 20.w,
  710. color: Get.reactiveTheme.hintColor,
  711. ),
  712. ),
  713. ],
  714. ),
  715. ),
  716. // 右侧内容
  717. if (trailing != null) trailing,
  718. ],
  719. ),
  720. ),
  721. );
  722. }
  723. /// 构建分割线
  724. Widget _buildDivider() {
  725. return Padding(
  726. padding: EdgeInsets.only(left: 60.w),
  727. child: Divider(
  728. height: 1,
  729. color: Get.reactiveTheme.dividerColor.withValues(alpha: 0.3),
  730. ),
  731. );
  732. }
  733. // /// 获取用户账号显示文本
  734. // String _getUserAccount() {
  735. // final user = IXSP.getUser();
  736. // if (user == null) return '';
  737. // if (user.memberLevel == MemberLevel.normal.level) {
  738. // return user.account?.username ?? '';
  739. // }
  740. // return '';
  741. // }
  742. }