基础组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

418 lines
14 KiB

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