Hibok
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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