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

347 lines
10 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'dart:ui';
  4. import 'package:cached_network_image/cached_network_image.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:fluttertoast/fluttertoast.dart';
  7. import 'package:path_provider/path_provider.dart';
  8. import 'package:permission_handler/permission_handler.dart';
  9. import 'package:share_extend/share_extend.dart';
  10. import 'package:sharesdk_plugin/sharesdk_plugin.dart';
  11. import 'package:zhiying_base_widget/dialog/loading/loading.dart';
  12. import 'package:zhiying_base_widget/utils/image_download_util/image_download_util.dart';
  13. import 'package:zhiying_base_widget/widgets/share/models/share_alert_model.dart';
  14. import 'package:zhiying_base_widget/widgets/share/models/share_data_model.dart';
  15. import 'package:zhiying_base_widget/widgets/share/models/share_icon_model.dart';
  16. import 'package:zhiying_base_widget/widgets/share/share_alert_content.dart';
  17. import 'package:zhiying_comm/zhiying_comm.dart';
  18. class ShareAlert extends StatefulWidget {
  19. final String skipIdentifier;
  20. final bool isContentShow;
  21. final ShareDataModel model;
  22. const ShareAlert(this.model, this.skipIdentifier, {Key key, this.isContentShow = false}) : super(key: key); // 中间视图
  23. @override
  24. _ShareAlertState createState() => _ShareAlertState();
  25. }
  26. class _ShareAlertState extends State<ShareAlert> {
  27. ShareAlertModel _iconModel;
  28. @override
  29. void initState() {
  30. NetUtil.request('/api/v1/mod/${widget.skipIdentifier}', method: NetMethod.GET, onCache: (data) {
  31. _parseData(data);
  32. }, onSuccess: (data) {
  33. _parseData(data);
  34. }, onError: (err) {});
  35. super.initState();
  36. }
  37. void _parseData(Map<String, dynamic> data) {
  38. List modList = data['mod_list'];
  39. Map d = modList.first;
  40. if (d != null) {
  41. String dString = d['data'];
  42. _iconModel = ShareAlertModel.fromJson(Map<String, dynamic>.from(jsonDecode(dString)));
  43. setState(() {});
  44. }
  45. }
  46. @override
  47. Widget build(BuildContext context) {
  48. return WillPopScope(
  49. onWillPop: () async {
  50. Loading.dismiss();
  51. Navigator.canPop(context);
  52. return true;
  53. },
  54. child: GestureDetector(
  55. child: Scaffold(
  56. backgroundColor: Colors.transparent,
  57. body: BackdropFilter(
  58. filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), //背景
  59. child: Container(
  60. child: Column(
  61. children: <Widget>[
  62. Expanded(
  63. child: Center(child: widget.isContentShow ? ShareAlertContent(_iconModel) : Container()),
  64. ),
  65. _ShareAlertContent(widget.model, widget.skipIdentifier, _iconModel),
  66. ],
  67. ),
  68. ), // 模糊化
  69. ),
  70. ),
  71. onTap: () {
  72. Navigator.of(context).pop();
  73. },
  74. ),
  75. );
  76. }
  77. }
  78. class _ShareAlertContent extends StatefulWidget {
  79. final ShareDataModel model;
  80. final String skipIdentifier;
  81. final ShareAlertModel iconModel;
  82. const _ShareAlertContent(this.model, this.skipIdentifier, this.iconModel, {Key key}) : super(key: key);
  83. @override
  84. _ShareAlertContentState createState() => _ShareAlertContentState();
  85. }
  86. class _ShareAlertContentState extends State<_ShareAlertContent> {
  87. @override
  88. Widget build(BuildContext context) {
  89. return GestureDetector(
  90. onTap: () {},
  91. child: Container(
  92. width: double.infinity,
  93. decoration: BoxDecoration(
  94. color: Colors.white,
  95. borderRadius: BorderRadius.only(
  96. topLeft: Radius.circular(12),
  97. topRight: Radius.circular(12),
  98. ),
  99. ),
  100. child: SafeArea(
  101. top: false,
  102. child: Column(
  103. children: <Widget>[
  104. Container(
  105. margin: EdgeInsets.only(top: 8, bottom: 8),
  106. width: 62,
  107. height: 4,
  108. decoration: BoxDecoration(color: Color(0xffd8d8d8), borderRadius: BorderRadius.circular(2)),
  109. ),
  110. Text(
  111. '分享至',
  112. style: TextStyle(fontSize: 15, color: Color(0xff333333), fontWeight: FontWeight.bold),
  113. ),
  114. Container(
  115. margin: EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 10),
  116. child: _createIcons(),
  117. ),
  118. GestureDetector(
  119. child: Container(
  120. margin: EdgeInsets.only(left: 12, right: 12, bottom: 10),
  121. padding: EdgeInsets.all(12),
  122. decoration: BoxDecoration(color: Color(0xfff3f3f3), borderRadius: BorderRadius.circular(8)),
  123. child: Center(
  124. child: Text(
  125. '取消',
  126. style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: Color(0xff999999)),
  127. ),
  128. ),
  129. ),
  130. onTap: () {
  131. Navigator.of(context).pop();
  132. },
  133. )
  134. ],
  135. ),
  136. ),
  137. ),
  138. );
  139. }
  140. Widget _createIcons() {
  141. return Wrap(
  142. spacing: 10,
  143. runSpacing: 10,
  144. children: widget.iconModel?.icons?.map((item) {
  145. return _createIcon(item);
  146. })?.toList() ??
  147. [],
  148. );
  149. }
  150. Widget _createIcon(ShareIconModel item) {
  151. return GestureDetector(
  152. child: Container(
  153. width: 60,
  154. child: Column(
  155. children: <Widget>[
  156. Container(
  157. width: 40,
  158. height: 40,
  159. child: CachedNetworkImage(
  160. imageUrl: item.icon,
  161. fit: BoxFit.contain,
  162. ),
  163. ),
  164. Padding(
  165. padding: const EdgeInsets.only(top: 2, bottom: 2),
  166. child: Text(
  167. item.name,
  168. style: TextStyle(fontSize: 12, color: Color(0xff333333), fontWeight: FontWeight.bold),
  169. ),
  170. ),
  171. ],
  172. ),
  173. ),
  174. onTap: () async {
  175. //检查是否有存储权限
  176. var status = await Permission.storage.status;
  177. if (!status.isGranted) {
  178. status = await Permission.storage.request();
  179. print(status);
  180. return;
  181. }
  182. if (item.type == 'wx') {
  183. _shareByMob(ShareSDKPlatforms.wechatSession);
  184. } else if (item.type == 'pyq') {
  185. _shareByMob(ShareSDKPlatforms.wechatTimeline);
  186. } else if (item.type == 'qq') {
  187. _shareByMob(ShareSDKPlatforms.qq);
  188. } else if (item.type == 'qq_space') {
  189. _shareByMob(ShareSDKPlatforms.qZone);
  190. } else if (item.type == 'weibo') {
  191. _shareByMob(ShareSDKPlatforms.sina);
  192. } else if (item.type == 'more_setting') {
  193. _shareBySystem();
  194. }
  195. },
  196. );
  197. }
  198. // mob分享,只能单图分享,多图分享调用系统分享
  199. void _shareByMob(ShareSDKPlatform plateform) async {
  200. int count = 0;
  201. if (widget.model.poster != null) {
  202. count++;
  203. }
  204. count += (widget.model?.image?.length ?? 0);
  205. // 多图分享
  206. if (count > 1) {
  207. _shareMultipleImages();
  208. return;
  209. }
  210. Loading.show(context);
  211. SSDKMap params;
  212. if (widget.model.poster != null) {
  213. String path = await _savePoster();
  214. if (path != null && path != '') {
  215. params = SSDKMap()
  216. ..setGeneral(
  217. widget.model?.title ?? '',
  218. widget.model?.content ?? '',
  219. Platform.isIOS ? path : null,
  220. null,
  221. Platform.isAndroid ? path : null,
  222. null,
  223. null,
  224. null,
  225. null,
  226. null,
  227. SSDKContentTypes.image,
  228. );
  229. }
  230. } else {
  231. params = SSDKMap()
  232. ..setGeneral(
  233. widget.model?.title ?? '',
  234. widget.model?.content ?? '',
  235. Platform.isIOS ? widget.model.image : null,
  236. Platform.isAndroid ? widget?.model?.image?.first : null,
  237. null,
  238. widget.model.url,
  239. null,
  240. null,
  241. null,
  242. null,
  243. SSDKContentTypes.auto,
  244. );
  245. }
  246. SharesdkPlugin.share(plateform, params, (SSDKResponseState state, Map userdata, Map contentEntity, SSDKError error) {
  247. print(error);
  248. if (state == SSDKResponseState.Fail) {
  249. Fluttertoast.showToast(msg: '分享失败');
  250. } else if (state == SSDKResponseState.Success) {
  251. Fluttertoast.showToast(msg: '分享成功');
  252. } else if (state == SSDKResponseState.Cancel) {
  253. Fluttertoast.showToast(msg: '取消分享');
  254. }
  255. Logger.debug('${state}, ${error.rawData}');
  256. Loading.dismiss();
  257. });
  258. }
  259. // 系统分享,只能分享图片或者文字,不能组合分享
  260. void _shareBySystem() async {
  261. int count = 0;
  262. if (widget.model.poster != null) {
  263. count++;
  264. }
  265. count += (widget.model?.image?.length ?? 0);
  266. // 多图分享
  267. if (count > 1) {
  268. _shareMultipleImages();
  269. return;
  270. }
  271. if (widget.model.poster != null) {
  272. String path = await _savePoster();
  273. if (path != null && path != '') {
  274. ShareExtend.share(path, 'image');
  275. }
  276. } else {
  277. ShareExtend.share(widget.model.content, 'text');
  278. }
  279. }
  280. Future<String> _savePoster() async {
  281. String path;
  282. if (widget.model.poster != null) {
  283. // 检查并请求权限
  284. var status = await Permission.storage.status;
  285. if (status != PermissionStatus.granted) {
  286. status = await Permission.storage.request();
  287. }
  288. if (status == PermissionStatus.denied) {
  289. Fluttertoast.showToast(msg: '暂无权限,分享失败');
  290. return null;
  291. }
  292. try {
  293. // 保存到本地路径
  294. final tempDir = await getTemporaryDirectory();
  295. final file = await File('${tempDir.path}/image.jpg').create();
  296. file.writeAsBytesSync(widget.model.poster);
  297. path = file.path;
  298. Logger.debug(file.path);
  299. } catch (err, s) {
  300. Logger.error(err.toString(), s.toString());
  301. Fluttertoast.showToast(msg: '分享失败');
  302. return null;
  303. }
  304. }
  305. return path;
  306. }
  307. // 多图分享,调用系统分享
  308. void _shareMultipleImages() async {
  309. List<String> paths = List();
  310. String path = await _savePoster();
  311. if (path != null && path != '') {
  312. paths.add(path);
  313. }
  314. Loading.show(context);
  315. List<String> downPaths = await ImageDownloadUtil.download(widget.model.image);
  316. paths.addAll(downPaths);
  317. ShareExtend.shareMultiple(paths, "image", subject: "");
  318. Loading.dismiss();
  319. }
  320. }