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.
 
 
 
 
 
 

1318 lines
49 KiB

  1. import 'dart:io';
  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/generated/i18n.dart';
  7. import 'package:chat/home/VerificationCenter.dart';
  8. import 'package:chat/home/VipPage.dart';
  9. import 'package:chat/home/realtimehelper/translation_evaluation_dialog.dart';
  10. import 'package:chat/home/realtimehelper/translation_order_push_dialog.dart';
  11. import 'package:chat/models/group_info_model.dart';
  12. import 'package:chat/photo/ui/dialog/not_permission_dialog.dart';
  13. import 'package:chat/utils/LoadingDialog.dart';
  14. import 'package:chat/utils/TokenMgr.dart';
  15. import 'package:chat/utils/screen.dart';
  16. import 'package:dio/dio.dart';
  17. import 'package:flutter/cupertino.dart';
  18. import 'package:flutter/material.dart';
  19. import 'package:flutter/painting.dart';
  20. import 'package:flutter/services.dart';
  21. import 'package:oktoast/oktoast.dart';
  22. import 'package:permission_handler/permission_handler.dart';
  23. import 'package:pull_to_refresh/pull_to_refresh.dart';
  24. import 'package:url_launcher/url_launcher.dart';
  25. import 'dart:ui' as ui;
  26. import '../r.dart';
  27. import 'HttpUtil.dart';
  28. import 'PicSwiper.dart';
  29. import 'TutorialOverlay.dart';
  30. import 'app_navigator.dart';
  31. import 'conversation_table.dart';
  32. class NoKeyboardEditableTextFocusNode extends FocusNode {
  33. // @override
  34. // bool consumeKeyboardToken() {
  35. // return false;
  36. // }
  37. }
  38. class CustomUI {
  39. static Widget buildPageLoading(
  40. BuildContext context, Widget content, bool isShow) {
  41. return Stack(
  42. children: <Widget>[
  43. content,
  44. isShow
  45. ? Scaffold(
  46. backgroundColor: Colors.transparent,
  47. body: LoadingDialog(),
  48. )
  49. : Container(),
  50. ],
  51. );
  52. }
  53. static void showContentDialog(
  54. BuildContext context, int programId, int replyId, int type, callback,
  55. {int replyUserId = 0,
  56. String replyUserName = '',
  57. bool isAd = false,
  58. bool isMyself = false}) {
  59. if (UserData().isMan() && !UserData().isVip && !isMyself) {
  60. CustomUI.buildOneConfirm(
  61. context, I18n.of(context).cant_comment, I18n.of(context).joinvip, () {
  62. Navigator.of(context).pop();
  63. Navigator.of(context).push(
  64. new MaterialPageRoute(
  65. builder: (context) {
  66. return VipPage();
  67. },
  68. ),
  69. );
  70. });
  71. return;
  72. }
  73. if (!UserData().isMan() && !UserData().basicInfo.isAttestation) {
  74. buildNotTrue(context);
  75. return;
  76. }
  77. Navigator.of(context).push(TutorialOverlay(
  78. child: Scaffold(
  79. backgroundColor: Constants.BlackTextColor.withOpacity(0.0),
  80. body: buildInput(context, programId, replyId, type, callback,
  81. replyUserId: replyUserId,
  82. replyUserName: replyUserName,
  83. isAd: isAd,
  84. isMyself: isMyself))));
  85. }
  86. static Widget buildInput(
  87. BuildContext context, int programId, int replyId, int type, callback,
  88. {int replyUserId = 0,
  89. String replyUserName = '',
  90. bool isAd: false,
  91. bool isMyself: false}) {
  92. print('replyUserName $replyUserName');
  93. var content = '';
  94. var hitStr = isMyself
  95. ? I18n.of(context).everyone_comment
  96. : I18n.of(context).your_comment;
  97. Widget input = Container(
  98. alignment: Alignment.topCenter,
  99. padding: EdgeInsets.only(left: 10, right: 10, bottom: 2),
  100. color: Colors.white,
  101. child: Row(
  102. children: <Widget>[
  103. Flexible(
  104. child: Container(
  105. margin: EdgeInsets.only(bottom: 10, right: 10),
  106. decoration: BoxDecoration(
  107. border: Border(
  108. bottom: BorderSide(color: const Color(0xFF0368FF)))),
  109. child: TextField(
  110. keyboardAppearance: Brightness.light,
  111. maxLines: 3,
  112. minLines: 1,
  113. style: TextStyle(textBaseline: TextBaseline.alphabetic),
  114. autofocus: true,
  115. inputFormatters: <TextInputFormatter>[
  116. LengthLimitingTextInputFormatter(30) //限制长度
  117. ],
  118. decoration: new InputDecoration(
  119. hintText: hitStr,
  120. hintMaxLines: 1,
  121. hintStyle: TextStyle(fontSize: 15),
  122. border: InputBorder.none,
  123. ),
  124. onChanged: (str) {
  125. content = str;
  126. },
  127. )),
  128. ),
  129. RaisedButton(
  130. color: const Color(0xFF0368FF),
  131. child: Text(
  132. I18n.of(context).send,
  133. textScaleFactor: 1.0,
  134. style: TextStyle(color: Colors.white),
  135. ),
  136. onPressed: () async {
  137. content = content.trim();
  138. if (content == '' || content == null) {
  139. return;
  140. }
  141. if (isAd) {
  142. Map rdata = {
  143. "userId": UserData().basicInfo.userId,
  144. "adId": programId,
  145. };
  146. rdata['sign'] = TokenMgr().getSign(rdata);
  147. rdata['content'] = content;
  148. Response res = await HttpUtil().post(
  149. 'adActivity/reply/evaluate',
  150. data: rdata,
  151. isShowLoading: true);
  152. var resData = res.data;
  153. var data = {
  154. 'Pid': resData['data'],
  155. 'UserId': UserData().basicInfo.userId,
  156. 'NickName': UserData().basicInfo.nickName,
  157. 'Type': type,
  158. 'ReplyUserId': replyUserId,
  159. 'ReplyNickName': replyUserName,
  160. 'Content': content
  161. };
  162. showToast(resData['msg']);
  163. if (resData['code'] == 0) {
  164. Navigator.of(context).pop();
  165. callback(data);
  166. }
  167. } else {
  168. Map rdata = {
  169. "userId": UserData().basicInfo.userId,
  170. "id": programId,
  171. "type": type,
  172. };
  173. rdata['sign'] = TokenMgr().getSign(rdata);
  174. rdata['content'] = content;
  175. rdata['replyId'] = replyId;
  176. Response res = await HttpUtil().post('station/reply/comment',
  177. data: rdata, isShowLoading: true);
  178. var resData = res.data;
  179. print('station/reply/comment $resData');
  180. var data = {
  181. 'Pid': resData['data'],
  182. 'UserId': UserData().basicInfo.userId,
  183. 'NickName': UserData().basicInfo.nickName,
  184. 'Type': type,
  185. 'ReplyUserId': replyUserId,
  186. 'ReplyNickName': replyUserName,
  187. 'Content': content
  188. };
  189. showToast(resData['msg']);
  190. if (resData['code'] == 0) {
  191. Navigator.of(context).pop();
  192. callback(data);
  193. }
  194. }
  195. },
  196. )
  197. ],
  198. ),
  199. );
  200. Widget button = Expanded(
  201. child: InkWell(
  202. highlightColor: Colors.transparent,
  203. radius: 0,
  204. onTap: () {
  205. Navigator.pop(context);
  206. },
  207. ),
  208. );
  209. return Column(
  210. mainAxisAlignment: MainAxisAlignment.end,
  211. children: <Widget>[
  212. button,
  213. input,
  214. ],
  215. );
  216. }
  217. static void buildNotTrue(BuildContext context) {
  218. buildOneConfirm(context, I18n.of(context).after_authenticate,
  219. I18n.of(context).authenticate_now, () {
  220. Navigator.pop(context);
  221. Navigator.of(context).push(
  222. new MaterialPageRoute(
  223. builder: (context) {
  224. return VerificationCenterPage();
  225. },
  226. ),
  227. );
  228. });
  229. }
  230. static Widget buildCancleBotton(title, callback) {
  231. return InkWell(
  232. onTap: callback,
  233. child: Container(
  234. decoration: BoxDecoration(
  235. color: const Color(0XFFC7E5FF),
  236. borderRadius: BorderRadius.all(
  237. Radius.circular(Constants.LittleButtonRadius))),
  238. margin: EdgeInsets.only(top: 0, bottom: 18.5),
  239. height: 37.5,
  240. width: 200,
  241. alignment: Alignment.center,
  242. child: fixedText(
  243. title,
  244. fontSize: 15,
  245. color: const Color(0xFF5781A6),
  246. )),
  247. );
  248. }
  249. static Widget _buildContentTip(tipTitle) {
  250. return tipTitle == ''
  251. ? Container()
  252. : Container(
  253. padding: EdgeInsets.only(top: 38.5, bottom: 31.5),
  254. child: Text(
  255. tipTitle,
  256. textScaleFactor: 1.0,
  257. style: TextStyle(
  258. fontSize: 14, color: Constants.BlackTextColor, height: 1.30),
  259. textAlign: TextAlign.center,
  260. ));
  261. }
  262. static Widget buildConfirmContent(tip, content) {
  263. return Container(
  264. padding: EdgeInsets.only(left: 40, right: 40),
  265. child: Column(
  266. children: <Widget>[tip, content],
  267. ),
  268. );
  269. }
  270. static Widget buildImgLoding(context, url) {
  271. return Center(
  272. child: CircularProgressIndicator(
  273. valueColor: AlwaysStoppedAnimation(Constants.BlueTextColor)));
  274. }
  275. static Widget buildConfirmBotton(title, callback) {
  276. return InkWell(
  277. onTap: callback,
  278. child: Container(
  279. decoration: Constants.ConfirmBUttonBoxDecoration,
  280. height: 37.5,
  281. width: 200,
  282. alignment: Alignment.center,
  283. child: fixedText(
  284. title,
  285. fontSize: 15,
  286. color: Colors.white,
  287. )),
  288. );
  289. }
  290. static void buildOneConfirm(
  291. BuildContext context, String tipTitle, String buttonTitle, callback,
  292. {title = '', failcallbak}) {
  293. var confirm = buildConfirmBotton(buttonTitle, callback);
  294. buildTip(context, title,
  295. buildConfirmContent(_buildContentTip(tipTitle), confirm),
  296. failcallbak: failcallbak);
  297. }
  298. static void buildContacts(
  299. BuildContext context, String tipTitle, String buttonTitle, callback,
  300. {title = '', failcallbak}) {
  301. var confirm = buildConfirmBotton(buttonTitle, callback);
  302. buildTip(
  303. context,
  304. title,
  305. buildConfirmContent(
  306. Container(
  307. alignment: Alignment.center,
  308. padding: EdgeInsets.only(top: 38.5, bottom: 31.5),
  309. child: Column(
  310. children: <Widget>[
  311. Text(
  312. tipTitle,
  313. textScaleFactor: 1.0,
  314. style: TextStyle(
  315. fontSize: 14,
  316. color: Constants.BlackTextColor,
  317. height: 1.30),
  318. textAlign: TextAlign.center,
  319. ),
  320. SizedBox(
  321. height: 5,
  322. ),
  323. GestureDetector(
  324. child: Text(
  325. I18n.of(context).privacy,
  326. style: TextStyle(color: Colors.blue, fontSize: 14),
  327. ),
  328. onTap: () {
  329. launch(
  330. 'http://datechatagent.chengyouhd.com/zh-CN/Home/Privacy?language=${UserData().language}');
  331. },
  332. )
  333. ],
  334. )),
  335. confirm),
  336. failcallbak: failcallbak);
  337. }
  338. static Widget buildNoData(BuildContext context, {String str, double height}) {
  339. if (height == null) {
  340. height = MediaQuery.of(context).size.height * 0.8;
  341. }
  342. return Container(
  343. width: MediaQuery.of(context).size.width,
  344. height: height,
  345. alignment: Alignment.center,
  346. child: Column(
  347. crossAxisAlignment: CrossAxisAlignment.center,
  348. mainAxisAlignment: MainAxisAlignment.center,
  349. children: <Widget>[
  350. Container(
  351. child: Icon(
  352. IconData(
  353. 0xe869,
  354. fontFamily: 'iconfont',
  355. ),
  356. size: 60,
  357. color: Constants.BlueTextColor,
  358. )),
  359. Container(
  360. alignment: Alignment.center,
  361. child: fixedText(str != null ? str : I18n.of(context).no_data,
  362. color: Constants.BlueTextColor)),
  363. ],
  364. ));
  365. }
  366. static Widget buildImgCover(int imgId, List pics, String imgUrl, double width,
  367. double raduis, bool isWatch, BuildContext context, int type,
  368. {bool isMyself = false, int payStatus = 0, int state = 1}) {
  369. Color color = isWatch
  370. ? const Color(0xFF999999)
  371. : const Color(0xFFFB5656); //const Color(0xfffb5656);
  372. String bottomStr = '';
  373. if (type == PhotoType.money.index) {
  374. bottomStr = I18n.of(context).red_photo;
  375. } else if (type == PhotoType.destroyMoney.index) {
  376. bottomStr = I18n.of(context).red_photo; //I18n.of(context).red_photo1;
  377. } else if (type == PhotoType.destroy.index) {
  378. bottomStr =
  379. isWatch ? I18n.of(context).destroyed : I18n.of(context).destroy_after;
  380. }
  381. double opacity = 0.5;
  382. Widget normalCover = isMyself && state == 0
  383. ? Positioned(
  384. right: 5,
  385. top: 5,
  386. child: Container(
  387. alignment: Alignment.center,
  388. width: width,
  389. height: width,
  390. decoration: BoxDecoration(
  391. color: Colors.black.withOpacity(opacity),
  392. borderRadius: BorderRadius.all(Radius.circular(raduis - 2))),
  393. child: Text(I18n.of(context).reviewing,
  394. textAlign: TextAlign.center,
  395. textScaleFactor: 1.0,
  396. style: TextStyle(fontSize: 12, color: Colors.white)),
  397. ),
  398. )
  399. : Container(
  400. width: width,
  401. height: width,
  402. decoration: BoxDecoration(
  403. border: Border.all(color: Colors.grey[300], width: 1),
  404. borderRadius: BorderRadius.circular(raduis)),
  405. );
  406. return InkWell(
  407. onTap: () {
  408. Navigator.of(context).push(
  409. new MaterialPageRoute(
  410. builder: (context) {
  411. return PicSwiper(
  412. id: imgId,
  413. pics: pics,
  414. );
  415. },
  416. ),
  417. );
  418. },
  419. child: Stack(
  420. alignment: Alignment.center,
  421. children: <Widget>[
  422. Container(
  423. decoration:
  424. BoxDecoration(borderRadius: BorderRadius.circular(2.0)),
  425. width: width,
  426. height: width,
  427. margin: EdgeInsets.all(5),
  428. child: ClipRRect(
  429. borderRadius: BorderRadius.circular(raduis),
  430. child: CachedNetworkImage(
  431. imageUrl: imgUrl == null ? "" : imgUrl,
  432. placeholder: CustomUI.buildImgLoding,
  433. fit: BoxFit.cover,
  434. ),
  435. )),
  436. (type == PhotoType.free.index ||
  437. (!isMyself &&
  438. type == PhotoType.money.index &&
  439. payStatus == 1))
  440. ? normalCover
  441. : Stack(
  442. alignment: Alignment.center,
  443. children: <Widget>[
  444. Container(
  445. width: width,
  446. height: width,
  447. decoration: BoxDecoration(
  448. border: Border.all(color: color, width: 1),
  449. borderRadius: BorderRadius.circular(raduis),
  450. ),
  451. margin: EdgeInsets.all(5),
  452. child: ClipRRect(
  453. borderRadius: BorderRadius.circular(raduis),
  454. child: BackdropFilter(
  455. //背景滤镜器
  456. filter: ui.ImageFilter.blur(
  457. sigmaX: 10.0,
  458. sigmaY: 10.0), //图片模糊过滤,横向竖向都设置5.0
  459. child: Opacity(
  460. //透明控件
  461. opacity: isMyself ? 0 : 0.5,
  462. child: Container(
  463. decoration: BoxDecoration(
  464. border: Border.all(color: color, width: 0),
  465. borderRadius: BorderRadius.circular(0),
  466. ),
  467. alignment: Alignment.center,
  468. ),
  469. ),
  470. )),
  471. ),
  472. isMyself && state == 0
  473. ? Positioned(
  474. right: 6,
  475. top: 6,
  476. child: Container(
  477. alignment: Alignment.center,
  478. width: width - 2,
  479. height: width - 2,
  480. decoration: BoxDecoration(
  481. color: Colors.black.withOpacity(opacity),
  482. borderRadius: BorderRadius.all(
  483. Radius.circular(raduis - 1))),
  484. child: Text(I18n.of(context).reviewing,
  485. textScaleFactor: 1.0,
  486. style: TextStyle(
  487. fontSize: 12, color: Colors.white)),
  488. ),
  489. )
  490. : Text(''),
  491. Positioned(
  492. left: 0,
  493. top: 0,
  494. child: Container(
  495. width: 18,
  496. height: 18,
  497. margin: EdgeInsets.all(5),
  498. decoration: BoxDecoration(
  499. color: color,
  500. borderRadius: BorderRadius.only(
  501. topLeft: Radius.circular(raduis),
  502. bottomRight: Radius.circular(raduis))),
  503. child: Icon(
  504. IconData(
  505. type == PhotoType.money.index ? 0xe632 : 0xe634,
  506. fontFamily: 'iconfont',
  507. ),
  508. color: Colors.white,
  509. size: 15,
  510. ),
  511. ),
  512. ),
  513. Positioned(
  514. bottom: 6,
  515. child: Container(
  516. width: width - 2,
  517. padding: EdgeInsets.only(
  518. bottom: 1, top: 2, left: 5, right: 5),
  519. decoration: isMyself
  520. ? BoxDecoration(
  521. color: Colors.red.withOpacity(0.7),
  522. borderRadius: BorderRadius.only(
  523. bottomLeft: Radius.circular(raduis - 1),
  524. bottomRight:
  525. Radius.circular(raduis - 1)))
  526. : BoxDecoration(),
  527. child: Text(bottomStr,
  528. textScaleFactor: 1.0,
  529. textAlign: TextAlign.center,
  530. style: TextStyle(
  531. color: isMyself ? Colors.white : color,
  532. fontSize: 10)),
  533. )),
  534. ],
  535. ),
  536. ],
  537. ));
  538. }
  539. static void buildTowConfirm(
  540. BuildContext context,
  541. String tipTitle,
  542. String confirmButtonTitle,
  543. confirmCallback,
  544. cancleButtonTitle,
  545. cancleCallback,
  546. {title = ''}) {
  547. var confirm = buildConfirmBotton(confirmButtonTitle, confirmCallback);
  548. var cancle = buildCancleBotton(cancleButtonTitle, cancleCallback);
  549. buildTip(
  550. context,
  551. title,
  552. buildConfirmContent(
  553. _buildContentTip(tipTitle),
  554. Column(
  555. children: <Widget>[cancle, confirm],
  556. )));
  557. }
  558. static Widget buildTipContent(
  559. BuildContext context, String tips, Widget content,
  560. {failcallbak}) {
  561. return Container(
  562. child: Column(
  563. mainAxisAlignment: MainAxisAlignment.center,
  564. children: <Widget>[
  565. Stack(
  566. children: <Widget>[
  567. Container(
  568. padding: EdgeInsets.only(bottom: 25),
  569. alignment: Alignment.center,
  570. decoration: BoxDecoration(
  571. color: Colors.white,
  572. borderRadius: BorderRadius.circular(10.0)),
  573. width: MediaQuery.of(context).size.width * 0.91,
  574. child: Column(
  575. children: <Widget>[
  576. tips == ''
  577. ? Container()
  578. : Container(
  579. margin:
  580. EdgeInsets.only(top: 15.5, left: 40, right: 40),
  581. padding: EdgeInsets.only(bottom: 10.5),
  582. decoration: BoxDecoration(
  583. border: Border(
  584. bottom: BorderSide(
  585. color: Constants.DividerLineColor))),
  586. alignment: Alignment.center,
  587. child: Text(
  588. tips,
  589. textScaleFactor: 1.0,
  590. style: TextStyle(
  591. color: Constants.BlackTextColor,
  592. fontSize: 16.5,
  593. fontWeight: FontWeight.w400),
  594. textAlign: TextAlign.center,
  595. ),
  596. ),
  597. content
  598. ],
  599. ),
  600. ),
  601. Positioned(
  602. top: -40,
  603. right: 0,
  604. child: InkWell(
  605. highlightColor: Colors.transparent,
  606. radius: 0,
  607. onTap: () {
  608. Navigator.of(context).pop();
  609. if (failcallbak != null) failcallbak();
  610. },
  611. child: Container(
  612. width: 40,
  613. height: 40,
  614. alignment: Alignment.center,
  615. margin: EdgeInsets.only(top: 36.5),
  616. decoration: BoxDecoration(
  617. borderRadius: BorderRadius.circular(50.0)),
  618. child: Icon(
  619. // IconData(
  620. // 0xe679,
  621. // fontFamily: 'iconfont',
  622. // ),
  623. Icons.close,
  624. color: Colors.grey[700],
  625. size: 24,
  626. ),
  627. )))
  628. ],
  629. )
  630. ]));
  631. // return Container(
  632. // child: Column(
  633. // mainAxisAlignment: MainAxisAlignment.center,
  634. // children: <Widget>[
  635. // Container(
  636. // padding: EdgeInsets.only(bottom: 25),
  637. // alignment: Alignment.center,
  638. // decoration: BoxDecoration(
  639. // color: Colors.white, borderRadius: BorderRadius.circular(10.0)),
  640. // width: MediaQuery.of(context).size.width * 0.91,
  641. // child: Column(
  642. // children: <Widget>[
  643. // tips == ''
  644. // ? Container()
  645. // : Container(
  646. // margin: EdgeInsets.only(top: 15.5, left: 40, right: 40),
  647. // padding: EdgeInsets.only(bottom: 10.5),
  648. // decoration: BoxDecoration(
  649. // border: Border(
  650. // bottom: BorderSide(
  651. // color: Constants.DividerLineColor))),
  652. // alignment: Alignment.center,
  653. // child: Text(
  654. // tips,
  655. // textScaleFactor: 1.0,
  656. // style: TextStyle(
  657. // color: Constants.BlackTextColor,
  658. // fontSize: 16.5,
  659. // fontWeight: FontWeight.w400),
  660. // textAlign: TextAlign.center,
  661. // ),
  662. // ),
  663. // content
  664. // ],
  665. // ),
  666. // ),
  667. // InkWell(
  668. // highlightColor: Colors.transparent,
  669. // radius: 0,
  670. // onTap: () {
  671. // Navigator.of(context).pop();
  672. // if (failcallbak != null) failcallbak();
  673. // },
  674. // child: Container(
  675. // width: 40,
  676. // height: 40,
  677. // alignment: Alignment.center,
  678. // margin: EdgeInsets.only(top: 36.5),
  679. // decoration: BoxDecoration(
  680. // color: Colors.white,
  681. // borderRadius: BorderRadius.circular(50.0)),
  682. // child: Icon(
  683. // IconData(
  684. // 0xe679,
  685. // fontFamily: 'iconfont',
  686. // ),
  687. // size: 20,
  688. // ),
  689. // ))
  690. // ]));
  691. }
  692. static void buildTip(BuildContext context, String tips, Widget content,
  693. {failcallbak}) {
  694. Navigator.of(context).push(TutorialOverlay(
  695. child:
  696. buildTipContent(context, tips, content, failcallbak: failcallbak)));
  697. }
  698. static Future<bool> showIosDialog(BuildContext context, String title,
  699. Function sureFunction, Function cancelFunction) async {
  700. bool isDismiss = await showDialog(
  701. context: context,
  702. builder: (context) {
  703. return CupertinoAlertDialog(
  704. title: fixedText(title),
  705. actions: <Widget>[
  706. CupertinoDialogAction(
  707. child: fixedText(I18n.of(context).determine),
  708. onPressed: sureFunction),
  709. CupertinoDialogAction(
  710. child: fixedText(I18n.of(context).cancel),
  711. onPressed: cancelFunction),
  712. ],
  713. );
  714. });
  715. return isDismiss;
  716. }
  717. static Widget buildTopTip(double leftPadding, str,
  718. {double fontSize = 15, bool showStar = false}) {
  719. return Container(
  720. decoration: BoxDecoration(
  721. color: Colors.white,
  722. border: Border(bottom: Constants.GreyBorderSide)),
  723. margin: EdgeInsets.only(top: 20),
  724. padding: EdgeInsets.only(left: leftPadding, top: 8, bottom: 8),
  725. alignment: Alignment.centerLeft,
  726. child: Row(
  727. children: <Widget>[
  728. showStar
  729. ? Padding(
  730. padding: EdgeInsets.only(top: 2, right: 2),
  731. child: Text(
  732. '*',
  733. style: TextStyle(color: Colors.red),
  734. ))
  735. : Text(''),
  736. Container(
  737. width: Screen.width - leftPadding * 2,
  738. child: Text(str,
  739. textScaleFactor: 1.0,
  740. style: TextStyle(
  741. color: Constants.BlackTextColor,
  742. fontSize: fontSize,
  743. fontWeight: FontWeight.w500)),
  744. )
  745. ],
  746. ),
  747. );
  748. }
  749. static Widget buildAudioContaniner(double height) {
  750. return ClipRRect(
  751. borderRadius: BorderRadius.circular(2.5),
  752. child: Container(
  753. height: height,
  754. color: const Color(0xFF04A4FE),
  755. width: 5,
  756. ),
  757. );
  758. }
  759. static Widget buildBox(nums, str) {
  760. return Container(
  761. width: (Screen.width - 80) / 3,
  762. child: Column(
  763. children: <Widget>[
  764. Container(
  765. alignment: Alignment.center,
  766. margin: EdgeInsets.only(top: 10),
  767. width: 58.1,
  768. height: 24.85,
  769. decoration: BoxDecoration(
  770. color: nums > 0 ? Constants.BlueTextColor : Colors.grey[200],
  771. borderRadius:
  772. BorderRadius.circular(Constants.LittleButtonRadius)),
  773. child: Text(
  774. nums > 99 ? '99+' : nums.toString(),
  775. textScaleFactor: 1.0,
  776. style: TextStyle(
  777. fontSize: 17.76,
  778. color: nums > 0 ? Colors.white : Colors.grey),
  779. ),
  780. ),
  781. Container(
  782. margin: EdgeInsets.only(top: 5),
  783. alignment: Alignment.center,
  784. child: Text(
  785. str,
  786. textScaleFactor: 1.0,
  787. style: TextStyle(color: Constants.BlackTextColor, fontSize: 12),
  788. ),
  789. ),
  790. ],
  791. ),
  792. );
  793. }
  794. static Future<bool> _willPop(BuildContext context, bool isForceUpdate) async {
  795. print('_willPop $isForceUpdate');
  796. if (isForceUpdate) {
  797. await SystemChannels.platform.invokeMethod('SystemNavigator.pop');
  798. } else {
  799. Navigator.pop(context);
  800. }
  801. return null;
  802. }
  803. static void buildVersionUpdate(
  804. BuildContext context,
  805. String versionName,
  806. ///版本号
  807. bool isForceUpdate,
  808. ///强制升级
  809. String describe,
  810. ///版本描述
  811. ValueNotifier<String> updateProgress,
  812. ///进度更新
  813. Function go
  814. ///点击开始体验回调
  815. ) {
  816. Navigator.of(context).push(TutorialOverlay(
  817. child: WillPopScope(
  818. child: Container(
  819. alignment: Alignment.center,
  820. width: 296,
  821. child: Container(
  822. width: 296,
  823. height: 387,
  824. child: Stack(
  825. children: <Widget>[
  826. Positioned(
  827. top: 10,
  828. child: Container(
  829. height: 307,
  830. width: 296,
  831. child: Column(
  832. children: <Widget>[
  833. SizedBox(
  834. height: 75,
  835. ),
  836. Container(
  837. padding: EdgeInsets.fromLTRB(20, 10, 20, 10),
  838. height: 161,
  839. width: 296,
  840. child: SingleChildScrollView(
  841. child: Text(
  842. describe ?? '',
  843. textAlign: TextAlign.left,
  844. style: TextStyle(
  845. fontSize: 15,
  846. fontWeight: FontWeight.w300),
  847. ),
  848. ),
  849. ),
  850. ValueListenableBuilder(
  851. builder: (BuildContext context, String value,
  852. Widget child) {
  853. return value == '-1'
  854. ? GestureDetector(
  855. onTap: go,
  856. child: Container(
  857. alignment: Alignment.center,
  858. width: 164,
  859. height: 40,
  860. child: Text(
  861. I18n.of(context).test_it,
  862. style: TextStyle(
  863. fontWeight: FontWeight.w500,
  864. color: Colors.white,
  865. fontSize: 17),
  866. ),
  867. decoration: BoxDecoration(
  868. color: Color(0xff3875E9),
  869. borderRadius:
  870. BorderRadius.all(
  871. Radius.circular(
  872. 3.0))),
  873. ),
  874. )
  875. : Container(
  876. alignment: Alignment.center,
  877. width: 164,
  878. height: 40,
  879. child: Stack(
  880. children: <Widget>[
  881. SizedBox(
  882. //限制进度条的高度
  883. height: 40,
  884. //限制进度条的宽度
  885. width: 164,
  886. child: ClipRRect(
  887. borderRadius:
  888. BorderRadius.all(
  889. Radius.circular(
  890. 3.0)),
  891. child:
  892. LinearProgressIndicator(
  893. //0~1的浮点数,用来表示进度多少;如果 value 为 null 或空,则显示一个动画,否则显示一个定值
  894. value: double.parse(
  895. value) /
  896. 100,
  897. //背景颜色
  898. backgroundColor:
  899. Color(
  900. 0xff4E5D7A),
  901. //进度颜色
  902. valueColor:
  903. new AlwaysStoppedAnimation<
  904. Color>(
  905. Color(
  906. 0xff65A5FC))),
  907. ),
  908. ),
  909. Container(
  910. alignment: Alignment.center,
  911. child: Text(
  912. '$value %',
  913. style: TextStyle(
  914. fontWeight:
  915. FontWeight.w500,
  916. color: Colors.white,
  917. fontSize: 19),
  918. ),
  919. )
  920. ],
  921. ),
  922. decoration: BoxDecoration(
  923. color: Color(0xff3875E9),
  924. borderRadius: BorderRadius.all(
  925. Radius.circular(3.0))),
  926. );
  927. },
  928. valueListenable: updateProgress,
  929. )
  930. ],
  931. ),
  932. decoration: BoxDecoration(
  933. color: Colors.white,
  934. borderRadius: BorderRadius.circular(12)))),
  935. Container(
  936. height: 81,
  937. child: Stack(
  938. children: <Widget>[
  939. Image.asset(
  940. R.assetsImagesImgUpdateBg,
  941. height: 81,
  942. ),
  943. Positioned.fill(
  944. child: Align(
  945. alignment: Alignment.center,
  946. child: Text(
  947. '${I18n.of(context).found_new} ($versionName)',
  948. style:
  949. TextStyle(color: Colors.white, fontSize: 18),
  950. ),
  951. )),
  952. Positioned.fill(
  953. child: Offstage(
  954. offstage: isForceUpdate,
  955. child: Align(
  956. alignment: Alignment.topRight,
  957. child: Container(
  958. width: 50,
  959. height: 50,
  960. child: GestureDetector(
  961. onTap: () {
  962. Navigator.of(context).pop();
  963. },
  964. child: Icon(
  965. IconData(
  966. 0xe679,
  967. fontFamily: 'iconfont',
  968. ),
  969. size: 16,
  970. color: Color(0xffa4c1fe),
  971. ),
  972. ),
  973. ),
  974. ),
  975. ))
  976. ],
  977. ),
  978. )
  979. ],
  980. ),
  981. ),
  982. ),
  983. onWillPop: () => _willPop(context, isForceUpdate))));
  984. }
  985. ///访问相册权限
  986. static Future<bool> showPhotoPermissionSetting(BuildContext context) async {
  987. return showPermissionSetting(
  988. context,
  989. Platform.isAndroid ? PermissionGroup.storage : PermissionGroup.photos,
  990. Platform.isAndroid
  991. ? I18n.of(context).location_permission
  992. : I18n.of(context).photo_permission);
  993. }
  994. ///权限申请被拒后 弹窗提示到设置界面打开
  995. static Future<bool> showPermissionSetting(BuildContext context,
  996. PermissionGroup permissionGroup, String tips) async {
  997. final PermissionStatus addStatus =
  998. await PermissionHandler().checkPermissionStatus(permissionGroup);
  999. print('check :$permissionGroup addStatus: $addStatus');
  1000. if (addStatus == PermissionStatus.granted) {
  1001. return true;
  1002. } else {
  1003. /// ios第一次-发起询问权限 || android 第一次发起请求或者被拒过
  1004. if (addStatus == PermissionStatus.unknown ||
  1005. (addStatus == PermissionStatus.denied && Platform.isAndroid)) {
  1006. Map<PermissionGroup, PermissionStatus> permissionRequestResult =
  1007. await PermissionHandler().requestPermissions([permissionGroup]);
  1008. PermissionStatus status = permissionRequestResult[permissionGroup];
  1009. print('status: $status');
  1010. if (status == PermissionStatus.granted) {
  1011. return true;
  1012. } else {
  1013. var result = await showDialog(
  1014. context: context,
  1015. builder: (ctx) => NotPermissionDialog(tips),
  1016. );
  1017. if (result == true) {
  1018. PermissionHandler().openAppSettings();
  1019. }
  1020. return false;
  1021. }
  1022. } else {
  1023. ///被用户禁用,所以弹窗去设置打开权限
  1024. var result = await showDialog(
  1025. context: context,
  1026. builder: (ctx) => NotPermissionDialog(tips),
  1027. );
  1028. if (result == true) {
  1029. PermissionHandler().openAppSettings();
  1030. }
  1031. return false;
  1032. }
  1033. }
  1034. }
  1035. goScanPage(BuildContext context) async {
  1036. if (await CustomUI.showPermissionSetting(
  1037. context, PermissionGroup.camera, I18n.of(context).camera_permission)) {
  1038. AppNavigator.pushScannerPage(context);
  1039. }
  1040. }
  1041. getSearchResult(String searchKey, List<FriendModel> sourceList) {
  1042. List<FriendModel> res = [];
  1043. for (var i = 0; i < sourceList.length; i++) {
  1044. var friendModel = sourceList[i];
  1045. if ((friendModel.refName != null &&
  1046. friendModel.refName.contains(searchKey)) ||
  1047. friendModel.name.contains(searchKey)) {
  1048. res.add(friendModel);
  1049. }
  1050. }
  1051. return res;
  1052. }
  1053. getGroupSearchResult(
  1054. String searchKey, List<GroupInfoModel> sourceList, Map refMap) {
  1055. List<GroupInfoModel> res = [];
  1056. for (var i = 0; i < sourceList.length; i++) {
  1057. var groupModel = sourceList[i];
  1058. if ((groupModel.name.contains(searchKey)) ||
  1059. groupModel.getGroupName(refMap).contains(searchKey)) {
  1060. res.add(groupModel);
  1061. }
  1062. }
  1063. return res;
  1064. }
  1065. static Widget buildLoaingAnim(BuildContext context,
  1066. {String str, double height}) {
  1067. if (height == null) {
  1068. height = MediaQuery.of(context).size.height * 0.8;
  1069. }
  1070. return Container(
  1071. width: MediaQuery.of(context).size.width,
  1072. height: height,
  1073. alignment: Alignment.topCenter,
  1074. child: Container(
  1075. width: 40,
  1076. height: 40,
  1077. margin: EdgeInsets.only(top: 20),
  1078. padding: EdgeInsets.all(10),
  1079. decoration: BoxDecoration(
  1080. shape: BoxShape.circle,
  1081. color: Colors.white,
  1082. boxShadow: [BoxShadow(blurRadius: 3.0, color: Colors.black26)]),
  1083. child: new CircularProgressIndicator(
  1084. strokeWidth: 2,
  1085. ),
  1086. ));
  1087. }
  1088. static Widget buildLoadingFooter() {
  1089. return CustomFooter(
  1090. builder: (BuildContext context, LoadStatus mode) {
  1091. Widget body = Container();
  1092. if (mode == LoadStatus.idle) {
  1093. //body = Text("pull up load");
  1094. } else if (mode == LoadStatus.loading) {
  1095. body = CupertinoActivityIndicator();
  1096. } else if (mode == LoadStatus.failed) {
  1097. //body = Text("Load Failed!Click retry!");
  1098. } else if (mode == LoadStatus.canLoading) {
  1099. //body = Text("release to load more");
  1100. } else {
  1101. //body = Text("No more Data");
  1102. }
  1103. return Container(
  1104. //height: 50.0,
  1105. child: Center(child: body),
  1106. );
  1107. },
  1108. );
  1109. }
  1110. static PreferredSizeWidget buildSearchButton(BuildContext context, callback,
  1111. {double bottom = 14}) {
  1112. return PreferredSize(
  1113. preferredSize: Size.fromHeight(49),
  1114. child: InkWell(
  1115. onTap: callback,
  1116. child: Container(
  1117. alignment: Alignment.center,
  1118. margin: EdgeInsets.only(bottom: bottom, left: 12.5, right: 12.5),
  1119. height: 35,
  1120. decoration: BoxDecoration(
  1121. color: const Color(0xFFEEEEEE),
  1122. borderRadius: BorderRadius.all(Radius.circular(8))),
  1123. child: Row(
  1124. crossAxisAlignment: CrossAxisAlignment.center,
  1125. children: <Widget>[
  1126. Container(
  1127. margin: EdgeInsets.only(left: 15, right: 15, bottom: 0),
  1128. child: Icon(
  1129. IconData(
  1130. 0xe664,
  1131. fontFamily: Constants.IconFontFamily,
  1132. ),
  1133. color: const Color(0xFFA0A0A0),
  1134. size: 18,
  1135. ),
  1136. ),
  1137. Container(
  1138. margin: EdgeInsets.only(bottom: 0),
  1139. child: Text(I18n.of(context).search,
  1140. style:
  1141. TextStyle(fontSize: 14.5, color: Colors.grey))),
  1142. ],
  1143. ))),
  1144. );
  1145. }
  1146. static Widget buildCustomLeading(BuildContext context,
  1147. {onTap, double iconPadding = 10}) {
  1148. return InkWell(
  1149. onTap: onTap == null
  1150. ? () {
  1151. Navigator.of(context).pop();
  1152. }
  1153. : onTap,
  1154. child: Container(
  1155. margin:
  1156. EdgeInsets.only(top: 2, left: iconPadding, right: iconPadding),
  1157. child: Image.asset(
  1158. 'assets/images/back.png',
  1159. scale: 2,
  1160. )),
  1161. );
  1162. }
  1163. static Widget buildImageLabel(String url, int nums,
  1164. {bool isLeft = true,
  1165. double imgOpc = 0.6,
  1166. double imgHeight = 14,
  1167. bool isPlayAnim = false}) {
  1168. double radius = 2.75;
  1169. return Container(
  1170. margin: EdgeInsets.only(top: 16, bottom: 14),
  1171. height: 18.5,
  1172. constraints: BoxConstraints(minWidth: 30),
  1173. decoration: BoxDecoration(
  1174. color: const Color(0xFFF0F0F0),
  1175. borderRadius: isLeft
  1176. ? BorderRadius.only(
  1177. topLeft: Radius.circular(radius),
  1178. bottomLeft: Radius.circular(radius))
  1179. : BorderRadius.only(
  1180. topRight: Radius.circular(radius),
  1181. bottomRight: Radius.circular(radius))),
  1182. child: Row(
  1183. children: <Widget>[
  1184. Container(
  1185. margin: EdgeInsets.only(top: 2.5, bottom: 2.5),
  1186. width: !isLeft ? 0.5 : 0,
  1187. color: const Color(0xFFDEDEDE),
  1188. ),
  1189. Opacity(
  1190. opacity: imgOpc,
  1191. child: Container(
  1192. height: imgHeight,
  1193. width: imgHeight,
  1194. margin: EdgeInsets.only(left: 5.5),
  1195. child: isPlayAnim ? Text('') : Image.asset(url))),
  1196. Opacity(
  1197. opacity: 0.8,
  1198. child: Container(
  1199. margin: EdgeInsets.only(left: 7, right: 7),
  1200. child: Text(
  1201. nums.toString(),
  1202. style:
  1203. TextStyle(color: const Color(0xFF4C4C4C), fontSize: 12),
  1204. ))),
  1205. ],
  1206. ),
  1207. );
  1208. }
  1209. ///** isUser 是否是用户,或为 翻译
  1210. static void buildTranslationHelperOrderDialog(
  1211. BuildContext context, bool isUser,
  1212. {String orderId,
  1213. int scenes = 0,
  1214. String desc,
  1215. Function userStartChat,
  1216. int createTime,
  1217. String userName}) {
  1218. Navigator.of(context).push(TutorialOverlay(
  1219. child: TranslateOrderPushPage(
  1220. isUser,
  1221. orderId: orderId,
  1222. scenes: scenes,
  1223. desc: desc,
  1224. userStartChat: userStartChat,
  1225. createTime: createTime,
  1226. userName: userName,
  1227. ),
  1228. ));
  1229. }
  1230. static void buildTranslationEvaluationDialog(BuildContext context) {
  1231. Navigator.of(context).push(TutorialOverlay(
  1232. child: TravelEvaluationPage(),
  1233. ));
  1234. }
  1235. static double getRealTextWidht(String text, double fontSize) {
  1236. TextPainter _textPainter = TextPainter(
  1237. maxLines: 2,
  1238. text: TextSpan(
  1239. text: text,
  1240. style: TextStyle(fontSize: fontSize, color: Colors.black)),
  1241. textDirection: TextDirection.ltr)
  1242. ..layout();
  1243. return _textPainter.width;
  1244. }
  1245. static void buildTowConfirmWithCountDown(
  1246. BuildContext context,
  1247. String tipTitle,
  1248. String confirmButtonTitle,
  1249. confirmCallback,
  1250. cancelCountDown,
  1251. {title = ''}) {
  1252. var confirm = buildConfirmBotton(confirmButtonTitle, confirmCallback);
  1253. // var cancle = buildCancleBotton(cancleButtonTitle, cancleCallback);
  1254. buildTip(
  1255. context,
  1256. title,
  1257. buildConfirmContent(
  1258. _buildContentTip(tipTitle),
  1259. Column(
  1260. children: <Widget>[cancelCountDown, confirm],
  1261. )));
  1262. }
  1263. }