account_view.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/services.dart';
  3. import 'package:flutter_screenutil/flutter_screenutil.dart';
  4. import 'package:get/get.dart';
  5. import 'package:nomo/app/base/base_view.dart';
  6. import 'package:nomo/app/widgets/click_opacity.dart';
  7. import 'package:nomo/app/widgets/ix_app_bar.dart';
  8. import 'package:nomo/app/widgets/submit_btn.dart';
  9. import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
  10. import '../../../../config/theme/dark_theme_colors.dart';
  11. import '../../../../config/translations/strings_enum.dart';
  12. import '../../../constants/assets.dart';
  13. import '../../../constants/iconfont/iconfont.dart';
  14. import '../../../widgets/ix_image.dart';
  15. import '../controllers/account_controller.dart';
  16. class AccountView extends BaseView<AccountController> {
  17. const AccountView({super.key});
  18. @override
  19. PreferredSizeWidget? get appBar => IXAppBar(title: Strings.account.tr);
  20. @override
  21. Widget buildContent(BuildContext context) {
  22. return Obx(() {
  23. final isPremium = controller.isPremium.value;
  24. return SingleChildScrollView(
  25. padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 10.w),
  26. child: Column(
  27. children: [
  28. // Account 信息卡片
  29. _buildAccountCard(isPremium),
  30. 20.verticalSpaceFromWidth,
  31. // 底部按钮
  32. _buildBottomButtons(isPremium),
  33. 20.verticalSpaceFromWidth,
  34. ],
  35. ),
  36. );
  37. });
  38. }
  39. /// 构建账户信息卡片
  40. Widget _buildAccountCard(bool isPremium) {
  41. return Container(
  42. decoration: BoxDecoration(
  43. color: Get.reactiveTheme.highlightColor,
  44. borderRadius: BorderRadius.circular(12.r),
  45. ),
  46. child: Column(
  47. children: [
  48. // Account 条目
  49. _buildAccountItem(isPremium),
  50. _buildDivider(),
  51. // UID 条目
  52. _buildUIDItem(),
  53. _buildDivider(),
  54. // Time/Term 条目
  55. if (isPremium) _buildValidTermItem() else _buildFreeTimeItem(),
  56. _buildDivider(),
  57. // Premium 功能列表
  58. _buildPremiumFeatures(isPremium),
  59. ],
  60. ),
  61. );
  62. }
  63. /// Account 条目
  64. Widget _buildAccountItem(bool isPremium) {
  65. return Container(
  66. height: 56.w,
  67. padding: EdgeInsets.symmetric(horizontal: 16.w),
  68. child: Row(
  69. children: [
  70. // 图标
  71. Container(
  72. width: 30.w,
  73. height: 30.w,
  74. decoration: BoxDecoration(
  75. color: Get.reactiveTheme.shadowColor,
  76. borderRadius: BorderRadius.circular(8.r),
  77. ),
  78. child: Icon(IconFont.icon29, size: 20.w, color: Colors.white),
  79. ),
  80. 10.horizontalSpace,
  81. // 标题
  82. Expanded(
  83. child: Text(
  84. Strings.account.tr,
  85. style: TextStyle(
  86. fontSize: 14.sp,
  87. color: Get.reactiveTheme.textTheme.bodyLarge!.color,
  88. fontWeight: FontWeight.w400,
  89. ),
  90. ),
  91. ),
  92. // 徽章
  93. IXImage(
  94. source: isPremium ? Assets.premium : Assets.free,
  95. width: isPremium ? 92.w : 64.w,
  96. height: 28.w,
  97. sourceType: ImageSourceType.asset,
  98. ),
  99. ],
  100. ),
  101. );
  102. }
  103. /// UID 条目
  104. Widget _buildUIDItem() {
  105. return ClickOpacity(
  106. onTap: () {
  107. Clipboard.setData(ClipboardData(text: controller.uid));
  108. Get.snackbar(Strings.copied.tr, 'UID ${Strings.copied.tr}');
  109. },
  110. child: Container(
  111. height: 56.w,
  112. padding: EdgeInsets.symmetric(horizontal: 16.w),
  113. child: Row(
  114. children: [
  115. // 图标
  116. Container(
  117. width: 30.w,
  118. height: 30.w,
  119. decoration: BoxDecoration(
  120. color: Get.reactiveTheme.shadowColor,
  121. borderRadius: BorderRadius.circular(8.r),
  122. ),
  123. child: Icon(IconFont.icon14, size: 20.w, color: Colors.white),
  124. ),
  125. 10.horizontalSpace,
  126. // UID
  127. Expanded(
  128. child: Text(
  129. controller.uid,
  130. style: TextStyle(
  131. fontSize: 14.sp,
  132. color: Get.reactiveTheme.textTheme.bodyLarge!.color,
  133. fontWeight: FontWeight.w400,
  134. ),
  135. ),
  136. ),
  137. // 复制图标
  138. Icon(
  139. IconFont.icon57,
  140. size: 20.w,
  141. color: Get.reactiveTheme.hintColor,
  142. ),
  143. ],
  144. ),
  145. ),
  146. );
  147. }
  148. /// Free Time 条目
  149. Widget _buildFreeTimeItem() {
  150. return Container(
  151. height: 56.w,
  152. padding: EdgeInsets.symmetric(horizontal: 16.w),
  153. child: Row(
  154. children: [
  155. // 图标
  156. Container(
  157. width: 30.w,
  158. height: 30.w,
  159. decoration: BoxDecoration(
  160. color: Get.reactiveTheme.shadowColor,
  161. borderRadius: BorderRadius.circular(8.r),
  162. ),
  163. child: Icon(IconFont.icon30, size: 20.w, color: Colors.white),
  164. ),
  165. 10.horizontalSpace,
  166. // 标题
  167. Expanded(
  168. child: Text(
  169. Strings.freeTime.tr,
  170. style: TextStyle(
  171. fontSize: 14.sp,
  172. color: Get.reactiveTheme.textTheme.bodyLarge!.color,
  173. fontWeight: FontWeight.w400,
  174. ),
  175. ),
  176. ),
  177. // 时间
  178. Text(
  179. controller.freeTime,
  180. style: TextStyle(
  181. fontSize: 13.sp,
  182. color: DarkThemeColors.validTermColor,
  183. fontWeight: FontWeight.w400,
  184. ),
  185. ),
  186. ],
  187. ),
  188. );
  189. }
  190. /// Valid Term 条目
  191. Widget _buildValidTermItem() {
  192. return Container(
  193. height: 56.w,
  194. padding: EdgeInsets.symmetric(horizontal: 16.w),
  195. child: Row(
  196. children: [
  197. // 图标
  198. Container(
  199. width: 30.w,
  200. height: 30.w,
  201. decoration: BoxDecoration(
  202. color: Get.reactiveTheme.shadowColor,
  203. borderRadius: BorderRadius.circular(8.r),
  204. ),
  205. child: Icon(IconFont.icon30, size: 20.w, color: Colors.white),
  206. ),
  207. 10.horizontalSpace,
  208. // 标题
  209. Expanded(
  210. child: Text(
  211. Strings.validTerm.tr,
  212. style: TextStyle(
  213. fontSize: 14.sp,
  214. color: Get.reactiveTheme.textTheme.bodyLarge!.color,
  215. fontWeight: FontWeight.w400,
  216. ),
  217. ),
  218. ),
  219. // 有效期
  220. Text(
  221. controller.validTerm,
  222. style: TextStyle(
  223. fontSize: 13.sp,
  224. color: Get.reactiveTheme.primaryColor,
  225. fontWeight: FontWeight.w400,
  226. ),
  227. ),
  228. ],
  229. ),
  230. );
  231. }
  232. Widget _buildPremiumFeatures(bool isPremium) {
  233. return Padding(
  234. padding: EdgeInsets.symmetric(horizontal: 14.w),
  235. child: Column(
  236. children: [
  237. _buildFeatureItem(IconFont.icon60, Strings.unlockAllFreeLocations.tr),
  238. _buildFeatureItem(IconFont.icon61, Strings.unlockSmartMode.tr),
  239. _buildFeatureItem(IconFont.icon62, Strings.unlockMultiHopMode.tr),
  240. _buildFeatureItem(
  241. IconFont.icon63,
  242. Strings.premiumCanShareXDevices.tr,
  243. ),
  244. _buildFeatureItem(
  245. IconFont.icon64,
  246. Strings.ownYourOwnPrivateServer.tr,
  247. ),
  248. _buildFeatureItem(IconFont.icon65, Strings.closeAds.tr),
  249. ],
  250. ),
  251. );
  252. }
  253. Widget _buildFeatureItem(IconData icon, String title) {
  254. return SizedBox(
  255. height: 44.w,
  256. child: Row(
  257. children: [
  258. Icon(icon, color: DarkThemeColors.subscriptionColor, size: 24.w),
  259. 12.horizontalSpace,
  260. Expanded(
  261. child: Text(
  262. title,
  263. style: TextStyle(
  264. fontSize: 13.sp,
  265. color: Get.reactiveTheme.hintColor,
  266. ),
  267. ),
  268. ),
  269. Container(
  270. width: 20.w,
  271. height: 20.w,
  272. decoration: BoxDecoration(
  273. shape: BoxShape.circle,
  274. color: DarkThemeColors.subscriptionSelectColor,
  275. ),
  276. child: Icon(Icons.check, color: Colors.white, size: 12.w),
  277. ),
  278. ],
  279. ),
  280. );
  281. }
  282. /// 底部按钮
  283. Widget _buildBottomButtons(bool isPremium) {
  284. if (isPremium) {
  285. return Column(
  286. children: [
  287. SubmitButton(
  288. text: Strings.changeSubscription.tr,
  289. bgColor: Get.reactiveTheme.highlightColor,
  290. textColor: DarkThemeColors.subscriptionColor,
  291. onPressed: () {
  292. // TODO: 修改订阅
  293. },
  294. ),
  295. 20.verticalSpaceFromWidth,
  296. // Device Authorization 按钮
  297. _buildSecondaryButton(
  298. text:
  299. '${Strings.deviceAuthorization.tr} (${controller.deviceCount}/${controller.maxDeviceCount})',
  300. icon: IconFont.icon11,
  301. onTap: () {
  302. // TODO: 设备授权
  303. },
  304. ),
  305. 10.verticalSpaceFromWidth,
  306. // 提示文字
  307. Text(
  308. Strings.youCanAuthorizeOtherDevices.trParams({
  309. 'current': controller.deviceCount.toString(),
  310. 'max': controller.maxDeviceCount.toString(),
  311. }),
  312. textAlign: TextAlign.center,
  313. style: TextStyle(
  314. fontSize: 12.sp,
  315. color: Get.reactiveTheme.hintColor,
  316. height: 1.5,
  317. ),
  318. ),
  319. ],
  320. );
  321. } else {
  322. return Column(
  323. children: [
  324. // Upgrade to Premium 按钮
  325. SubmitButton(
  326. text: Strings.upgradeToPremium.tr,
  327. bgColor: Get.reactiveTheme.highlightColor,
  328. textColor: DarkThemeColors.subscriptionColor,
  329. onPressed: () {
  330. // TODO: 修改订阅
  331. },
  332. ),
  333. 20.verticalSpaceFromWidth,
  334. // Activate Pre Code 按钮
  335. _buildSecondaryButton(
  336. text: Strings.activatePreCode.tr,
  337. icon: IconFont.icon23,
  338. onTap: () {
  339. // TODO: 激活兑换码
  340. },
  341. ),
  342. 10.verticalSpaceFromWidth,
  343. // 提示文字
  344. Text(
  345. Strings.preCodeHint.tr,
  346. textAlign: TextAlign.center,
  347. style: TextStyle(
  348. fontSize: 12.sp,
  349. color: Get.reactiveTheme.hintColor,
  350. ),
  351. ),
  352. ],
  353. );
  354. }
  355. }
  356. /// 次要按钮(黑色边框)
  357. Widget _buildSecondaryButton({
  358. required String text,
  359. required IconData icon,
  360. required VoidCallback onTap,
  361. }) {
  362. return ClickOpacity(
  363. onTap: onTap,
  364. child: Container(
  365. height: 52.w,
  366. decoration: BoxDecoration(
  367. border: Border.all(color: Get.reactiveTheme.dividerColor, width: 1.w),
  368. borderRadius: BorderRadius.circular(12.r),
  369. ),
  370. child: Row(
  371. mainAxisAlignment: MainAxisAlignment.center,
  372. children: [
  373. Text(
  374. text,
  375. style: TextStyle(
  376. fontSize: 16.sp,
  377. color: DarkThemeColors.subscriptionColor,
  378. fontWeight: FontWeight.w400,
  379. ),
  380. ),
  381. SizedBox(width: 8.w),
  382. Icon(icon, size: 20.w, color: DarkThemeColors.subscriptionColor),
  383. ],
  384. ),
  385. ),
  386. );
  387. }
  388. /// 构建分割线
  389. Widget _buildDivider() {
  390. return Divider(height: 1.w, color: Get.reactiveTheme.dividerColor);
  391. }
  392. }