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.
 
 
 
 
 
 

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