基础组件库
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

invited_friends.dart 14 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. import 'dart:typed_data';
  2. import 'dart:ui' as ui;
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter/rendering.dart';
  6. import 'package:flutter/services.dart';
  7. import 'package:flutter_swiper/flutter_swiper.dart';
  8. import 'package:fluttertoast/fluttertoast.dart';
  9. import 'package:zhiying_base_widget/pages/invited_friends/invited_friends_bloc.dart';
  10. import 'package:zhiying_base_widget/pages/invited_friends/models/invite_friend_data_model.dart';
  11. import 'package:zhiying_base_widget/pages/invited_friends/models/invited_friends_model.dart';
  12. import 'package:zhiying_base_widget/template/invited_friend_template/invited_friend_template_creater.dart';
  13. import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart';
  14. import 'package:zhiying_base_widget/widgets/share/models/share_data_model.dart';
  15. import 'package:zhiying_base_widget/widgets/share/share_alert.dart';
  16. import 'package:zhiying_comm/util/base_bloc.dart';
  17. import 'package:zhiying_comm/zhiying_comm.dart';
  18. // 邀请好友
  19. class InvitedFriendsPage extends StatefulWidget {
  20. final Map<String, dynamic> model;
  21. const InvitedFriendsPage(this.model, {Key key}) : super(key: key);
  22. @override
  23. _InvitedFriendsPageState createState() => _InvitedFriendsPageState();
  24. }
  25. class _InvitedFriendsPageState extends State<InvitedFriendsPage> {
  26. @override
  27. Widget build(BuildContext context) {
  28. return BlocProvider<InvitedFriendshBloc>(
  29. bloc: InvitedFriendshBloc(),
  30. child: _InvitedFriendsContainer(widget.model),
  31. );
  32. }
  33. }
  34. class _InvitedFriendsContainer extends StatefulWidget {
  35. final Map<String, dynamic> data;
  36. const _InvitedFriendsContainer(this.data, {Key key}) : super(key: key);
  37. @override
  38. _InvitedFriendsContainerState createState() =>
  39. _InvitedFriendsContainerState();
  40. }
  41. class _InvitedFriendsContainerState extends State<_InvitedFriendsContainer> {
  42. InvitedFriendshBloc _bloc;
  43. InvitedFriendsModel _model;
  44. int _currentIndex = 0; // 邀请海报下标
  45. List<GlobalKey> _contentKeys;
  46. SwiperController _controller;
  47. @override
  48. void initState() {
  49. _bloc = BlocProvider.of<InvitedFriendshBloc>(context);
  50. _bloc.loadData(widget.data['skip_identifier']);
  51. _controller = SwiperController();
  52. super.initState();
  53. }
  54. @override
  55. void dispose() {
  56. _controller?.dispose();
  57. super.dispose();
  58. }
  59. @override
  60. Widget build(BuildContext context) {
  61. return StreamBuilder<InvitedFriendsModel>(
  62. stream: _bloc.outData,
  63. builder: (BuildContext context, AsyncSnapshot snapshot) {
  64. _model = snapshot.data;
  65. _contentKeys = List.generate(
  66. _model?.dataModel?.posterList?.length ?? 0,
  67. (index) => GlobalKey());
  68. var posters = List.generate(
  69. _model?.dataModel?.posterList?.length ?? 0, (index) {
  70. return InvitedFriendsTemp(
  71. _model.dataModel.posterList[index], _contentKeys[index]);
  72. });
  73. return Scaffold(
  74. appBar: _createNav(),
  75. body: _model == null
  76. ? Container()
  77. : Stack(
  78. children: <Widget>[
  79. Container(
  80. width: double.infinity,
  81. height: double.infinity,
  82. child: CachedNetworkImage(
  83. imageUrl: _model?.bgImg ?? '',
  84. fit: BoxFit.cover,
  85. ),
  86. ),
  87. Column(
  88. children: <Widget>[
  89. Expanded(
  90. child: _createSwiper(posters),
  91. ),
  92. _createTeacher(),
  93. _createBottom(),
  94. ],
  95. ),
  96. ],
  97. ),
  98. );
  99. });
  100. }
  101. // 导航栏
  102. Widget _createNav() {
  103. return CupertinoNavigationBar(
  104. border: Border(
  105. bottom: BorderSide(
  106. width: 0.0, // One physical pixel.
  107. style: BorderStyle.none,
  108. ),
  109. ),
  110. backgroundColor: HexColor.fromHex(_model?.appBarBgColor ?? '#ffffff'),
  111. leading: Navigator.canPop(context)
  112. ? GestureDetector(
  113. child: Container(
  114. padding: EdgeInsets.zero,
  115. child: Icon(
  116. Icons.arrow_back_ios,
  117. size: 20,
  118. ),
  119. ),
  120. onTap: () {
  121. if (Navigator.canPop(context)) {
  122. Navigator.pop(context);
  123. }
  124. },
  125. )
  126. : Container(),
  127. middle: Text(
  128. _model?.appBarName ?? '邀请好友',
  129. style: TextStyle(
  130. fontSize: 15,
  131. color: HexColor.fromHex(_model?.appBarNameColor ?? '#333333'),
  132. ),
  133. ),
  134. trailing: Text(
  135. _model?.appBarRightBtnText ?? '规则',
  136. style: TextStyle(
  137. fontSize: 15,
  138. color: HexColor.fromHex(_model?.appBarRightBtnTextColor ?? '#333333'),
  139. ),
  140. ),
  141. );
  142. }
  143. Widget _createSwiper(List<Widget> posters) {
  144. if ((_model?.dataModel?.posterList?.length ?? 0) <= 0) {
  145. return Container(
  146. margin: EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 20),
  147. width: double.infinity,
  148. child: EmptyWidget(),
  149. color: Colors.white,
  150. );
  151. }
  152. return Container(
  153. width: double.infinity,
  154. child: Swiper(
  155. controller: _controller,
  156. onIndexChanged: (index) {
  157. _currentIndex = index;
  158. },
  159. itemBuilder: (BuildContext context, int index) {
  160. return posters[index];
  161. },
  162. itemCount: posters.length,
  163. viewportFraction: 0.7,
  164. scale: 0.9,
  165. ),
  166. );
  167. }
  168. Widget _createTeacher() {
  169. if (_model.wechatTip == null) {
  170. return Container();
  171. }
  172. InvitedWechatTeacherSkipModel skipModel;
  173. // 是否绑定微信导师
  174. if (_model.dataModel.isBindTeacher == '1') {
  175. skipModel = _model.wechatTip.toWechatTeacher;
  176. } else {
  177. skipModel = _model.wechatTip.toInputWechatUsername;
  178. }
  179. return Container(
  180. width: double.infinity,
  181. margin: EdgeInsets.only(top: 20, left: 30, right: 30),
  182. padding: EdgeInsets.only(left: 13, right: 3),
  183. height: 36,
  184. decoration: BoxDecoration(
  185. color: Color(0x80ffffff),
  186. borderRadius: BorderRadius.circular(18),
  187. ),
  188. child: Row(
  189. children: <Widget>[
  190. Container(
  191. margin: EdgeInsets.only(right: 10),
  192. width: 18,
  193. height: 18,
  194. child:
  195. CachedNetworkImage(imageUrl: _model?.wechatTip?.icon ?? '')),
  196. Expanded(
  197. child: Text(
  198. skipModel.tipText ?? '',
  199. maxLines: 1,
  200. overflow: TextOverflow.ellipsis,
  201. style: TextStyle(
  202. fontSize: 13,
  203. color: HexColor.fromHex(skipModel.tipTextColor ?? '#333333'),
  204. ),
  205. ),
  206. ),
  207. GestureDetector(
  208. onTap: () {
  209. RouterUtil.route(skipModel, skipModel.toJson(), context);
  210. },
  211. child: Container(
  212. width: 88,
  213. height: 30,
  214. decoration: BoxDecoration(
  215. color: HexColor.fromHex(
  216. _model?.wechatTip?.btnBgColor ?? '#ffffff'),
  217. borderRadius: BorderRadius.circular(15)),
  218. child: Center(
  219. child: Text(
  220. skipModel?.btnText ?? '',
  221. style: TextStyle(
  222. fontSize: 13,
  223. color: HexColor.fromHex(
  224. _model?.wechatTip?.btnTextColor ?? '#333333'),
  225. ),
  226. ),
  227. ),
  228. ),
  229. ),
  230. ],
  231. ),
  232. );
  233. }
  234. Widget _createBottom() {
  235. return SafeArea(
  236. top: false,
  237. child: Container(
  238. margin: EdgeInsets.all(12.5),
  239. padding: EdgeInsets.all(10),
  240. width: double.infinity,
  241. decoration: BoxDecoration(
  242. color: HexColor.fromHex(_model?.bottom?.bgColor ?? '#ffffff'),
  243. borderRadius: BorderRadius.circular(18),
  244. boxShadow: [
  245. BoxShadow(
  246. offset: Offset(0, 5), //x,y轴
  247. color: Colors.black12.withOpacity(0.1), //投影颜色
  248. blurRadius: 10 //,投影距离
  249. )
  250. ],
  251. ),
  252. child: Column(
  253. children: <Widget>[
  254. Row(
  255. children:
  256. List.generate(_model?.bottom?.btns?.length ?? 0, (index) {
  257. InvitedFriendsButtonModel model = _model.bottom.btns[index];
  258. return Expanded(
  259. child: GestureDetector(
  260. onTap: () {
  261. _onButtonTap(model.type ?? '');
  262. },
  263. child: Container(
  264. margin: EdgeInsets.only(left: 8, right: 8),
  265. height: 28,
  266. decoration: BoxDecoration(
  267. color: HexColor.fromHex(model?.bgColor ?? ''),
  268. borderRadius: BorderRadius.circular(14),
  269. ),
  270. child: Row(
  271. mainAxisAlignment: MainAxisAlignment.center,
  272. crossAxisAlignment: CrossAxisAlignment.center,
  273. children: <Widget>[
  274. Container(
  275. margin: EdgeInsets.only(right: 2),
  276. width: 12,
  277. height: 12,
  278. child: CachedNetworkImage(
  279. imageUrl: model?.icon ?? '',
  280. ),
  281. ),
  282. Text(
  283. model?.text,
  284. style: TextStyle(
  285. color: HexColor.fromHex(
  286. model?.textColor ?? '#ffffff'),
  287. fontSize: 13),
  288. ),
  289. ],
  290. ),
  291. ),
  292. ),
  293. );
  294. }),
  295. ),
  296. _model?.bottom?.tipText == null || _model?.bottom?.tipText == ''
  297. ? Container()
  298. : Padding(
  299. padding: EdgeInsets.only(top: 10),
  300. child: Text(
  301. _model?.bottom?.tipText ?? '',
  302. style: TextStyle(
  303. fontSize: 13,
  304. color: HexColor.fromHex(
  305. _model?.bottom?.tipTextColor ?? '#999999')),
  306. ),
  307. ),
  308. ],
  309. ),
  310. ),
  311. );
  312. }
  313. // 底部按钮点击
  314. void _onButtonTap(String type) {
  315. if (_currentIndex >= (_model?.dataModel?.posterList?.length ?? 0)) {
  316. Fluttertoast.showToast(msg: '分享失败,暂无选中海报');
  317. return;
  318. }
  319. InvitedFriendsPosterDataModel poster =
  320. _model.dataModel.posterList[_currentIndex];
  321. if (type == 'copy_link') {
  322. //复制链接
  323. if (_model?.dataModel?.inviteLink != null &&
  324. _model.dataModel.inviteLink.length > 0) {
  325. Fluttertoast.showToast(msg: '复制成功');
  326. Clipboard.setData(ClipboardData(text: _model.dataModel.inviteLink));
  327. }
  328. } else if (type == 'share_poster') {
  329. //分享海报
  330. GlobalKey key = _contentKeys[_currentIndex];
  331. _sharePoster(key);
  332. } else if (type == 'copy_invite_code') {
  333. //复制邀请码
  334. if (poster?.inviteCode != null && poster.inviteCode != '') {
  335. Fluttertoast.showToast(msg: '复制成功');
  336. Clipboard.setData(ClipboardData(text: poster.inviteCode));
  337. }
  338. }
  339. }
  340. // 生成海报分享
  341. void _sharePoster(GlobalKey key) async {
  342. BuildContext buildContext = key.currentContext;
  343. if (null != buildContext) {
  344. RenderRepaintBoundary boundary = buildContext.findRenderObject();
  345. ui.Image image = await boundary.toImage(pixelRatio: 2.0);
  346. // 注意:png是压缩后格式,如果需要图片的原始像素数据,请使用rawRgba
  347. ByteData byteData =
  348. await image.toByteData(format: ui.ImageByteFormat.png);
  349. Uint8List pngBytes = byteData.buffer.asUint8List();
  350. ShareDataModel shareModel = ShareDataModel(poster: pngBytes);
  351. _showShareAlert(shareModel);
  352. }
  353. }
  354. // 弹出分享框
  355. void _showShareAlert(ShareDataModel shareModel) async {
  356. showCupertinoModalPopup(
  357. context: context,
  358. builder: (context) => ShareAlert(
  359. shareModel,
  360. 'pub.flutter.share_icon',
  361. // child: GoodsShareAlertContent(),
  362. ),
  363. );
  364. }
  365. }
  366. class InvitedFriendsTemp extends StatefulWidget {
  367. final InvitedFriendsPosterDataModel dataModel;
  368. final GlobalKey contentKey;
  369. const InvitedFriendsTemp(this.dataModel, this.contentKey, {Key key})
  370. : super(key: key);
  371. @override
  372. _InvitedFriendsTempState createState() => _InvitedFriendsTempState();
  373. }
  374. class _InvitedFriendsTempState extends State<InvitedFriendsTemp> {
  375. double _scale = 0;
  376. @override
  377. void initState() {
  378. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  379. double scaleW = context.size.height / 667;
  380. double scaleH = context.size.width / 375;
  381. double scale = scaleH < scaleW ? scaleH : scaleW;
  382. if (scale != _scale) {
  383. setState(() {
  384. _scale = scale;
  385. });
  386. }
  387. Logger.debug('${context.size.height} ${context.size.width} ${_scale}');
  388. });
  389. super.initState();
  390. }
  391. @override
  392. Widget build(BuildContext context) {
  393. return Transform.scale(
  394. scale: _scale,
  395. child: InvitedFriendTemplateCreater.create(
  396. widget.dataModel, widget.contentKey));
  397. }
  398. }