opt: share/save video cover

Closes #563

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-03-29 20:38:36 +08:00
parent 6539457f83
commit db1c836a3e
6 changed files with 116 additions and 43 deletions

View File

@@ -72,6 +72,17 @@ void imageSaveDialog({
),
),
const SizedBox(width: 4),
IconButton(
tooltip: '分享',
onPressed: () {
DownloadUtils.onShareImg(cover ?? '');
},
icon: Icon(
Icons.share,
size: 20,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
IconButton(
tooltip: '保存封面图',
onPressed: () async {
@@ -89,7 +100,7 @@ void imageSaveDialog({
size: 20,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
),
],
),
),

View File

@@ -1,21 +1,16 @@
import 'dart:io';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'interactive_viewer_boundary.dart';
import 'interactive_viewer.dart' as custom;
@@ -380,7 +375,7 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
itemBuilder: (context) {
return [
PopupMenuItem(
onTap: () => onShareImg(
onTap: () => DownloadUtils.onShareImg(
widget.sources[currentIndex.value].url),
child: const Text("分享图片"),
),
@@ -442,34 +437,6 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
);
}
// 图片分享
void onShareImg(String imgUrl) async {
try {
SmartDialog.showLoading();
var response = await Request()
.get(imgUrl, options: Options(responseType: ResponseType.bytes));
final temp = await getTemporaryDirectory();
SmartDialog.dismiss();
String imgName =
"plpl_pic_${DateTime.now().toString().split('-').join()}.jpg";
var path = '${temp.path}/$imgName';
File(path).writeAsBytesSync(response.data);
Rect? sharePositionOrigin;
if (Platform.isIOS && (await Utils.isIpad())) {
sharePositionOrigin = Rect.fromLTWH(0, 0, Get.width, Get.height / 2);
}
Share.shareXFiles(
[XFile(path)],
subject: imgUrl,
sharePositionOrigin: sharePositionOrigin,
);
} catch (e) {
SmartDialog.showToast(e.toString());
}
}
Widget _itemBuilder(index) {
return Center(
child: Hero(
@@ -573,7 +540,8 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
children: [
ListTile(
onTap: () {
onShareImg(widget.sources[currentIndex.value].url);
DownloadUtils.onShareImg(
widget.sources[currentIndex.value].url);
Get.back();
},
dense: true,

View File

@@ -18,6 +18,7 @@ import 'package:PiliPlus/pages/video/detail/member/horizontal_member_page.dart';
import 'package:PiliPlus/pages/video/detail/reply_reply/view.dart';
import 'package:PiliPlus/pages/video/detail/view_point/view_points_page.dart';
import 'package:PiliPlus/pages/video/detail/widgets/ai_detail.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/id_utils.dart';
@@ -1047,6 +1048,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
case 'note':
videoDetailController.showNoteList(context);
break;
case 'savePic':
DownloadUtils.downloadImg(
context,
[videoDetailController.videoItem['pic']],
);
break;
}
},
itemBuilder: (BuildContext context) =>
@@ -1060,6 +1067,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
value: 'note',
child: Text('查看笔记'),
),
if (videoDetailController.videoItem['pic'] != null)
const PopupMenuItem<String>(
value: 'savePic',
child: Text('保存封面'),
),
const PopupMenuItem<String>(
value: 'report',
child: Text('举报'),

View File

@@ -19,6 +19,7 @@ import 'package:PiliPlus/pages/video/detail/member/horizontal_member_page.dart';
import 'package:PiliPlus/pages/video/detail/reply_reply/view.dart';
import 'package:PiliPlus/pages/video/detail/view_point/view_points_page.dart';
import 'package:PiliPlus/pages/video/detail/widgets/ai_detail.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/id_utils.dart';
@@ -889,6 +890,17 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
.showNoteList(
context);
break;
case 'savePic':
DownloadUtils
.downloadImg(
context,
[
videoDetailController
.videoItem[
'pic']
],
);
break;
}
},
itemBuilder: (BuildContext
@@ -906,6 +918,14 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
value: 'note',
child: Text('查看笔记'),
),
if (videoDetailController
.videoItem['pic'] !=
null)
const PopupMenuItem<
String>(
value: 'savePic',
child: Text('保存封面'),
),
const PopupMenuItem<String>(
value: 'report',
child: Text('举报'),
@@ -1456,6 +1476,12 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
case 'note':
videoDetailController.showNoteList(context);
break;
case 'savePic':
DownloadUtils.downloadImg(
context,
[videoDetailController.videoItem['pic']],
);
break;
}
},
itemBuilder: (BuildContext context) =>
@@ -1469,6 +1495,11 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
value: 'note',
child: Text('查看笔记'),
),
if (videoDetailController.videoItem['pic'] != null)
const PopupMenuItem<String>(
value: 'savePic',
child: Text('保存封面'),
),
const PopupMenuItem<String>(
value: 'report',
child: Text('举报'),

View File

@@ -9,6 +9,7 @@ import 'package:PiliPlus/models/common/super_resolution_type.dart';
import 'package:PiliPlus/pages/bangumi/introduction/controller.dart';
import 'package:PiliPlus/pages/setting/widgets/switch_item.dart';
import 'package:PiliPlus/pages/video/detail/introduction/widgets/action_item.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
@@ -163,6 +164,19 @@ class HeaderControlState extends State<HeaderControl> {
leading: const Icon(Icons.note_alt_outlined, size: 20),
title: const Text('查看笔记', style: titleStyle),
),
if (widget.videoDetailCtr.videoItem['pic'] != null)
ListTile(
dense: true,
onTap: () {
Get.back();
DownloadUtils.downloadImg(
context,
[widget.videoDetailCtr.videoItem['pic']],
);
},
leading: const Icon(Icons.image_outlined, size: 20),
title: const Text('保存封面', style: titleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), scheduleExit()},
@@ -1118,13 +1132,19 @@ class HeaderControlState extends State<HeaderControl> {
SmartDialog.showToast('已保存');
}
} catch (e) {
Share.shareXFiles([
XFile.fromData(
res.data,
name: name,
mimeType: 'application/json',
)
]);
Share.shareXFiles(
[
XFile.fromData(
res.data,
name: name,
mimeType: 'application/json',
),
],
sharePositionOrigin: await Utils.isIpad()
? Rect.fromLTWH(
0, 0, Get.width, Get.height / 2)
: null,
);
}
}
} catch (e) {

View File

@@ -7,13 +7,44 @@ import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:live_photo_maker/live_photo_maker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:saver_gallery/saver_gallery.dart';
import 'dart:io';
import 'package:share_plus/share_plus.dart';
class DownloadUtils {
// 图片分享
static void onShareImg(String imgUrl) async {
try {
SmartDialog.showLoading();
var response = await Request()
.get(imgUrl, options: Options(responseType: ResponseType.bytes));
final temp = await getTemporaryDirectory();
SmartDialog.dismiss();
String imgName =
"plpl_pic_${DateTime.now().toString().split('-').join()}.jpg";
var path = '${temp.path}/$imgName';
File(path).writeAsBytesSync(response.data);
Rect? sharePositionOrigin;
if (Platform.isIOS && (await Utils.isIpad())) {
sharePositionOrigin = Rect.fromLTWH(0, 0, Get.width, Get.height / 2);
}
Share.shareXFiles(
[XFile(path)],
subject: imgUrl,
sharePositionOrigin: sharePositionOrigin,
);
} catch (e) {
SmartDialog.showToast(e.toString());
}
}
// 获取存储权限
static Future<bool> requestStoragePer(BuildContext context) async {
await Permission.storage.request();