Hibok
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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