Hibok
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

1313 строки
49 KiB

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