menu_share_bottom.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. import 'dart:ui';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/rendering.dart';
  5. import 'package:flutter/services.dart';
  6. import 'package:image_gallery_saver/image_gallery_saver.dart';
  7. import 'package:provider/provider.dart';
  8. import 'package:sport/bean/forum.dart';
  9. import 'package:sport/bean/post.dart';
  10. import 'package:sport/pages/social/post_page.dart';
  11. import 'package:sport/pages/social/post_share_page.dart';
  12. import 'package:sport/provider/user_model.dart';
  13. import 'package:sport/router/navigator_util.dart';
  14. import 'package:sport/services/api/inject_api.dart';
  15. import 'package:sport/services/api/resp.dart';
  16. import 'package:sport/utils/toast.dart';
  17. import 'package:path_provider/path_provider.dart';
  18. import 'package:sport/sharesdk/tencent.dart';
  19. import 'package:sport/sharesdk/wechat.dart';
  20. import 'package:sport/widgets/space.dart';
  21. import 'dart:io';
  22. import 'dart:typed_data';
  23. import 'package:wechat_kit/wechat_kit.dart';
  24. class MenuShareBottomContent extends StatefulWidget {
  25. final String url; // 复制的那个链接
  26. final bool hasDownload; // 有些又download 有些没download
  27. final GlobalKey poster; // 下载海报...
  28. final String shareType; // 什么类型 Img social Link
  29. final Post post; // social 连带的 post
  30. final String hash; // 分享 link 连带的hash
  31. MenuShareBottomContent(
  32. this.shareType, {
  33. this.post,
  34. this.url = "",
  35. this.hasDownload = false,
  36. this.poster,
  37. this.hash,
  38. });
  39. @override
  40. State<StatefulWidget> createState() {
  41. // TODO: implement createState
  42. return _MenuShareBottomContentState();
  43. }
  44. }
  45. // shareType : Img / Link / Social
  46. class _MenuShareBottomContentState extends State<MenuShareBottomContent>
  47. with TencentMixin, WechatMixin, InjectApi {
  48. List<Map<String, dynamic>> map;
  49. Uint8List postInstance;
  50. @override
  51. listenShareMsg(WechatSdkResp resp) {
  52. Navigator.pop(context);
  53. ToastUtil.show("分享成功");
  54. }
  55. @override
  56. void initState() {
  57. // TODO: implement initState
  58. super.initState();
  59. map = [
  60. {
  61. "value": "微信",
  62. "url": "share_icon_wechat",
  63. "callBack": () async {
  64. if (widget.shareType == "Img") {
  65. String path = await initFile();
  66. wechatShareImage(path, "chat");
  67. } else if (widget.shareType == "Link") {
  68. wechatShareLink(widget.url + "?h=${widget.hash}", "chat",
  69. Provider.of<UserModel>(context, listen: false).user.name);
  70. }
  71. }
  72. },
  73. {
  74. "value": "朋友圈",
  75. "url": "share_icon_wechatmonents",
  76. "callBack": () async {
  77. if (widget.shareType == "Img") {
  78. String path = await initFile();
  79. wechatShareImage(path, "friend");
  80. } else if (widget.shareType == "Link") {
  81. wechatShareLink(widget.url + "?h=${widget.hash}", "friend",
  82. Provider.of<UserModel>(context, listen: false).user.name);
  83. }
  84. }
  85. },
  86. {
  87. "value": "QQ",
  88. "url": "share_icon_qq",
  89. "callBack": () async {
  90. if (widget.shareType == "Img") {
  91. String path = await initFile();
  92. qqShare(path);
  93. } else if (widget.shareType == "Link") {
  94. qqShareLink(widget.url);
  95. }
  96. }
  97. },
  98. {
  99. "value": "社区",
  100. "url": "share_icon_community",
  101. "callBack": () async {
  102. List buttonList = [];
  103. RespList<Forum> data = await api.getForumIndex();
  104. buttonList = data.results;
  105. if (data.results.length > 0) {
  106. buttonList.insert(0, new Forum(gameName: "全部"));
  107. }
  108. if (widget.shareType == "social") {
  109. await NavigatorUtil.goPage(
  110. context,
  111. (contxt) => PostPage(
  112. "",
  113. post: widget.post,
  114. forums: buttonList,
  115. ));
  116. } else if (widget.shareType == "Link") {
  117. await NavigatorUtil.goPage(
  118. context,
  119. (contxt) => PostPage(
  120. "",
  121. post: widget.post,
  122. url: "http://shoes-web.hiyd.com/share",
  123. hash: widget.hash,
  124. forums: buttonList,
  125. ));
  126. } else if (widget.shareType == "Img") {
  127. String path = await initFile();
  128. print("$path---------------------------------");
  129. Future.delayed(new Duration(milliseconds: 200));
  130. await NavigatorUtil.goPage(
  131. context,
  132. (context) => PostPage(
  133. "",
  134. image: path,
  135. forums: buttonList,
  136. ));
  137. }
  138. Navigator.pop(context, true);
  139. }
  140. },
  141. {
  142. "value": "社区好友",
  143. "url": "share_icon_friends",
  144. "callBack": () async {
  145. if (widget.shareType == "social") {
  146. await NavigatorUtil.goPage(
  147. context,
  148. (context) => PostShareFriendsPage(
  149. post: widget.post,
  150. ));
  151. } else if (widget.shareType == "Link") {
  152. // 这里可能得组装一手 link 的 数据 ...
  153. await NavigatorUtil.goPage(
  154. context, (context) => PostShareFriendsPage(hash: widget.hash));
  155. } else if (widget.shareType == "Img") {
  156. String path = await initFile();
  157. String url = (await api.postChatUpload(File(path))).data["url"];
  158. await NavigatorUtil.goPage(
  159. context,
  160. (context) => PostShareFriendsPage(
  161. image: url,
  162. ));
  163. }
  164. Navigator.pop(context, true);
  165. }
  166. },
  167. {
  168. "value": "复制链接",
  169. "url": "share_icon_link",
  170. "callBack": () {
  171. Clipboard.setData(ClipboardData(text: widget.url));
  172. ToastUtil.show("复制成功");
  173. }
  174. },
  175. {
  176. "value": "下载图片",
  177. "url": "share_icon_download",
  178. "callBack": () {
  179. _capture().then((file) async {}).whenComplete(() {
  180. print("Complete-------------------------------------------------");
  181. });
  182. }
  183. },
  184. ];
  185. if (widget.hasDownload == null || !widget.hasDownload) {
  186. map.removeLast();
  187. }
  188. if (widget.url == null) {
  189. map.removeAt(5);
  190. }
  191. // 社区暂时先把前面的隐藏掉
  192. if (widget.shareType == "social") {
  193. map = map.sublist(map.length - 2, map.length);
  194. }
  195. }
  196. // 封装成灵活的更通用一点...
  197. Future<String> initFile() async {
  198. Uint8List pngBytes = await initFileUint8List();
  199. print("$pngBytes------------------------------");
  200. String sTempDir = (await getTemporaryDirectory()).path;
  201. bool isDirExist = await Directory(sTempDir).exists();
  202. if (!isDirExist) {
  203. Directory(sTempDir).create();
  204. }
  205. // QQ分享需要一个确实存在的图片
  206. File file = await File(sTempDir +
  207. "/poster-temp-${DateTime.now().millisecondsSinceEpoch}.png")
  208. .writeAsBytes(pngBytes);
  209. print(
  210. "[file]:${file.readAsBytesSync().length}---------------${pngBytes.length}----------------");
  211. return file.path;
  212. }
  213. Future<Uint8List> initFileUint8List() async {
  214. try {
  215. RenderRepaintBoundary boundary =
  216. widget.poster.currentContext.findRenderObject();
  217. //boundary.toImage()转化为ui.Image对象,不会自动为包裹的组件添加背景,不设置可能会缺失背景
  218. var image = await boundary.toImage(pixelRatio: window.devicePixelRatio);
  219. //将image转化为byteData
  220. ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
  221. //这个对象就是图片数据
  222. Uint8List pngBytes = byteData.buffer.asUint8List();
  223. print("成功生成图片 ----------------------------------------");
  224. return pngBytes;
  225. } catch (e) {
  226. print(e);
  227. }
  228. return null;
  229. }
  230. Future<File> _capture() async {
  231. Uint8List pngBytes = await initFileUint8List();
  232. final result = await ImageGallerySaver.saveImage(pngBytes); //这个是核心的保存图片的插件
  233. print(result);
  234. ToastUtil.show("下载成功");
  235. }
  236. @override
  237. Widget build(BuildContext context) {
  238. return Container(
  239. margin: EdgeInsets.fromLTRB(12, 23, 24, 17),
  240. child: Column(
  241. mainAxisSize: MainAxisSize.min,
  242. children: <Widget>[
  243. Row(
  244. children: <Widget>[
  245. Expanded(
  246. child: Divider(
  247. endIndent: 12.0,
  248. ),
  249. ),
  250. Text(
  251. "分享至",
  252. style: Theme.of(context).textTheme.bodyText2,
  253. ),
  254. Expanded(
  255. child: Divider(
  256. indent: 12.0,
  257. ),
  258. )
  259. ],
  260. ),
  261. SizedBox(
  262. height: 20.0,
  263. ),
  264. GridView(
  265. shrinkWrap: true,
  266. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  267. crossAxisCount: 4,
  268. crossAxisSpacing: 12.0,
  269. mainAxisSpacing: 18.0),
  270. children: map
  271. .map(
  272. (e) => InkWell(
  273. child: Column(
  274. crossAxisAlignment: CrossAxisAlignment.center,
  275. children: <Widget>[
  276. Image.asset(
  277. "lib/assets/img/${e["url"]}.png",
  278. width: 44.0,
  279. height: 44.0,
  280. ),
  281. Space(
  282. height: 6.0,
  283. ),
  284. Text(
  285. "${e["value"]}",
  286. style: Theme.of(context).textTheme.subtitle2,
  287. ),
  288. // Space(height: 8.0,),
  289. ],
  290. ),
  291. onTap: () {
  292. e["callBack"]();
  293. },
  294. ),
  295. )
  296. .toList())
  297. ],
  298. ),
  299. );
  300. }
  301. }
  302. Future<bool> menuShareBottom(BuildContext context, String shareType,
  303. {Post post, String url, bool hasDownload, GlobalKey poster, String hash}) {
  304. return showModalBottomSheet(
  305. context: context,
  306. builder: (context) {
  307. return MenuShareBottomContent(shareType,
  308. post: post,
  309. url: url,
  310. hasDownload: hasDownload,
  311. poster: poster,
  312. hash: hash);
  313. },
  314. backgroundColor: Colors.white,
  315. elevation: 10,
  316. shape: RoundedRectangleBorder(
  317. borderRadius: BorderRadius.only(
  318. topLeft: Radius.circular(10), topRight: Radius.circular(10)),
  319. ),
  320. );
  321. }