menu_share_bottom.dart 10 KB

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