Hibok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

433 lines
13 KiB

  1. import 'dart:async';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:chat/data/UserData.dart';
  4. import 'package:chat/data/WebData.dart';
  5. import 'package:chat/data/constants.dart';
  6. import 'package:chat/data/conversation.dart';
  7. import 'package:chat/generated/i18n.dart';
  8. import 'package:chat/home/InfoList.dart';
  9. import 'package:chat/home/ProfilePage.dart';
  10. import 'package:chat/home/rich_title.dart';
  11. import 'package:chat/utils/CustomUI.dart';
  12. import 'package:chat/utils/HttpUtil.dart';
  13. import 'package:chat/utils/TokenMgr.dart';
  14. import 'package:dio/dio.dart';
  15. import 'package:flutter/cupertino.dart';
  16. import 'package:flutter/material.dart';
  17. import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
  18. import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx;
  19. import 'package:oktoast/oktoast.dart';
  20. import 'package:pull_to_refresh/pull_to_refresh.dart';
  21. class _ConversationItem extends StatelessWidget {
  22. const _ConversationItem(
  23. {Key key,
  24. this.conversation,
  25. this.callback,
  26. this.showRight = true,
  27. this.rightButton,
  28. this.showReturn = false,
  29. this.applyInfo,
  30. this.bgColor,
  31. this.isInCome = false,
  32. this.money,
  33. this.title})
  34. : assert(conversation != null),
  35. super(key: key);
  36. final Widget rightButton;
  37. final Conversation conversation;
  38. final callback;
  39. final int money;
  40. final bool showRight;
  41. final title;
  42. final applyInfo;
  43. final bgColor;
  44. final bool showReturn;
  45. final bool isInCome;
  46. @override
  47. Widget build(BuildContext context) {
  48. Widget avatar;
  49. double width = 44.55;
  50. if (conversation.isAvatarFromNet()) {
  51. avatar = ClipRRect(
  52. borderRadius: BorderRadius.circular(10),
  53. child: CachedNetworkImage(
  54. imageUrl: conversation.avatar,
  55. placeholder: (context, url) => Image.asset(
  56. Constants.DefaultHeadImgUrl,
  57. width: width,
  58. height: width,
  59. ),
  60. fit: BoxFit.cover,
  61. width: width,
  62. height: width,
  63. ));
  64. } else {
  65. avatar = ClipRRect(
  66. borderRadius: BorderRadius.circular(10),
  67. child: Container(
  68. width: width,
  69. height: width,
  70. alignment: Alignment.center,
  71. decoration: BoxDecoration(
  72. gradient: this.bgColor,
  73. borderRadius: BorderRadius.all(Radius.circular(50))),
  74. child: Image.asset(
  75. conversation.avatar,
  76. height: 27,
  77. )));
  78. }
  79. return InkWell(
  80. child: Container(
  81. padding:
  82. const EdgeInsets.only(left: 21, top: 12.5, bottom: 12.5, right: 24.5),
  83. decoration: BoxDecoration(
  84. color: Color(AppColors.ConversationItemBgColor),
  85. border: Border(
  86. bottom: BorderSide(
  87. color: AppColors.DividerColor,
  88. width: Constants.DividerWidth))),
  89. child: Row(
  90. crossAxisAlignment: CrossAxisAlignment.center,
  91. children: <Widget>[
  92. avatar,
  93. Container(width: 14.0),
  94. Expanded(
  95. child: Container(
  96. padding: EdgeInsets.only(top: 3),
  97. child: Column(
  98. crossAxisAlignment: CrossAxisAlignment.start,
  99. children: <Widget>[
  100. Container(
  101. child: title == null
  102. ? Text(conversation.title,
  103. textScaleFactor: 1.0,
  104. style: TextStyle(
  105. fontSize: 11,
  106. color: Constants.LightGreyTextColor))
  107. : title),
  108. Container(
  109. padding: EdgeInsets.only(top: 10),
  110. child: Text(conversation.desc,
  111. textScaleFactor: 1.0,
  112. style: TextStyle(
  113. fontSize: 11, color: Constants.LightGreyTextColor)),
  114. )
  115. ],
  116. ),
  117. )),
  118. Container(
  119. height: width,
  120. margin: EdgeInsets.only(left: 10),
  121. child: Column(
  122. crossAxisAlignment: CrossAxisAlignment.end,
  123. mainAxisAlignment: MainAxisAlignment.center,
  124. children: <Widget>[
  125. Text(
  126. '${money > 0 ? '+' : ''}${this.isInCome ? money * 1000 : (money.toString() + I18n.of(context).mask_coin)}',
  127. style: TextStyle(
  128. fontSize: 14,
  129. fontWeight: FontWeight.w500,
  130. color:
  131. money > 0 ? Color(0xFFFE4624) : Color(0xFF5498FF)),
  132. ),
  133. showReturn
  134. ? Padding(
  135. padding: EdgeInsets.only(top: 3),
  136. child: Text(
  137. I18n.of(context).alreay_back,
  138. style: TextStyle(
  139. fontSize: 12,
  140. fontWeight: FontWeight.normal,
  141. color: Constants.BlackTextColor),
  142. ))
  143. : Container()
  144. ],
  145. ),
  146. alignment: Alignment.center,
  147. ),
  148. ],
  149. ),
  150. ),
  151. onTap: () {
  152. callback();
  153. },
  154. );
  155. }
  156. }
  157. class MoneyDetailPage extends StatefulWidget {
  158. final int type;
  159. MoneyDetailPage({Key key, this.type}) : super(key: key);
  160. MoneyDetailPageState createState() => MoneyDetailPageState();
  161. }
  162. class MoneyDetailPageState extends State<MoneyDetailPage>
  163. with SingleTickerProviderStateMixin {
  164. List list = new List(); //列表要展示的数据
  165. RefreshController _refreshController =
  166. RefreshController(initialRefresh: true);
  167. int _page = 1; //加载的页数
  168. int rows = 20;
  169. TabController tabCtrl;
  170. var bindAccount;
  171. @override
  172. void initState() {
  173. super.initState();
  174. tabCtrl = TabController(length: 2, vsync: this);
  175. fluwx.responseFromPayment.listen((data) {
  176. if (data.errCode == 0) {
  177. Navigator.of(context).pop();
  178. setState(() {});
  179. showToast(I18n.of(context).payment_successful);
  180. }
  181. });
  182. }
  183. void addList(data) {
  184. if (data == null || data.length == 0) {
  185. _page--;
  186. _refreshController.loadNoData();
  187. } else {
  188. list.addAll(data);
  189. _refreshController.loadComplete();
  190. }
  191. setState(() {});
  192. }
  193. void _onLoading() async {
  194. _page++;
  195. getNewData(addList);
  196. }
  197. @override
  198. void dispose() {
  199. tabCtrl.dispose();
  200. _refreshController.dispose();
  201. if (_conectionSubscription != null) {
  202. _conectionSubscription.cancel();
  203. _conectionSubscription = null;
  204. }
  205. if (_purchaseUpdatedSubscription != null) {
  206. _purchaseUpdatedSubscription.cancel();
  207. _purchaseUpdatedSubscription = null;
  208. }
  209. if (_purchaseErrorSubscription != null) {
  210. _purchaseErrorSubscription.cancel();
  211. _purchaseErrorSubscription = null;
  212. }
  213. super.dispose();
  214. }
  215. @override
  216. Widget build(BuildContext context) {
  217. Widget content = Scaffold(
  218. resizeToAvoidBottomPadding: false,
  219. appBar: AppBar(
  220. leading: CustomUI.buildCustomLeading(context),
  221. backgroundColor: AppColors.NewAppbarBgColor,
  222. title: Text(
  223. widget.type == 1
  224. ? I18n.of(context).my_money_info
  225. : I18n.of(context).get_money_detail,
  226. textScaleFactor: 1.0,
  227. ),
  228. centerTitle: true,
  229. ),
  230. body: SafeArea(child: showCoin()),
  231. );
  232. return content;
  233. //return CustomUI.buildPageLoading(context, content, !isLoadingFish);
  234. }
  235. Widget showCoin() {
  236. return Scaffold(
  237. body: SafeArea(
  238. child: Center(
  239. child: Container(
  240. height: MediaQuery.of(context).size.height,
  241. width: MediaQuery.of(context).size.width,
  242. child: _buildCoinBody(),
  243. ),
  244. )));
  245. }
  246. void _onRefresh() async {
  247. _page = 1;
  248. getNewData(initList);
  249. }
  250. void initList(data) {
  251. list.clear();
  252. if (data != null) {
  253. list.addAll(data);
  254. }
  255. setState(() {});
  256. }
  257. getNewData(callback) async {
  258. Map data = {
  259. "userId": UserData().basicInfo.userId,
  260. 'type': widget.type,
  261. };
  262. data['sign'] = TokenMgr().getSign(data);
  263. data["page"] = _page;
  264. data['rows'] = rows;
  265. Response res = await HttpUtil().post('wallet/balance/detail', data: data);
  266. var resData = res.data;
  267. _refreshController.refreshCompleted();
  268. print(resData);
  269. if (resData['code'] == 0) {
  270. callback(resData['data']);
  271. } else {
  272. showToast(resData['msg']);
  273. }
  274. }
  275. bool isAdd(int type) {
  276. if (widget.type == 1) {
  277. return type == 1 ||
  278. type == 2 ||
  279. type == 3 ||
  280. type == 12 ||
  281. type == 13 ||
  282. type == 14;
  283. } else {
  284. return !(type == 1 || type == 2);
  285. }
  286. }
  287. //钱包通知
  288. Widget _buildMoneyInfo(data) {
  289. String imgUrl = data['HeadImg'] == null ||
  290. data['HeadImg'] == '' ||
  291. data['ChangeUserId'] == 0
  292. ? UserData().basicInfo.headimgurl
  293. : data['HeadImg'];
  294. return _ConversationItem(
  295. conversation: Conversation(
  296. avatar: imgUrl,
  297. title: '',
  298. desc: WebData().getLoginTime(context, data['CreateTime']),
  299. updateAt: '',
  300. ),
  301. bgColor: Constants.MoneyGradient,
  302. isInCome: widget.type == 2,
  303. money: isAdd(data['DetailType']) ? data['Value'] : -data['Value'],
  304. title: RichTitle.getRichTitleWidget(data, context,
  305. widget.type == 1 ? InfoType.MyMoney : InfoType.IncomeMoney,
  306. titleStyle: TextStyle(fontSize: 12, color: const Color(0XFF7F7F7F)),
  307. nameStyle: TextStyle(
  308. fontWeight: FontWeight.normal,
  309. fontSize: 13,
  310. color: Constants.BlackTextColor)),
  311. callback: () {
  312. if (data['ChangeUserId'] != 0) {
  313. Navigator.of(context).push(
  314. new MaterialPageRoute(
  315. builder: (context) {
  316. return ProfilePage(
  317. userId: data['UserId'] == UserData().basicInfo.userId
  318. ? data['ChangeUserId']
  319. : data['UserId'],
  320. );
  321. },
  322. ),
  323. );
  324. }
  325. },
  326. );
  327. }
  328. Widget _renderRow(BuildContext context, int index) {
  329. if (index < list.length) {
  330. var userInfo = list[index];
  331. Widget result = _buildMoneyInfo(userInfo);
  332. if (index == 0) {
  333. result = Padding(padding: EdgeInsets.only(top: 10), child: result);
  334. }
  335. return result;
  336. }
  337. return Container();
  338. }
  339. Widget _buildCoinBody() {
  340. return SmartRefresher(
  341. enablePullDown: true,
  342. enablePullUp: true,
  343. header: MaterialClassicHeader(),
  344. footer: CustomUI.buildLoadingFooter(),
  345. controller: _refreshController,
  346. onRefresh: _onRefresh,
  347. onLoading: _onLoading,
  348. child: (_refreshController.headerStatus == RefreshStatus.completed &&
  349. list.length == 0)
  350. ? CustomUI.buildNoData(context)
  351. : ListView.builder(
  352. itemBuilder: _renderRow,
  353. itemCount: list.length,
  354. ),
  355. );
  356. }
  357. static String currentGoodsId = '';
  358. static StreamSubscription _conectionSubscription,
  359. _purchaseUpdatedSubscription,
  360. _purchaseErrorSubscription;
  361. ///ios 内购初始化
  362. static Future initPayConf(BuildContext context) async {
  363. if (_purchaseErrorSubscription != null) {
  364. return;
  365. }
  366. // prepare
  367. print('initPayConf -------- start: ');
  368. var result = await FlutterInappPurchase.instance.initConnection;
  369. print('initPayConf -------- result: $result');
  370. FlutterInappPurchase.instance.clearTransactionIOS();
  371. _conectionSubscription =
  372. FlutterInappPurchase.connectionUpdated.listen((connected) {
  373. print('connected: $connected');
  374. });
  375. _purchaseUpdatedSubscription =
  376. FlutterInappPurchase.purchaseUpdated.listen((productItem) {
  377. print('支付成功,成功回调 ------ purchase-updated: $productItem');
  378. // showToast('支付成功,成功回调 ------ purchase-updated: $productItem');
  379. if (productItem.transactionReceipt != null &&
  380. productItem.transactionReceipt.isNotEmpty) {
  381. HttpUtil().createOrder(currentGoodsId, productItem.transactionReceipt,
  382. productItem.purchaseToken,
  383. context: context);
  384. showToast(I18n.of(context).payment_successful);
  385. }
  386. Navigator.of(context).pop();
  387. });
  388. _purchaseErrorSubscription =
  389. FlutterInappPurchase.purchaseError.listen((purchaseError) {
  390. // showToast('支付失败回调 -------- purchase-error: $purchaseError');
  391. FlutterInappPurchase.instance.clearTransactionIOS();
  392. Navigator.of(context).pop();
  393. });
  394. }
  395. }