Hibok
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

591 linhas
20 KiB

  1. import 'package:chat/data/UserData.dart';
  2. import 'package:chat/data/constants.dart';
  3. import 'package:chat/generated/i18n.dart';
  4. import 'package:chat/models/money_change.dart';
  5. import 'package:chat/utils/ChargeMoney.dart';
  6. import 'package:chat/utils/CustomUI.dart';
  7. import 'package:chat/utils/HttpUtil.dart';
  8. import 'package:chat/utils/MessageMgr.dart';
  9. import 'package:chat/utils/ShadowButton.dart';
  10. import 'package:chat/utils/TokenMgr.dart';
  11. import 'package:chat/utils/screen.dart';
  12. import 'package:dio/dio.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:oktoast/oktoast.dart';
  15. import 'package:provider/provider.dart';
  16. const double PaddingSize = 8;
  17. class VipPage extends StatefulWidget {
  18. VipPage({Key key}) : super(key: key);
  19. _VipPageState createState() => _VipPageState();
  20. }
  21. enum PayWay {
  22. wx,
  23. zfb,
  24. }
  25. class _VipPageState extends State<VipPage> with SingleTickerProviderStateMixin {
  26. TabController tabCtrl;
  27. List vipData = [];
  28. int selectId = 0;
  29. int selectMoney = 0;
  30. int payWay = PayWay.wx.index;
  31. bool isLoadingFish = false;
  32. bool isNormalVip = true;
  33. int subMoney = 0;
  34. List goodsList = [];
  35. Map memberInfo = {
  36. 'CheckNum': 0,
  37. 'PhotoOrAccount': 0,
  38. 'BurnTime': 0,
  39. 'PublishAd': 0,
  40. 'HumanTranslation': 0,
  41. 'ExclusiveCustomer': 0,
  42. 'PremiumUIDisplay': 0,
  43. };
  44. @override
  45. void initState() {
  46. super.initState();
  47. getVipInfo(1);
  48. }
  49. void getVipInfo(type) async {
  50. Map data = {
  51. "userid": UserData().basicInfo.userId,
  52. };
  53. data['sign'] = TokenMgr().getSign(data);
  54. data['type'] = type;
  55. Response res = await HttpUtil().post('goods/member/list',
  56. data: data, failback: () => Navigator.of(context).pop());
  57. Map resData = res.data;
  58. if (resData['code'] == 0 &&
  59. resData['data'] != null &&
  60. resData['data'].length > 0) {
  61. if (type == 2) subMoney = upgradNum(vipData, resData['data']['list']);
  62. memberInfo = resData['data']['memberInfo'];
  63. vipData = resData['data']['list'];
  64. selectId = vipData[0]['Id'];
  65. selectMoney = vipData[0]['TotalPrice'];
  66. isLoadingFish = true;
  67. isNormalVip = type == 1;
  68. setState(() {});
  69. }
  70. }
  71. @override
  72. void dispose() {
  73. super.dispose();
  74. }
  75. @override
  76. Widget build(BuildContext context) {
  77. Widget content = Scaffold(
  78. appBar: AppBar(
  79. backgroundColor: AppColors.NewAppbarBgColor,
  80. title: Text(
  81. I18n.of(context).member_centre,
  82. textScaleFactor: 1.0,
  83. style: TextStyle(color: AppColors.NewAppbarTextColor),
  84. ),
  85. centerTitle: true,
  86. leading: CustomUI.buildCustomLeading(context),
  87. ),
  88. body: SafeArea(
  89. child: Center(
  90. child: Container(
  91. height: MediaQuery.of(context).size.height,
  92. width: MediaQuery.of(context).size.width,
  93. child: _buildBody(),
  94. ),
  95. )));
  96. return CustomUI.buildPageLoading(context, content, !isLoadingFish);
  97. }
  98. Widget _buildBody() {
  99. return ListView(
  100. children: <Widget>[
  101. _buildTips(),
  102. _buildGoodsItemList(),
  103. _buildCommit(),
  104. ],
  105. );
  106. }
  107. //构建注册按钮
  108. Widget _buildCommit() {
  109. Text text = new Text(
  110. UserData().isVip
  111. ? I18n.of(context).renewal_fee
  112. : I18n.of(context).open_immediately,
  113. textScaleFactor: 1.0,
  114. style: TextStyle(fontSize: 17, color: Colors.white));
  115. LinearGradient gradientColor = new LinearGradient(colors: <Color>[
  116. Constants.ConfrimButtonColor,
  117. Constants.ConfrimButtonColor,
  118. ]);
  119. callback() {
  120. if (UserData().isSuperVip && isNormalVip) {
  121. showToast(I18n.of(context).cannot_vip);
  122. return;
  123. }
  124. if (UserData().isVip && !UserData().isSuperVip && !isNormalVip) {
  125. if (subMoney == 0) {
  126. return;
  127. }
  128. CustomUI.buildOneConfirm(
  129. context,
  130. I18n.of(context)
  131. .becomeSvip
  132. .replaceFirst('/s1', subMoney.toString()),
  133. I18n.of(context).determine, () {
  134. HttpUtil().buyVIP(subMoney, 0, 2, context, () {
  135. Navigator.of(context).pop();
  136. MessageMgr().emit('refresh_money');
  137. MessageMgr().emit('update_data');
  138. });
  139. });
  140. return;
  141. }
  142. if (Provider.of<MoneyChangeProvider>(context).money < selectMoney) {
  143. CustomUI.buildOneConfirm(context, I18n.of(context).balance_insufficien,
  144. I18n.of(context).recharge, () {
  145. Navigator.of(context).pop();
  146. ChargeMoney.showChargeSheet(context, () {
  147. setState(() {});
  148. });
  149. });
  150. return;
  151. }
  152. CustomUI.buildOneConfirm(
  153. context,
  154. I18n.of(context).confirm_pay +
  155. selectMoney.toString() +
  156. I18n.of(context).mask_coin,
  157. I18n.of(context).determine, () {
  158. HttpUtil().buyVIP(selectMoney, selectId, isNormalVip ? 1 : 2, context,
  159. () {
  160. Navigator.of(context).pop();
  161. MessageMgr().emit('refresh_money');
  162. MessageMgr().emit('update_data');
  163. });
  164. });
  165. }
  166. return Container(
  167. child: Column(
  168. children: <Widget>[
  169. Container(
  170. margin: EdgeInsets.only(left: 28),
  171. alignment: Alignment.centerLeft,
  172. child: RichText(
  173. text: TextSpan(children: [
  174. TextSpan(
  175. text: I18n.of(context).total,
  176. style: TextStyle(fontSize: 15.49, color: Colors.black),
  177. ),
  178. TextSpan(
  179. text: ' $selectMoney',
  180. style: TextStyle(
  181. color: const Color(0xFFE30101),
  182. fontSize: 16,
  183. fontWeight: FontWeight.normal),
  184. ),
  185. TextSpan(
  186. text: I18n.of(context).mask_coin,
  187. style:
  188. TextStyle(color: const Color(0xFFE30101), fontSize: 15))
  189. ]))),
  190. Container(
  191. margin: EdgeInsets.only(top: 21, left: 31, right: 31, bottom: 20),
  192. height: 44,
  193. child: ShadowButton().builder(gradientColor, text, callback),
  194. )
  195. ],
  196. ),
  197. );
  198. }
  199. // Widget _buildVerText(String str) {
  200. // List<Widget> child = [];
  201. // List list = str.split(' ');
  202. // list.forEach((str) {
  203. // child.add(Text(
  204. // str,
  205. // style: TextStyle(fontSize: 14, color: Constants.BlackTextColor),
  206. // ));
  207. // });
  208. // return Column(
  209. // mainAxisAlignment: MainAxisAlignment.center,
  210. // children: child,
  211. // );
  212. // }
  213. Widget _buildGoodsItem(month, money, oldMoney, leftTop, value) {
  214. bool isSelect = selectId == value['Id'];
  215. return InkWell(
  216. onTap: () {
  217. setState(() {
  218. selectId = value['Id'];
  219. selectMoney = value['TotalPrice'];
  220. });
  221. },
  222. child: Container(
  223. alignment: Alignment.center,
  224. height: 49.25,
  225. margin: EdgeInsets.only(bottom: 15, left: 12.5, right: 12.5),
  226. decoration: BoxDecoration(
  227. color: Colors.white,
  228. border: Border.all(
  229. width: 1,
  230. color: isSelect
  231. ? const Color(0xFF2D81FF)
  232. : const Color(0xFFC9C9C9)),
  233. boxShadow: [
  234. BoxShadow(
  235. color: isSelect
  236. ? const Color(0x7A2D81FF)
  237. : const Color(0x7ABCBCBC),
  238. offset: Offset(0, 5),
  239. blurRadius: 9,
  240. )
  241. ],
  242. borderRadius: BorderRadius.all(Radius.circular(10))),
  243. child: Stack(
  244. children: <Widget>[
  245. leftTop
  246. ? Positioned(
  247. left: 0,
  248. top: 0,
  249. child: Container(
  250. decoration: BoxDecoration(
  251. borderRadius: BorderRadius.only(
  252. topLeft: Radius.circular(9),
  253. bottomRight: Radius.circular(5)),
  254. gradient: LinearGradient(
  255. begin: Alignment.topCenter,
  256. end: Alignment.bottomCenter,
  257. colors: <Color>[
  258. const Color(0xFFCE0B0B),
  259. const Color(0xFFFF0000),
  260. ]),
  261. ),
  262. padding: EdgeInsets.only(left: 5, right: 5),
  263. child: Text(I18n.of(context).recommend,
  264. textScaleFactor: 1.0,
  265. style:
  266. TextStyle(fontSize: 13, color: Colors.white)),
  267. ))
  268. : Positioned(left: 0, top: 0, child: Container()),
  269. isSelect
  270. ? Positioned(
  271. right: -1,
  272. bottom: 0,
  273. child: Image.asset(
  274. 'assets/images/login/vip_rect2.png',
  275. ),
  276. width: 25,
  277. )
  278. : Positioned(
  279. right: 0,
  280. bottom: 0,
  281. child: Container(),
  282. ),
  283. Container(
  284. height: double.infinity,
  285. child: Row(
  286. mainAxisAlignment: MainAxisAlignment.end,
  287. children: <Widget>[
  288. Expanded(
  289. child: Container(
  290. alignment: Alignment.center,
  291. child: Row(
  292. crossAxisAlignment: CrossAxisAlignment.center,
  293. mainAxisAlignment: MainAxisAlignment.center,
  294. children: <Widget>[
  295. Text('$money',
  296. textScaleFactor: 1.0,
  297. style: TextStyle(
  298. color: const Color(0xFFE30101),
  299. fontSize: 22,
  300. fontWeight: FontWeight.normal)),
  301. Text('${I18n.of(context).mask_coin}',
  302. textScaleFactor: 1.0,
  303. style: TextStyle(
  304. color: const Color(0xFFE30101),
  305. fontSize: 20,
  306. fontWeight: FontWeight.normal)),
  307. ],
  308. )),
  309. ),
  310. Image.asset(
  311. 'assets/images/login/vip_rect3.png',
  312. height: 25,
  313. color: Colors.grey,
  314. ),
  315. Container(
  316. width: 110,
  317. alignment: Alignment.center,
  318. child: Text(month,
  319. textScaleFactor: 1.0,
  320. style: TextStyle(
  321. fontSize: 15, color: Constants.BlackTextColor)),
  322. ),
  323. ],
  324. ),
  325. )
  326. ],
  327. )));
  328. }
  329. Widget buildSelectContainer(str, bool isSelect, bool isNormalVip) {
  330. var color = Constants.BlackTextColor;
  331. return Container(
  332. alignment: Alignment.center,
  333. padding: EdgeInsets.only(bottom: isSelect ? 9 : 12),
  334. decoration: BoxDecoration(
  335. color: Colors.white,
  336. border: Border(
  337. bottom: BorderSide(
  338. color:
  339. isSelect ? const Color(0xFF2D81FF) : Colors.transparent,
  340. width: isSelect ? 4 : 1))),
  341. child: Row(
  342. mainAxisAlignment: MainAxisAlignment.center,
  343. children: <Widget>[
  344. Padding(
  345. padding: EdgeInsets.only(top: 0),
  346. child: Image.asset(
  347. isNormalVip
  348. ? 'assets/images/vip/hy_hy.png'
  349. : 'assets/images/vip/hy_cjhy.png',
  350. width: 18,
  351. ),
  352. ),
  353. SizedBox(width: 5),
  354. Text(str,
  355. textScaleFactor: 1.0,
  356. style: TextStyle(fontSize: 16, color: color))
  357. ],
  358. ),
  359. );
  360. }
  361. Widget _buildGoodsItemList() {
  362. Widget tip = Container(
  363. color: Colors.white,
  364. margin: EdgeInsets.only(bottom: 15),
  365. child: Row(
  366. mainAxisAlignment: MainAxisAlignment.spaceAround,
  367. children: <Widget>[
  368. InkWell(
  369. onTap: isNormalVip
  370. ? null
  371. : () {
  372. getVipInfo(1);
  373. },
  374. child: buildSelectContainer(
  375. I18n.of(context).member, isNormalVip, true)),
  376. InkWell(
  377. onTap: !isNormalVip
  378. ? null
  379. : () {
  380. getVipInfo(2);
  381. },
  382. child: buildSelectContainer(
  383. I18n.of(context).svip, !isNormalVip, false)),
  384. ],
  385. ));
  386. List<Widget> list = [tip];
  387. vipData.forEach((k) {
  388. var name = k['MonthValue'] == 0.5
  389. ? I18n.of(context).half_month
  390. : I18n.of(context)
  391. .month2
  392. .replaceFirst('/s1', k['MonthValue'].toInt().toString());
  393. list.add(_buildGoodsItem(
  394. name, k['TotalPrice'], 72, vipData.indexOf(k) == 0, k));
  395. });
  396. list.add(Container(
  397. height: 1,
  398. color: const Color(0xFFDADADA),
  399. margin: EdgeInsets.only(left: 14, right: 14, bottom: 13),
  400. ));
  401. return Container(
  402. child: Wrap(
  403. alignment: WrapAlignment.spaceEvenly,
  404. children: list,
  405. ),
  406. );
  407. }
  408. double subNum(data) {
  409. return data['MonthPrice'] / 30;
  410. }
  411. //补差价
  412. int upgradNum(vipList, sVipList) {
  413. if (UserData().memberEndTime == '') {
  414. return 0;
  415. }
  416. int day = 0;
  417. const moneyDay = 30;
  418. try {
  419. DateTime endTime = DateTime.parse(UserData().memberEndTime);
  420. day = endTime.difference(DateTime.now()).inDays;
  421. if (day < 0) {
  422. return 0;
  423. }
  424. //小于最小天数按最小天数补
  425. if (day < vipList[0]['MonthValue'] * moneyDay) {
  426. return (day * (subNum(sVipList[0]) - subNum(vipList[0]))).ceil();
  427. }
  428. //大于最大天数按最大天数补
  429. if (day > vipList[vipList.length - 1]['MonthValue'] * moneyDay) {
  430. return (day *
  431. (subNum(sVipList[vipList.length - 1]) -
  432. subNum(vipList[vipList.length - 1])))
  433. .ceil();
  434. }
  435. for (int i = 0; i < vipList.length; i++) {
  436. int standDay = (vipList[i]['MonthValue'] * moneyDay).ceil();
  437. if (day < standDay) {
  438. return (day * (subNum(sVipList[i - 1]) - subNum(vipList[i - 1])))
  439. .ceil();
  440. }
  441. }
  442. } catch (e) {}
  443. return 0;
  444. }
  445. Widget _buildTipItem(leftStr, rightStr, {isShow = true}) {
  446. var color = isShow ? Colors.white : Colors.white.withOpacity(0);
  447. return Container(
  448. margin: EdgeInsets.only(left: 39, right: 5),
  449. child: Row(
  450. children: <Widget>[
  451. Container(
  452. margin: EdgeInsets.only(right: 20.5),
  453. child: Text(
  454. leftStr,
  455. textScaleFactor: 1.0,
  456. style: TextStyle(
  457. color: color, fontSize: 11.44, fontWeight: FontWeight.w600),
  458. ),
  459. ),
  460. Expanded(
  461. child: Container(
  462. padding: EdgeInsets.only(right: 5),
  463. child: Text(
  464. rightStr,
  465. textScaleFactor: 1.0,
  466. style: TextStyle(
  467. color: color,
  468. fontSize: 10.4,
  469. ),
  470. ),
  471. )),
  472. ],
  473. ),
  474. );
  475. }
  476. Widget _buildTips() {
  477. Widget tip = Container(
  478. margin: EdgeInsets.only(left: PaddingSize, right: PaddingSize),
  479. padding: EdgeInsets.only(top: 9, left: 12, bottom: 10),
  480. child: Row(
  481. children: <Widget>[
  482. Image.asset(
  483. 'assets/images/vip/hy_tq.png',
  484. width: 16,
  485. ),
  486. Text(
  487. I18n.of(context).members_privilege,
  488. textScaleFactor: 1.0,
  489. style: TextStyle(color: Colors.white, fontSize: 13.54),
  490. ),
  491. ],
  492. ));
  493. return Container(
  494. color: Colors.white,
  495. width: Screen.width,
  496. child: Stack(
  497. children: <Widget>[
  498. Container(
  499. color: Colors.white,
  500. margin: EdgeInsets.only(left: PaddingSize, right: PaddingSize),
  501. alignment: Alignment.center,
  502. child: Image.asset(
  503. 'assets/images/vip/hy_bg.png',
  504. fit: BoxFit.fitWidth,
  505. ),
  506. ),
  507. // Container(
  508. // height: 150,
  509. // margin: EdgeInsets.only(top:5,left: PaddingSize, right: PaddingSize),
  510. // alignment: Alignment.center,
  511. // child: Text(''),
  512. // decoration: BoxDecoration(
  513. // borderRadius: BorderRadius.circular(12),
  514. // gradient: LinearGradient(
  515. // begin: Alignment.centerLeft,
  516. // end: Alignment.centerRight,
  517. // colors: [Color(0xffff9186), Color(0xffff5599)],
  518. //
  519. // )),
  520. // ),
  521. Positioned(
  522. child: Container(
  523. height: (Screen.width - PaddingSize * 2) / 2.18,
  524. padding: EdgeInsets.only(bottom: 15),
  525. child: Column(
  526. mainAxisAlignment: MainAxisAlignment.spaceAround,
  527. crossAxisAlignment: CrossAxisAlignment.start,
  528. children: <Widget>[
  529. tip,
  530. _buildTipItem(I18n.of(context).see_more,
  531. I18n.of(context).unlimited_see),
  532. _buildTipItem(
  533. I18n.of(context).see_cheaper,
  534. I18n.of(context).free10.replaceFirst('/s1',
  535. memberInfo['PhotoOrAccount'].toString())),
  536. _buildTipItem(
  537. I18n.of(context).see_longer,
  538. I18n.of(context).towto6.replaceFirst('/s1',
  539. (memberInfo['BurnTime'] + 2).toString())),
  540. _buildTipItem(
  541. I18n.of(context).see_better,
  542. I18n.of(context).free_program.replaceFirst(
  543. '/s1', memberInfo['PublishAd'].toString())),
  544. _buildTipItem(I18n.of(context).right5,
  545. I18n.of(context).free_translate,
  546. isShow: !isNormalVip),
  547. _buildTipItem(I18n.of(context).right6,
  548. I18n.of(context).personalTraff,
  549. isShow: !isNormalVip),
  550. ],
  551. ))),
  552. ],
  553. ));
  554. }
  555. }