Hibok
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

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