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.
 
 
 
 
 
 

1341 lines
50 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/screen.dart';
  14. import 'package:dio/dio.dart';
  15. import 'package:flutter/cupertino.dart';
  16. import 'package:flutter/material.dart';
  17. import 'package:flutter/painting.dart';
  18. import 'package:flutter/services.dart';
  19. import 'package:oktoast/oktoast.dart';
  20. import 'package:permission_handler/permission_handler.dart';
  21. import 'package:pull_to_refresh/pull_to_refresh.dart';
  22. import 'package:url_launcher/url_launcher.dart';
  23. import 'dart:ui' as ui;
  24. import '../r.dart';
  25. import 'HttpUtil.dart';
  26. import 'PicSwiper.dart';
  27. import 'TutorialOverlay.dart';
  28. import 'app_navigator.dart';
  29. import 'conversation_table.dart';
  30. import 'count_down_button.dart';
  31. class NoKeyboardEditableTextFocusNode extends FocusNode {
  32. // @override
  33. // bool consumeKeyboardToken() {
  34. // return false;
  35. // }
  36. }
  37. class CustomUI {
  38. static Widget buildPageLoading(
  39. BuildContext context, Widget content, bool isShow) {
  40. return Stack(
  41. children: <Widget>[
  42. content,
  43. isShow
  44. ? Scaffold(
  45. backgroundColor: Colors.transparent,
  46. body: LoadingDialog(),
  47. )
  48. : Container(),
  49. ],
  50. );
  51. }
  52. static void showContentDialog(
  53. BuildContext context, int programId, int replyId, int type, callback,
  54. {int replyUserId = 0,
  55. String replyUserName = '',
  56. bool isAd = false,
  57. bool isMyself = false}) {
  58. if (UserData().isMan() && !UserData().isVip && !isMyself) {
  59. showToast(I18n.of(context).cant_comment);
  60. return;
  61. }
  62. if (!UserData().isMan() && !UserData().basicInfo.isAttestation) {
  63. buildNotTrue(context);
  64. return;
  65. }
  66. Navigator.of(context).push(TutorialOverlay(
  67. child: Scaffold(
  68. backgroundColor: Constants.BlackTextColor.withOpacity(0.0),
  69. body: buildInput(context, programId, replyId, type, callback,
  70. replyUserId: replyUserId,
  71. replyUserName: replyUserName,
  72. isAd: isAd,
  73. isMyself: isMyself))));
  74. }
  75. static Widget buildInput(
  76. BuildContext context, int programId, int replyId, int type, callback,
  77. {int replyUserId = 0,
  78. String replyUserName = '',
  79. bool isAd: false,
  80. bool isMyself: false}) {
  81. print('replyUserName $replyUserName');
  82. var content = '';
  83. var hitStr = isMyself
  84. ? I18n.of(context).everyone_comment
  85. : I18n.of(context).your_comment;
  86. Widget input = Container(
  87. alignment: Alignment.topCenter,
  88. padding: EdgeInsets.only(left: 10, right: 10, bottom: 2),
  89. color: Colors.white,
  90. child: Row(
  91. children: <Widget>[
  92. Flexible(
  93. child: Container(
  94. margin: EdgeInsets.only(bottom: 10, right: 10),
  95. decoration: BoxDecoration(
  96. border: Border(
  97. bottom: BorderSide(color: const Color(0xFF0368FF)))),
  98. child: TextField(
  99. keyboardAppearance: Brightness.light,
  100. maxLines: 3,
  101. minLines: 1,
  102. style: TextStyle(textBaseline: TextBaseline.alphabetic),
  103. autofocus: true,
  104. inputFormatters: <TextInputFormatter>[
  105. LengthLimitingTextInputFormatter(30) //限制长度
  106. ],
  107. decoration: new InputDecoration(
  108. hintText: hitStr,
  109. hintMaxLines: 1,
  110. hintStyle: TextStyle(fontSize: 15),
  111. border: InputBorder.none,
  112. ),
  113. onChanged: (str) {
  114. content = str;
  115. },
  116. )),
  117. ),
  118. RaisedButton(
  119. color: const Color(0xFF0368FF),
  120. child: Text(
  121. I18n.of(context).send,
  122. textScaleFactor: 1.0,
  123. style: TextStyle(color: Colors.white),
  124. ),
  125. onPressed: () async {
  126. content = content.trim();
  127. if (content == '' || content == null) {
  128. return;
  129. }
  130. if (isAd) {
  131. Map rdata = {
  132. "userId": UserData().basicInfo.userId,
  133. "adId": programId,
  134. };
  135. rdata['sign'] = TokenMgr().getSign(rdata);
  136. rdata['content'] = content;
  137. Response res = await HttpUtil().post(
  138. 'adActivity/reply/evaluate',
  139. data: rdata,
  140. isShowLoading: true);
  141. var resData = res.data;
  142. var data = {
  143. 'Pid': resData['data'],
  144. 'UserId': UserData().basicInfo.userId,
  145. 'NickName': UserData().basicInfo.nickName,
  146. 'Type': type,
  147. 'ReplyUserId': replyUserId,
  148. 'ReplyNickName': replyUserName,
  149. 'Content': content
  150. };
  151. showToast(resData['msg']);
  152. if (resData['code'] == 0) {
  153. Navigator.of(context).pop();
  154. callback(data);
  155. }
  156. } else {
  157. Map rdata = {
  158. "userId": UserData().basicInfo.userId,
  159. "id": programId,
  160. "type": type,
  161. };
  162. rdata['sign'] = TokenMgr().getSign(rdata);
  163. rdata['content'] = content;
  164. rdata['replyId'] = replyId;
  165. Response res = await HttpUtil().post('station/reply/comment',
  166. data: rdata, isShowLoading: true);
  167. var resData = res.data;
  168. print('station/reply/comment $resData');
  169. var data = {
  170. 'Pid': resData['data'],
  171. 'UserId': UserData().basicInfo.userId,
  172. 'NickName': UserData().basicInfo.nickName,
  173. 'Type': type,
  174. 'ReplyUserId': replyUserId,
  175. 'ReplyNickName': replyUserName,
  176. 'Content': content
  177. };
  178. showToast(resData['msg']);
  179. if (resData['code'] == 0) {
  180. Navigator.of(context).pop();
  181. callback(data);
  182. }
  183. }
  184. },
  185. )
  186. ],
  187. ),
  188. );
  189. Widget button = Expanded(
  190. child: InkWell(
  191. highlightColor: Colors.transparent,
  192. radius: 0,
  193. onTap: () {
  194. Navigator.pop(context);
  195. },
  196. ),
  197. );
  198. return Column(
  199. mainAxisAlignment: MainAxisAlignment.end,
  200. children: <Widget>[
  201. button,
  202. input,
  203. ],
  204. );
  205. }
  206. static void buildNotTrue(BuildContext context) {
  207. buildOneConfirm(context, I18n.of(context).after_authenticate,
  208. I18n.of(context).authenticate_now, () {
  209. Navigator.pop(context);
  210. Navigator.of(context).push(
  211. new MaterialPageRoute(
  212. builder: (context) {
  213. return VerificationCenterPage();
  214. },
  215. ),
  216. );
  217. });
  218. }
  219. static Widget buildCancleBotton(title, callback) {
  220. return InkWell(
  221. onTap: callback,
  222. child: Container(
  223. decoration: BoxDecoration(
  224. color: const Color(0XFFC7E5FF),
  225. borderRadius: BorderRadius.all(
  226. Radius.circular(Constants.LittleButtonRadius))),
  227. margin: EdgeInsets.only(top: 0, bottom: 18.5),
  228. height: 37.5,
  229. width: 200,
  230. alignment: Alignment.center,
  231. child: fixedText(
  232. title,
  233. fontSize: 15,
  234. color: const Color(0xFF5781A6),
  235. )),
  236. );
  237. }
  238. static Widget _buildContentTip(tipTitle) {
  239. return tipTitle == ''
  240. ? Container()
  241. : Container(
  242. padding: EdgeInsets.only(top: 38.5, bottom: 31.5),
  243. child: Text(
  244. tipTitle,
  245. textScaleFactor: 1.0,
  246. style: TextStyle(
  247. fontSize: 14, color: Constants.BlackTextColor, height: 1.30),
  248. textAlign: TextAlign.center,
  249. ));
  250. }
  251. static Widget buildConfirmContent(tip, content) {
  252. return Container(
  253. padding: EdgeInsets.only(left: 40, right: 40),
  254. child: Column(
  255. children: <Widget>[tip, content],
  256. ),
  257. );
  258. }
  259. static Widget buildImgLoding(context, url) {
  260. return Center(
  261. child: CircularProgressIndicator(
  262. valueColor: AlwaysStoppedAnimation(Constants.BlueTextColor)));
  263. }
  264. static Widget buildConfirmBotton(title, callback) {
  265. return InkWell(
  266. onTap: callback,
  267. child: Container(
  268. decoration: Constants.ConfirmBUttonBoxDecoration,
  269. height: 37.5,
  270. width: 200,
  271. alignment: Alignment.center,
  272. child: fixedText(
  273. title,
  274. fontSize: 15,
  275. color: Colors.white,
  276. )),
  277. );
  278. }
  279. static void buildOneConfirm(
  280. BuildContext context, String tipTitle, String buttonTitle, callback,
  281. {title = '', failcallbak}) {
  282. var confirm = buildConfirmBotton(buttonTitle, callback);
  283. buildTip(context, title,
  284. buildConfirmContent(_buildContentTip(tipTitle), confirm),
  285. failcallbak: failcallbak);
  286. }
  287. static void buildContacts(
  288. BuildContext context, String tipTitle, String buttonTitle, callback,
  289. {title = '', failcallbak}) {
  290. var confirm = buildConfirmBotton(buttonTitle, callback);
  291. buildTip(
  292. context,
  293. title,
  294. buildConfirmContent(
  295. Container(
  296. alignment: Alignment.center,
  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,
  1109. {double bottom = 14}) {
  1110. return PreferredSize(
  1111. preferredSize: Size.fromHeight(49),
  1112. child: InkWell(
  1113. onTap: callback,
  1114. child: Container(
  1115. alignment: Alignment.center,
  1116. margin: EdgeInsets.only(bottom: bottom, left: 12.5, right: 12.5),
  1117. height: 35,
  1118. decoration: BoxDecoration(
  1119. color: const Color(0xFFEEEEEE),
  1120. borderRadius: BorderRadius.all(Radius.circular(8))),
  1121. child: Row(
  1122. crossAxisAlignment: CrossAxisAlignment.center,
  1123. children: <Widget>[
  1124. Container(
  1125. margin: EdgeInsets.only(left: 15, right: 15, bottom: 0),
  1126. child: Icon(
  1127. IconData(
  1128. 0xe664,
  1129. fontFamily: Constants.IconFontFamily,
  1130. ),
  1131. color: const Color(0xFFA0A0A0),
  1132. size: 18,
  1133. ),
  1134. ),
  1135. Container(
  1136. margin: EdgeInsets.only(bottom: 0),
  1137. child: Text(I18n.of(context).search,
  1138. style:
  1139. TextStyle(fontSize: 14.5, color: Colors.grey))),
  1140. ],
  1141. ))),
  1142. );
  1143. }
  1144. static Widget buildCustomLeading(BuildContext context,
  1145. {onTap, double iconPadding = 10}) {
  1146. return InkWell(
  1147. onTap: onTap == null
  1148. ? () {
  1149. Navigator.of(context).pop();
  1150. }
  1151. : onTap,
  1152. child: Container(
  1153. margin:
  1154. EdgeInsets.only(top: 2, left: iconPadding, right: iconPadding),
  1155. child: Image.asset(
  1156. 'assets/images/back.png',
  1157. scale: 2,
  1158. )),
  1159. );
  1160. }
  1161. static Widget buildImageLabel(String url, int nums,
  1162. {bool isLeft = true, double imgOpc = 0.6, double imgHeight = 14}) {
  1163. double radius = 2.75;
  1164. return Container(
  1165. margin: EdgeInsets.only(top: 16, bottom: 14),
  1166. height: 18.5,
  1167. constraints: BoxConstraints(minWidth: 30),
  1168. decoration: BoxDecoration(
  1169. color: const Color(0xFFF0F0F0),
  1170. borderRadius: isLeft
  1171. ? BorderRadius.only(
  1172. topLeft: Radius.circular(radius),
  1173. bottomLeft: Radius.circular(radius))
  1174. : BorderRadius.only(
  1175. topRight: Radius.circular(radius),
  1176. bottomRight: Radius.circular(radius))),
  1177. child: Row(
  1178. children: <Widget>[
  1179. Container(
  1180. margin: EdgeInsets.only(top: 2.5, bottom: 2.5),
  1181. width: !isLeft ? 0.5 : 0,
  1182. color: const Color(0xFFDEDEDE),
  1183. ),
  1184. Opacity(
  1185. opacity: imgOpc,
  1186. child: Container(
  1187. height: imgHeight,
  1188. margin: EdgeInsets.only(left: 5.5),
  1189. child: Image.asset(url))),
  1190. Opacity(
  1191. opacity: 0.8,
  1192. child: Container(
  1193. margin: EdgeInsets.only(left: 7, right: 7),
  1194. child: Text(
  1195. nums.toString(),
  1196. style:
  1197. TextStyle(color: const Color(0xFF4C4C4C), fontSize: 12),
  1198. ))),
  1199. ],
  1200. ),
  1201. );
  1202. }
  1203. static void buildTranslationHelperOrderDialog(BuildContext context) {
  1204. Navigator.of(context).push(TutorialOverlay(
  1205. child: InkWell(
  1206. onTap: () {
  1207. Navigator.of(context).pop();
  1208. },
  1209. child: UnconstrainedBox(
  1210. alignment: Alignment.topCenter,
  1211. child: InkWell(
  1212. onTap: () {},
  1213. child: Container(
  1214. alignment: Alignment.topCenter,
  1215. // height: 180,
  1216. width: Screen.width - 20,
  1217. margin: EdgeInsets.all(10),
  1218. child: Card(
  1219. elevation: 2, // 阴影
  1220. shape: RoundedRectangleBorder(
  1221. borderRadius: BorderRadius.circular(10),
  1222. // side: BorderSide(color: Colors.green,width: 25),
  1223. ),
  1224. child: Container(
  1225. // color: Colors.yellow,
  1226. width: double.maxFinite,
  1227. padding: EdgeInsets.all(16),
  1228. child: Column(
  1229. crossAxisAlignment: CrossAxisAlignment.start,
  1230. children: <Widget>[
  1231. Padding(
  1232. padding: EdgeInsets.only(bottom: 15),
  1233. child: Text(
  1234. I18n.of(context).translation_butler_dialog_title,
  1235. textScaleFactor: 1.0,
  1236. textAlign: TextAlign.left,
  1237. style: TextStyle(
  1238. fontWeight: FontWeight.w500,
  1239. color: AppColors.NewAppbarTextColor,
  1240. fontSize: 17),
  1241. ),
  1242. ),
  1243. Text(
  1244. I18n.of(context)
  1245. .translation_butler_dialog_order
  1246. .replaceAll('s1', 'xxx'),
  1247. textScaleFactor: 1.0,
  1248. textAlign: TextAlign.left,
  1249. style: TextStyle(
  1250. color: AppColors.NewAppbarTextColor, fontSize: 14),
  1251. ),
  1252. SizedBox(
  1253. height: 10,
  1254. ),
  1255. Text(
  1256. '时间:今天11:45 时长:10分钟',
  1257. textScaleFactor: 1.0,
  1258. textAlign: TextAlign.left,
  1259. style: TextStyle(
  1260. color: AppColors.NewAppbarTextColor, fontSize: 14),
  1261. ),
  1262. Container(
  1263. margin: EdgeInsets.only(
  1264. left: 30, right: 30, top: 20, bottom: 10),
  1265. child: CountDownButton(
  1266. I18n.of(context)
  1267. .translation_butler_dialog_start_service, () {
  1268. Navigator.of(context).pop();
  1269. }),
  1270. )
  1271. ],
  1272. ),
  1273. ),
  1274. ),
  1275. ),
  1276. ),
  1277. ),
  1278. ),
  1279. ));
  1280. }
  1281. static void buildTranslationEvaluationDialog(BuildContext context) {
  1282. Navigator.of(context).push(TutorialOverlay(
  1283. child: TravelEvaluationPage(),
  1284. ));
  1285. }
  1286. }