mine_page.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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(
  58. child: buildLoginInfo()),
  59. //Spacer(),
  60. Obx(() {
  61. return Visibility(
  62. visible: controller.isOpenFreeMember == true,
  63. child: GestureDetector(
  64. onTap: controller.onMemberTryOutClick,
  65. child: buildMemberTryOutView()));
  66. })
  67. ],
  68. ),
  69. ),
  70. SizedBox(height: 20.w),
  71. buildExperienceContent(),
  72. SizedBox(height: 16.w),
  73. buildFunList()
  74. ]),
  75. ),
  76. ),
  77. buildBackBtn(),
  78. ],
  79. );
  80. }
  81. Widget buildMineFunItem(
  82. ImageProvider icon, String funName, VoidCallback onTap) {
  83. return GestureDetector(
  84. behavior: HitTestBehavior.translucent,
  85. onTap: onTap,
  86. child: Container(
  87. padding: EdgeInsets.symmetric(vertical: 15.w, horizontal: 12.w),
  88. child: Row(
  89. children: [
  90. Image(image: icon, width: 24.w, height: 24.w),
  91. SizedBox(width: 6.w),
  92. Text(funName,
  93. style: TextStyle(fontSize: 15.sp, color: '#202020'.color)),
  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 Column(
  169. mainAxisAlignment: MainAxisAlignment.center,
  170. crossAxisAlignment: CrossAxisAlignment.start,
  171. children: [
  172. Row(
  173. children: [
  174. Obx(() {
  175. String desc = "";
  176. if (controller.isLogin && controller.phone?.isNotEmpty == true) {
  177. desc = controller.getUserName(controller.phone!);
  178. } else {
  179. desc = StringName.mineAccountGoLogin;
  180. }
  181. return Text(desc,
  182. style: TextStyle(
  183. fontSize: 16.sp,
  184. color: '#333333'.color,
  185. fontWeight: FontWeight.bold));
  186. }),
  187. SizedBox(width: 6.w),
  188. Obx(() {
  189. return Visibility(
  190. visible: controller.isLogin &&
  191. controller.memberStatusInfo != null &&
  192. controller.memberStatusInfo?.expired == false,
  193. child: Assets.images.iconVip.image(width: 28.w));
  194. })
  195. ],
  196. ),
  197. SizedBox(height: 6.w),
  198. buildLoginDesc(),
  199. ],
  200. );
  201. }
  202. Container buildMemberTryOutView() {
  203. return Container(
  204. margin: EdgeInsets.only(right: 16.w),
  205. decoration: BoxDecoration(
  206. color: '#267B7DFF'.color, borderRadius: BorderRadius.circular(26.w)),
  207. padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 5.w),
  208. child: Text(controller.isLogin ? ((controller.memberStatusInfo?.trialed == false) ? StringName.memberTryOut : StringName.memberReceivedMembership) : StringName.memberTryOut,
  209. style: TextStyle(fontSize: 12.sp, color: '#8163FF'.color)),
  210. );
  211. }
  212. Widget buildBackBtn() {
  213. return SafeArea(
  214. child: GestureDetector(
  215. onTap: controller.onBack,
  216. child: Container(
  217. margin: EdgeInsets.only(top: 16.w, left: 14.w),
  218. child: CommonView.getBackBtnView())),
  219. );
  220. }
  221. Widget buildLoginDesc() {
  222. return Obx(() {
  223. String txt = '';
  224. if (!controller.isLogin) {
  225. txt = StringName.mineNotLoginDesc;
  226. } else if (controller.memberStatusInfo != null &&
  227. controller.memberStatusInfo?.expired == false) {
  228. txt = StringName.mineVip;
  229. } else if (controller.memberStatusInfo?.expired == true) {
  230. txt = StringName.mineRenewalVipContinueProtectYou;
  231. } else {
  232. txt = StringName.mineOpenVip;
  233. }
  234. return Text(txt,
  235. style: TextStyle(fontSize: 13.sp, color: '#727272'.color));
  236. });
  237. }
  238. Widget buildMemberCard() {
  239. return Container(
  240. decoration: BoxDecoration(
  241. borderRadius: BorderRadius.only(
  242. topLeft: Radius.circular(20.w),
  243. topRight: Radius.circular(20.w),
  244. bottomLeft: Radius.circular(8.w),
  245. bottomRight: Radius.circular(8.w)),
  246. gradient: LinearGradient(
  247. begin: Alignment.centerLeft,
  248. end: Alignment.centerRight,
  249. stops: [0.0, 0.1],
  250. colors: ['#FFF8DA'.color, '#FFF1BA'.color])),
  251. margin: EdgeInsets.symmetric(horizontal: 14.w),
  252. child: Column(
  253. children: [
  254. GestureDetector(
  255. onTap: controller.onMemberCardClick,
  256. child: AspectRatio(
  257. aspectRatio: 332 / 75,
  258. child: Container(
  259. //margin: EdgeInsets.symmetric(horizontal: 14.w),
  260. decoration: BoxDecoration(
  261. image: DecorationImage(
  262. image: Assets.images.bgMineMemberCard.provider(),
  263. fit: BoxFit.fill)),
  264. child: Row(
  265. children: [
  266. SizedBox(width: 14.w),
  267. Column(
  268. crossAxisAlignment: CrossAxisAlignment.start,
  269. mainAxisAlignment: MainAxisAlignment.center,
  270. children: [
  271. Row(
  272. children: [
  273. Assets.images.iconMineUnlockVip.image(width: 68.w),
  274. SizedBox(width: 6.5.w),
  275. Assets.images.iconMineSmallVip
  276. .image(width: 21.6.w, height: 21.6.w),
  277. ],
  278. ),
  279. SizedBox(height: 6.w),
  280. buildMemberCardVipDesc()
  281. ],
  282. ),
  283. Spacer(),
  284. buildBuyMemberCardBtn()
  285. ],
  286. ),
  287. ),
  288. ),
  289. ),
  290. Obx(() {
  291. return Visibility(
  292. visible: controller.isLogin,
  293. child: GestureDetector(
  294. onTap:!(controller.memberStatusInfo?.trialed ?? false) ? controller.onMemberTryOutClick : null,
  295. child: Container(
  296. width: double.infinity,
  297. padding: EdgeInsets.symmetric(horizontal: 15.w),
  298. height: 32.w,
  299. child: Row(
  300. children: [
  301. Assets.images.iconMemberVipSign.image(width: 16.w,height: 16.w),
  302. SizedBox(width: 4.w,),
  303. Expanded(
  304. child: Obx(() {
  305. return MineTrialMembershipCountdownText(
  306. memberStatusInfo: controller.memberStatusInfo ?? MemberStatusInfo(level: 0, endTimestamp: 0, expired: false, permanent: false),
  307. trialHasExpiredCallBack: controller.promptWindowPopsCountdownExpires,
  308. );
  309. }),
  310. ),
  311. Visibility(
  312. visible: !(controller.memberStatusInfo?.trialed ?? false),
  313. child: Row(
  314. children: [
  315. Text(
  316. StringName.memberExperienceVipReceive,
  317. style: TextStyle(
  318. fontSize: 13.sp,
  319. color: "#8A5F03".color,
  320. fontWeight: FontWeight.w400
  321. )
  322. ),
  323. Assets.images.iconMemberVipMore.image(width: 16.w,height: 16.w)
  324. ],
  325. )
  326. ),
  327. ],
  328. ),
  329. ),
  330. )
  331. );
  332. })
  333. ],
  334. ),
  335. );
  336. }
  337. Widget buildMemberCardVipDesc() {
  338. return Obx(() {
  339. String desc = '';
  340. if (!controller.isLogin) {
  341. desc = StringName.memberCardNoLoginDesc;
  342. } else if (controller.memberStatusInfo == null ||
  343. controller.memberStatusInfo?.expired == true) {
  344. desc = StringName.memberCardNoVipDesc;
  345. } else if (controller.memberStatusInfo?.expired == false &&
  346. controller.memberStatusInfo?.permanent == true) {
  347. desc = StringName.memberCardPermanentVipDesc;
  348. } else {
  349. desc =
  350. '${DateUtil.fromMillisecondsSinceEpoch('yyyy.MM.dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
  351. }
  352. return Text(desc,
  353. style: TextStyle(fontSize: 12.sp, color: ColorName.white80));
  354. });
  355. }
  356. Widget buildBuyMemberCardBtn() {
  357. return Obx(() {
  358. String txt = "";
  359. if (!controller.isLogin ||
  360. controller.memberStatusInfo == null ||
  361. controller.memberStatusInfo?.expired == true) {
  362. txt = StringName.memberVipUnlock;
  363. } else if (controller.memberStatusInfo?.expired == false &&
  364. controller.memberStatusInfo?.permanent == true) {
  365. txt = StringName.mineMemberPermanent;
  366. } else {
  367. txt = StringName.memberVipRenew;
  368. }
  369. return Container(
  370. margin: EdgeInsets.only(right: 20.w),
  371. decoration: BoxDecoration(
  372. color: ColorName.white, borderRadius: BorderRadius.circular(26.w)),
  373. padding: EdgeInsets.symmetric(horizontal: 13.w, vertical: 6.w),
  374. child: Text(txt,
  375. style: TextStyle(
  376. fontSize: 12.sp,
  377. color: '#5558FC'.color,
  378. fontWeight: FontWeight.bold)),
  379. );
  380. });
  381. }
  382. Widget buildFunList() {
  383. return Container(
  384. decoration: BoxDecoration(
  385. color: ColorName.white, borderRadius: BorderRadius.circular(12.w)),
  386. margin: EdgeInsets.symmetric(horizontal: 12.w),
  387. padding: EdgeInsets.symmetric(vertical: 5.w),
  388. child: Column(
  389. children: [
  390. buildMineFunItem(
  391. Assets.images.iconMineUrgentContact.provider(),
  392. StringName.mineUrgentContact,
  393. () => controller.onUrgentContactClick()),
  394. buildMineFunItem(Assets.images.iconMineFunShare.provider(),
  395. StringName.mineFunShare, () => controller.onShareClick()),
  396. Visibility(
  397. visible: Platform.isAndroid,
  398. child: buildMineFunItem(
  399. Assets.images.iconMineFunCustomerService.provider(),
  400. StringName.mineFunCustomerService,
  401. () => controller.onCustomerServiceClick()),),
  402. buildMineFunItem(
  403. Assets.images.iconMineFunPermissionSetting.provider(),
  404. StringName.mineFunPermissionSetting,
  405. () => controller.onPermissionSettingClick()),
  406. if (Platform.isAndroid) buildMineFunItem(
  407. Assets.images.iconMineFunAccountFeedback.provider(),
  408. StringName.mineFunAccountFeedback,
  409. () => controller.onAccountFeedbackClick()),
  410. buildMineFunItem(Assets.images.iconMineFunAbout.provider(),
  411. StringName.mineFunAbout, () => controller.onAboutClick()),
  412. Obx(() {
  413. return Visibility(
  414. visible: controller.isLogin,
  415. child: buildMineFunItem(
  416. Assets.images.iconMineFunLogoutAccount.provider(),
  417. StringName.mineFunLogoutAccount,
  418. () => controller.onLogoutAccountClick()),
  419. );
  420. }),
  421. Obx(() {
  422. return Visibility(
  423. visible: controller.isLogin,
  424. child: buildMineFunItem(
  425. Assets.images.iconMineFunExitAccount.provider(),
  426. StringName.mineFunExitAccount,
  427. () => controller.onFunExitAccountClick()),
  428. );
  429. }),
  430. ],
  431. ),
  432. );
  433. }
  434. Widget buildAvatarView(String avatar) {
  435. return Container(
  436. decoration: BoxDecoration(
  437. shape: BoxShape.circle,
  438. border: Border.all(
  439. color: '#E8E1FF'.color,
  440. width: 1.w,
  441. ),
  442. ),
  443. child: buildCustomAvatarView(
  444. size: 54.w,
  445. avatar: avatar,
  446. ),
  447. );
  448. }
  449. }