Hibok
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

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