account_view.dart 11 KB

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