mine_page.dart 17 KB

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