基础组件库
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.
 
 
 
 
 

434 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. 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: GestureDetector(
  135. behavior: HitTestBehavior.opaque,
  136. onTap: (){
  137. RouterUtil.openWebview(_model?.dataModel?.ruleLink??"", context);
  138. },
  139. child: Text(
  140. _model?.appBarRightBtnText ?? '规则',
  141. style: TextStyle(
  142. fontSize: 15,
  143. color: HexColor.fromHex(_model?.appBarRightBtnTextColor ?? '#333333'),
  144. ),
  145. ),
  146. ),
  147. );
  148. }
  149. Widget _createSwiper(List<Widget> posters) {
  150. if ((_model?.dataModel?.posterList?.length ?? 0) <= 0) {
  151. return Container(
  152. margin: EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 20),
  153. width: double.infinity,
  154. child: EmptyWidget(),
  155. color: Colors.white,
  156. );
  157. }
  158. return Container(
  159. width: double.infinity,
  160. child: Swiper(
  161. controller: _controller,
  162. onIndexChanged: (index) {
  163. _currentIndex = index;
  164. },
  165. itemBuilder: (BuildContext context, int index) {
  166. return posters[index];
  167. },
  168. itemCount: posters.length,
  169. viewportFraction: 0.7,
  170. scale: 0.9,
  171. ),
  172. );
  173. }
  174. Widget _createTeacher() {
  175. if (_model.wechatTip == null) {
  176. return Container();
  177. }
  178. InvitedWechatTeacherSkipModel skipModel;
  179. // 是否绑定微信导师
  180. if (_model.dataModel.isBindTeacher == '1') {
  181. skipModel = _model.wechatTip.toWechatTeacher;
  182. } else {
  183. skipModel = _model.wechatTip.toInputWechatUsername;
  184. }
  185. return Container(
  186. width: double.infinity,
  187. margin: EdgeInsets.only(top: 20, left: 30, right: 30),
  188. padding: EdgeInsets.only(left: 13, right: 3),
  189. height: 36,
  190. decoration: BoxDecoration(
  191. color: Color(0x80ffffff),
  192. borderRadius: BorderRadius.circular(18),
  193. ),
  194. child: Row(
  195. children: <Widget>[
  196. Container(
  197. margin: EdgeInsets.only(right: 10),
  198. width: 18,
  199. height: 18,
  200. child:
  201. CachedNetworkImage(imageUrl: _model?.wechatTip?.icon ?? '')),
  202. Expanded(
  203. child: Text(
  204. skipModel.tipText ?? '',
  205. maxLines: 1,
  206. overflow: TextOverflow.ellipsis,
  207. style: TextStyle(
  208. fontSize: 13,
  209. color: HexColor.fromHex(skipModel.tipTextColor ?? '#333333'),
  210. ),
  211. ),
  212. ),
  213. GestureDetector(
  214. onTap: () {
  215. RouterUtil.route(skipModel, skipModel.toJson(), context);
  216. },
  217. child: Container(
  218. width: 88,
  219. height: 30,
  220. decoration: BoxDecoration(
  221. color: HexColor.fromHex(
  222. _model?.wechatTip?.btnBgColor ?? '#ffffff'),
  223. borderRadius: BorderRadius.circular(15)),
  224. child: Center(
  225. child: Text(
  226. skipModel?.btnText ?? '',
  227. style: TextStyle(
  228. fontSize: 13,
  229. color: HexColor.fromHex(
  230. _model?.wechatTip?.btnTextColor ?? '#333333'),
  231. ),
  232. ),
  233. ),
  234. ),
  235. ),
  236. ],
  237. ),
  238. );
  239. }
  240. Widget _createBottom() {
  241. return SafeArea(
  242. top: false,
  243. child: Container(
  244. margin: EdgeInsets.all(12.5),
  245. padding: EdgeInsets.all(10),
  246. width: double.infinity,
  247. decoration: BoxDecoration(
  248. color: HexColor.fromHex(_model?.bottom?.bgColor ?? '#ffffff'),
  249. borderRadius: BorderRadius.circular(18),
  250. boxShadow: [
  251. BoxShadow(
  252. offset: Offset(0, 5), //x,y轴
  253. color: Colors.black12.withOpacity(0.1), //投影颜色
  254. blurRadius: 10 //,投影距离
  255. )
  256. ],
  257. ),
  258. child: Column(
  259. children: <Widget>[
  260. Row(
  261. children:
  262. List.generate(_model?.bottom?.btns?.length ?? 0, (index) {
  263. InvitedFriendsButtonModel model = _model.bottom.btns[index];
  264. return Expanded(
  265. child: GestureDetector(
  266. onTap: () {
  267. _onButtonTap(model.type ?? '');
  268. },
  269. child: Container(
  270. margin: EdgeInsets.only(left: 8, right: 8),
  271. height: 28,
  272. decoration: BoxDecoration(
  273. color: HexColor.fromHex(model?.bgColor ?? ''),
  274. borderRadius: BorderRadius.circular(14),
  275. ),
  276. child: Row(
  277. mainAxisAlignment: MainAxisAlignment.center,
  278. crossAxisAlignment: CrossAxisAlignment.center,
  279. children: <Widget>[
  280. Container(
  281. margin: EdgeInsets.only(right: 2),
  282. width: 12,
  283. height: 12,
  284. child: CachedNetworkImage(
  285. imageUrl: model?.icon ?? '',
  286. ),
  287. ),
  288. Text(
  289. model?.text,
  290. style: TextStyle(
  291. color: HexColor.fromHex(
  292. model?.textColor ?? '#ffffff'),
  293. fontSize: 13),
  294. ),
  295. ],
  296. ),
  297. ),
  298. ),
  299. );
  300. }),
  301. ),
  302. _model?.bottom?.tipText == null || _model?.bottom?.tipText == ''
  303. ? Container()
  304. : Padding(
  305. padding: EdgeInsets.only(top: 10),
  306. child: Text(
  307. _model?.bottom?.tipText ?? '',
  308. style: TextStyle(
  309. fontSize: 13,
  310. color: HexColor.fromHex(
  311. _model?.bottom?.tipTextColor ?? '#999999')),
  312. ),
  313. ),
  314. ],
  315. ),
  316. ),
  317. );
  318. }
  319. // 底部按钮点击
  320. void _onButtonTap(String type) {
  321. if (_currentIndex >= (_model?.dataModel?.posterList?.length ?? 0)) {
  322. Fluttertoast.showToast(msg: '分享失败,暂无选中海报');
  323. return;
  324. }
  325. InvitedFriendsPosterDataModel poster =
  326. _model.dataModel.posterList[_currentIndex];
  327. if (type == 'copy_link') {
  328. //复制链接
  329. if (_model?.dataModel?.inviteLink != null &&
  330. _model.dataModel.inviteLink.length > 0) {
  331. Fluttertoast.showToast(msg: '复制成功');
  332. Clipboard.setData(ClipboardData(text: _model.dataModel.inviteLink));
  333. }
  334. } else if (type == 'share_poster') {
  335. //分享海报
  336. GlobalKey key = _contentKeys[_currentIndex];
  337. _sharePoster(key);
  338. } else if (type == 'copy_invite_code') {
  339. //复制邀请码
  340. if (poster?.inviteCode != null && poster.inviteCode != '') {
  341. Fluttertoast.showToast(msg: '复制成功');
  342. Clipboard.setData(ClipboardData(text: poster.inviteCode));
  343. }
  344. }
  345. }
  346. // 生成海报分享
  347. void _sharePoster(GlobalKey key) async {
  348. BuildContext buildContext = key.currentContext;
  349. if (null != buildContext) {
  350. RenderRepaintBoundary boundary = buildContext.findRenderObject();
  351. ui.Image image = await boundary.toImage(pixelRatio: 2.0);
  352. // 注意:png是压缩后格式,如果需要图片的原始像素数据,请使用rawRgba
  353. ByteData byteData =
  354. await image.toByteData(format: ui.ImageByteFormat.png);
  355. Uint8List pngBytes = byteData.buffer.asUint8List();
  356. ShareDataModel shareModel = ShareDataModel(poster: pngBytes);
  357. _showShareAlert(shareModel);
  358. }
  359. }
  360. // 弹出分享框
  361. void _showShareAlert(ShareDataModel shareModel) async {
  362. showCupertinoModalPopup(
  363. context: context,
  364. builder: (context) => ShareAlert(
  365. shareModel,
  366. 'pub.flutter.share_icon',
  367. // child: GoodsShareAlertContent(),
  368. ),
  369. );
  370. }
  371. }
  372. class InvitedFriendsTemp extends StatefulWidget {
  373. final InvitedFriendsPosterDataModel dataModel;
  374. final GlobalKey contentKey;
  375. const InvitedFriendsTemp(this.dataModel, this.contentKey, {Key key})
  376. : super(key: key);
  377. @override
  378. _InvitedFriendsTempState createState() => _InvitedFriendsTempState();
  379. }
  380. class _InvitedFriendsTempState extends State<InvitedFriendsTemp> {
  381. double _scale = 0;
  382. @override
  383. void initState() {
  384. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  385. double scaleW = context.size.height / 667;
  386. double scaleH = context.size.width / 375;
  387. double scale = scaleH < scaleW ? scaleH : scaleW;
  388. if (scale != _scale) {
  389. setState(() {
  390. _scale = scale;
  391. });
  392. }
  393. Logger.debug('${context.size.height} ${context.size.width} ${_scale}');
  394. });
  395. super.initState();
  396. }
  397. @override
  398. Widget build(BuildContext context) {
  399. return Transform.scale(
  400. scale: _scale,
  401. child: InvitedFriendTemplateCreater.create(
  402. widget.dataModel, widget.contentKey));
  403. }
  404. }