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.
 
 
 
 
 
 

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