mine_page.dart 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. import 'dart:io';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_screenutil/flutter_screenutil.dart';
  6. import 'package:get/get.dart';
  7. import 'package:location/base/base_page.dart';
  8. import 'package:location/data/bean/member_status_info.dart';
  9. import 'package:location/resource/assets.gen.dart';
  10. import 'package:location/resource/colors.gen.dart';
  11. import 'package:location/resource/string.gen.dart';
  12. import 'package:location/utils/common_expand.dart';
  13. import '../../router/app_pages.dart';
  14. import '../../utils/common_style.dart';
  15. import '../../utils/date_util.dart';
  16. import '../../widget/common_view.dart';
  17. import 'mine_controller.dart';
  18. import 'mine_trial_membership_countdown_text.dart';
  19. class MinePage extends BasePage<MineController> {
  20. const MinePage({super.key});
  21. static void start() {
  22. Get.toNamed(RoutePath.mine);
  23. }
  24. @override
  25. bool immersive() {
  26. return true;
  27. }
  28. @override
  29. Color backgroundColor() {
  30. return '#FAFAFA'.color;
  31. }
  32. @override
  33. Widget buildBody(BuildContext context) {
  34. return Stack(
  35. children: [
  36. Assets.images.bgPageBackground.image(width: double.infinity),
  37. SafeArea(
  38. child: SingleChildScrollView(
  39. child: Column(children: [
  40. SizedBox(height: 70.w),
  41. Row(
  42. children: [
  43. SizedBox(width: 12.w),
  44. GestureDetector(
  45. onTap: () => controller.onEditUserAvatarClick(),
  46. child: Obx(() {
  47. return controller.isLogin
  48. ? (controller.mineInfo.avatar != null
  49. ? buildAvatarView(controller.mineInfo.avatar!)
  50. : Assets.images.iconMineLogged
  51. .image(width: 54.w, height: 54.w))
  52. : Assets.images.iconMineNoLogin
  53. .image(width: 54.w, height: 54.w);
  54. }),
  55. ),
  56. SizedBox(width: 10.w),
  57. Expanded(child: buildLoginInfo()),
  58. //Spacer(),
  59. Obx(() {
  60. return Visibility(
  61. visible: controller.isOpenFreeMember == true,
  62. child: GestureDetector(
  63. onTap: () => controller.onMemberTryOutClick(),
  64. child: buildMemberTryOutView()));
  65. })
  66. ],
  67. ),
  68. SizedBox(height: 20.w),
  69. buildExperienceContent(),
  70. SizedBox(height: 16.w),
  71. buildFunList()
  72. ]),
  73. ),
  74. ),
  75. buildBackBtn(),
  76. ],
  77. );
  78. }
  79. Widget buildMineFunItem(ImageProvider icon, String funName,
  80. VoidCallback onTap,
  81. {Widget? secondaryWidget}) {
  82. return GestureDetector(
  83. behavior: HitTestBehavior.translucent,
  84. onTap: onTap,
  85. child: Container(
  86. padding: EdgeInsets.symmetric(vertical: 15.w, horizontal: 12.w),
  87. child: Row(
  88. children: [
  89. Image(image: icon, width: 24.w, height: 24.w),
  90. SizedBox(width: 6.w),
  91. Text(funName,
  92. style: TextStyle(fontSize: 15.sp, color: '#202020'.color)),
  93. if (secondaryWidget != null) secondaryWidget,
  94. Spacer(),
  95. Assets.images.iconMineFunArrow.image(width: 20.w, height: 20.w)
  96. ],
  97. ),
  98. ),
  99. );
  100. }
  101. Widget buildExperienceContent() {
  102. return Stack(
  103. children: [
  104. Column(
  105. children: [
  106. AspectRatio(
  107. aspectRatio: 332 / 57, child: SizedBox(width: double.infinity)),
  108. /*Obx(() {
  109. return Visibility(
  110. visible: controller.isOpenFreeMember == true,
  111. child: GestureDetector(
  112. onTap: controller.onMemberTryOutClick,
  113. child: Stack(
  114. children: [
  115. Container(
  116. margin: EdgeInsets.symmetric(horizontal: 14.w),
  117. width: double.infinity,
  118. height: 50.w,
  119. decoration: BoxDecoration(
  120. borderRadius: BorderRadius.only(
  121. bottomLeft: Radius.circular(8.w),
  122. bottomRight: Radius.circular(8.w)),
  123. gradient: LinearGradient(
  124. begin: Alignment.centerLeft,
  125. end: Alignment.centerRight,
  126. colors: ['#FFF8DA'.color, '#FFF1BA'.color]),
  127. ),
  128. ),
  129. Positioned(
  130. bottom: 0,
  131. left: 0,
  132. right: 0,
  133. child: Container(
  134. margin: EdgeInsets.symmetric(horizontal: 14.w),
  135. height: 32.w,
  136. child: Row(
  137. children: [
  138. SizedBox(width: 15.w),
  139. Assets.images.iconExperiment
  140. .image(width: 16.w, height: 16.w),
  141. SizedBox(width: 4.w),
  142. Text(StringName.memberExperienceVip,
  143. style: TextStyle(
  144. fontSize: 13.sp, color: '#8A5F03'.color)),
  145. Spacer(),
  146. Text(StringName.memberExperienceVipReceive,
  147. style: TextStyle(
  148. fontSize: 13.sp, color: '#8A5F03'.color)),
  149. Assets.images.iconMemberVipReceiveArrow
  150. .image(width: 16.w, height: 16.w),
  151. SizedBox(width: 13.w),
  152. ],
  153. ),
  154. ),
  155. )
  156. ],
  157. ),
  158. ),
  159. );
  160. })*/
  161. ],
  162. ),
  163. buildMemberCard()
  164. ],
  165. );
  166. }
  167. Widget buildLoginInfo() {
  168. return GestureDetector(
  169. behavior: HitTestBehavior.translucent,
  170. onTap: controller.onMineDescClick,
  171. child: Column(
  172. mainAxisAlignment: MainAxisAlignment.center,
  173. crossAxisAlignment: CrossAxisAlignment.start,
  174. children: [
  175. Row(
  176. children: [
  177. Obx(() {
  178. String desc = "";
  179. if (controller.isLogin &&
  180. controller.phone?.isNotEmpty == true) {
  181. desc = controller.getUserName(controller.phone!);
  182. } else {
  183. desc = StringName.mineAccountGoLogin;
  184. }
  185. return Text(desc,
  186. style: TextStyle(
  187. fontSize: 16.sp,
  188. color: '#333333'.color,
  189. fontWeight: FontWeight.bold));
  190. }),
  191. SizedBox(width: 6.w),
  192. Obx(() {
  193. return Visibility(
  194. visible: controller.isLogin &&
  195. controller.memberStatusInfo != null &&
  196. controller.memberStatusInfo?.expired == false,
  197. child: Assets.images.iconVip.image(width: 28.w));
  198. })
  199. ],
  200. ),
  201. SizedBox(height: 6.w),
  202. buildLoginDesc(),
  203. ],
  204. ),
  205. );
  206. }
  207. Container buildMemberTryOutView() {
  208. return Container(
  209. margin: EdgeInsets.only(right: 16.w),
  210. decoration: BoxDecoration(
  211. color: '#267B7DFF'.color, borderRadius: BorderRadius.circular(26.w)),
  212. padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 5.w),
  213. child: Text(
  214. controller.isLogin
  215. ? ((controller.memberStatusInfo?.trialed == false)
  216. ? StringName.memberTryOut
  217. : StringName.memberReceivedMembership)
  218. : StringName.memberTryOut,
  219. style: TextStyle(fontSize: 12.sp, color: '#8163FF'.color)),
  220. );
  221. }
  222. Widget buildBackBtn() {
  223. return SafeArea(
  224. child: GestureDetector(
  225. onTap: controller.onBack,
  226. child: Container(
  227. margin: EdgeInsets.only(top: 16.w, left: 14.w),
  228. child: CommonView.getBackBtnView())),
  229. );
  230. }
  231. Widget buildLoginDesc() {
  232. return Obx(() {
  233. String txt = '';
  234. if (!controller.isLogin) {
  235. txt = StringName.mineNotLoginDesc;
  236. } else if (controller.memberStatusInfo != null &&
  237. controller.memberStatusInfo?.expired == false) {
  238. txt = StringName.mineVip;
  239. } else if (controller.memberStatusInfo?.expired == true) {
  240. txt = StringName.mineRenewalVipContinueProtectYou;
  241. } else {
  242. txt = StringName.mineOpenVip;
  243. }
  244. return Text(txt,
  245. style: TextStyle(fontSize: 13.sp, color: '#727272'.color));
  246. });
  247. }
  248. Widget buildMemberCard() {
  249. return Container(
  250. decoration: BoxDecoration(
  251. borderRadius: BorderRadius.only(
  252. topLeft: Radius.circular(20.w),
  253. topRight: Radius.circular(20.w),
  254. bottomLeft: Radius.circular(8.w),
  255. bottomRight: Radius.circular(8.w)),
  256. gradient: LinearGradient(
  257. begin: Alignment.centerLeft,
  258. end: Alignment.centerRight,
  259. stops: [0.0, 0.1],
  260. colors: ['#FFF8DA'.color, '#FFF1BA'.color])),
  261. margin: EdgeInsets.symmetric(horizontal: 14.w),
  262. child: Column(
  263. children: [
  264. GestureDetector(
  265. onTap: controller.onMemberCardClick,
  266. child: AspectRatio(
  267. aspectRatio: 332 / 75,
  268. child: Container(
  269. //margin: EdgeInsets.symmetric(horizontal: 14.w),
  270. decoration: BoxDecoration(
  271. image: DecorationImage(
  272. image: Assets.images.bgMineMemberCard.provider(),
  273. fit: BoxFit.fill)),
  274. child: Row(
  275. children: [
  276. SizedBox(width: 14.w),
  277. Column(
  278. crossAxisAlignment: CrossAxisAlignment.start,
  279. mainAxisAlignment: MainAxisAlignment.center,
  280. children: [
  281. Row(
  282. children: [
  283. Assets.images.iconMineUnlockVip.image(width: 68.w),
  284. SizedBox(width: 6.5.w),
  285. Assets.images.iconMineSmallVip
  286. .image(width: 21.6.w, height: 21.6.w),
  287. ],
  288. ),
  289. SizedBox(height: 6.w),
  290. buildMemberCardVipDesc()
  291. ],
  292. ),
  293. Spacer(),
  294. buildBuyMemberCardBtn()
  295. ],
  296. ),
  297. ),
  298. ),
  299. ),
  300. Obx(() {
  301. return Visibility(
  302. visible: controller.isLogin,
  303. child: GestureDetector(
  304. onTap: !(controller.memberStatusInfo?.trialed ?? false)
  305. ? () => controller.onMemberTryOutClick()
  306. : null,
  307. child: Container(
  308. width: double.infinity,
  309. padding: EdgeInsets.symmetric(horizontal: 15.w),
  310. height: 32.w,
  311. child: Row(
  312. children: [
  313. Assets.images.iconMemberVipSign
  314. .image(width: 16.w, height: 16.w),
  315. SizedBox(
  316. width: 4.w,
  317. ),
  318. Expanded(
  319. child: Obx(() {
  320. return MineTrialMembershipCountdownText(
  321. memberStatusInfo: controller.memberStatusInfo ??
  322. MemberStatusInfo(
  323. level: 0,
  324. endTimestamp: 0,
  325. expired: false,
  326. permanent: false),
  327. trialHasExpiredCallBack:
  328. controller.promptWindowPopsCountdownExpires,
  329. );
  330. }),
  331. ),
  332. Visibility(
  333. visible: !(controller.memberStatusInfo?.trialed ??
  334. false),
  335. child: Row(
  336. children: [
  337. Text(StringName.memberExperienceVipReceive,
  338. style: TextStyle(
  339. fontSize: 13.sp,
  340. color: "#8A5F03".color,
  341. fontWeight: FontWeight.w400)),
  342. Assets.images.iconMemberVipMore
  343. .image(width: 16.w, height: 16.w)
  344. ],
  345. )),
  346. ],
  347. ),
  348. ),
  349. ));
  350. })
  351. ],
  352. ),
  353. );
  354. }
  355. Widget buildMemberCardVipDesc() {
  356. return Obx(() {
  357. String desc = '';
  358. if (!controller.isLogin) {
  359. desc = StringName.memberCardNoLoginDesc;
  360. } else if (controller.memberStatusInfo == null ||
  361. controller.memberStatusInfo?.expired == true) {
  362. desc = StringName.memberCardNoVipDesc;
  363. } else if (controller.memberStatusInfo?.expired == false &&
  364. controller.memberStatusInfo?.permanent == true) {
  365. desc = StringName.memberCardPermanentVipDesc;
  366. } else {
  367. desc =
  368. '${DateUtil.fromMillisecondsSinceEpoch('yyyy.MM.dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
  369. }
  370. return Text(desc,
  371. style: TextStyle(fontSize: 12.sp, color: ColorName.white80));
  372. });
  373. }
  374. Widget buildBuyMemberCardBtn() {
  375. return Obx(() {
  376. String txt = "";
  377. if (!controller.isLogin ||
  378. controller.memberStatusInfo == null ||
  379. controller.memberStatusInfo?.expired == true) {
  380. txt = StringName.memberVipUnlock;
  381. } else if (controller.memberStatusInfo?.expired == false &&
  382. controller.memberStatusInfo?.permanent == true) {
  383. txt = StringName.mineMemberPermanent;
  384. } else {
  385. txt = StringName.memberVipRenew;
  386. }
  387. return Container(
  388. margin: EdgeInsets.only(right: 20.w),
  389. decoration: BoxDecoration(
  390. color: ColorName.white, borderRadius: BorderRadius.circular(26.w)),
  391. padding: EdgeInsets.symmetric(horizontal: 13.w, vertical: 6.w),
  392. child: Text(txt,
  393. style: TextStyle(
  394. fontSize: 12.sp,
  395. color: '#5558FC'.color,
  396. fontWeight: FontWeight.bold)),
  397. );
  398. });
  399. }
  400. Widget buildFunList() {
  401. return Container(
  402. decoration: BoxDecoration(
  403. color: ColorName.white, borderRadius: BorderRadius.circular(12.w)),
  404. margin: EdgeInsets.symmetric(horizontal: 12.w),
  405. padding: EdgeInsets.symmetric(vertical: 5.w),
  406. child: Column(
  407. children: [
  408. buildMineFunItem(
  409. Assets.images.iconMineUrgentContact.provider(),
  410. StringName.mineUrgentContact,
  411. () => controller.onUrgentContactClick()),
  412. buildMineFunItem(
  413. Assets.images.iconMineCommonPoint.provider(),
  414. StringName.mineFunCommonPoint,
  415. () => controller.onCommonPointClick(),
  416. secondaryWidget: Container(
  417. margin: EdgeInsets.only(left: 5.w),
  418. child:
  419. Assets.images.iconFunCommonPointSummary.image(width: 63.w),
  420. )),
  421. buildMineFunItem(Assets.images.iconMineFunShare.provider(),
  422. StringName.mineFunShare, () => controller.onShareClick()),
  423. Visibility(
  424. visible: Platform.isAndroid,
  425. child: buildMineFunItem(
  426. Assets.images.iconMineFunCustomerService.provider(),
  427. StringName.mineFunCustomerService,
  428. () => controller.onCustomerServiceClick()),
  429. ),
  430. buildMineFunItem(
  431. Assets.images.iconMineFunPermissionSetting.provider(),
  432. StringName.mineFunPermissionSetting,
  433. () => controller.onPermissionSettingClick()),
  434. if (Platform.isAndroid)
  435. buildMineFunItem(
  436. Assets.images.iconMineFunAccountFeedback.provider(),
  437. StringName.mineFunAccountFeedback,
  438. () => controller.onAccountFeedbackClick()),
  439. buildMineFunItem(Assets.images.iconMineFunAbout.provider(),
  440. StringName.mineFunAbout, () => controller.onAboutClick()),
  441. Obx(() {
  442. return Visibility(
  443. visible: controller.isLogin,
  444. child: buildMineFunItem(
  445. Assets.images.iconMineFunLogoutAccount.provider(),
  446. StringName.mineFunLogoutAccount,
  447. () => controller.onLogoutAccountClick()),
  448. );
  449. }),
  450. Obx(() {
  451. return Visibility(
  452. visible: controller.isLogin,
  453. child: buildMineFunItem(
  454. Assets.images.iconMineFunExitAccount.provider(),
  455. StringName.mineFunExitAccount,
  456. () => controller.onFunExitAccountClick()),
  457. );
  458. }),
  459. ],
  460. ),
  461. );
  462. }
  463. Widget buildAvatarView(String avatar) {
  464. return Container(
  465. decoration: BoxDecoration(
  466. shape: BoxShape.circle,
  467. border: Border.all(
  468. color: '#E8E1FF'.color,
  469. width: 1.w,
  470. ),
  471. ),
  472. child: buildCustomAvatarView(
  473. size: 54.w,
  474. avatar: avatar,
  475. ),
  476. );
  477. }
  478. }