mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-01 08:38:18 +08:00
mod: save as livephoto for ios
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -92,6 +92,15 @@ Widget imageview(
|
||||
|
||||
late final enableLivePhoto = GStorage.enableLivePhoto;
|
||||
|
||||
int parseSize(size) {
|
||||
return switch (size) {
|
||||
int() => size,
|
||||
double() => size.round(),
|
||||
String() => int.tryParse(size) ?? 1,
|
||||
_ => 1,
|
||||
};
|
||||
}
|
||||
|
||||
return NineGridView(
|
||||
type: NineGridType.weiBo,
|
||||
margin: const EdgeInsets.only(top: 6),
|
||||
@@ -111,17 +120,19 @@ Widget imageview(
|
||||
onViewImage?.call();
|
||||
context.imageView(
|
||||
initialPage: index,
|
||||
imgList: picArr
|
||||
.map(
|
||||
(item) => SourceModel(
|
||||
sourceType: item.isLivePhoto && enableLivePhoto
|
||||
? SourceType.livePhoto
|
||||
: SourceType.networkImage,
|
||||
url: item.url,
|
||||
liveUrl: item.liveUrl,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
imgList: picArr.map(
|
||||
(item) {
|
||||
bool isLive = item.isLivePhoto && enableLivePhoto;
|
||||
return SourceModel(
|
||||
sourceType:
|
||||
isLive ? SourceType.livePhoto : SourceType.networkImage,
|
||||
url: item.url,
|
||||
liveUrl: isLive ? item.liveUrl : null,
|
||||
width: isLive ? parseSize(item.width) : null,
|
||||
height: isLive ? parseSize(item.height) : null,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
onDismissed: onDismissed,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,11 +41,15 @@ class SourceModel {
|
||||
final SourceType sourceType;
|
||||
final String url;
|
||||
final String? liveUrl;
|
||||
final int? width;
|
||||
final int? height;
|
||||
|
||||
const SourceModel({
|
||||
this.sourceType = SourceType.networkImage,
|
||||
required this.url,
|
||||
this.liveUrl,
|
||||
this.width,
|
||||
this.height,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -387,17 +391,6 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
|
||||
},
|
||||
child: const Text("保存图片"),
|
||||
),
|
||||
if (widget.sources[currentIndex.value].sourceType ==
|
||||
SourceType.livePhoto)
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
DownloadUtils.downloadVideo(
|
||||
context,
|
||||
widget.sources[currentIndex.value].liveUrl!,
|
||||
);
|
||||
},
|
||||
child: const Text("保存 Live"),
|
||||
),
|
||||
if (widget.sources.length > 1)
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
@@ -410,6 +403,23 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
|
||||
},
|
||||
child: const Text("保存全部图片"),
|
||||
),
|
||||
if (widget.sources[currentIndex.value].sourceType ==
|
||||
SourceType.livePhoto)
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
DownloadUtils.downloadLivePhoto(
|
||||
context: context,
|
||||
url: widget.sources[currentIndex.value].url,
|
||||
liveUrl: widget
|
||||
.sources[currentIndex.value].liveUrl!,
|
||||
width:
|
||||
widget.sources[currentIndex.value].width!,
|
||||
height: widget
|
||||
.sources[currentIndex.value].height!,
|
||||
);
|
||||
},
|
||||
child: const Text("保存 Live Photo"),
|
||||
),
|
||||
];
|
||||
},
|
||||
child: const Icon(Icons.more_horiz, color: Colors.white),
|
||||
@@ -565,22 +575,6 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
|
||||
dense: true,
|
||||
title: const Text('保存图片', style: TextStyle(fontSize: 14)),
|
||||
),
|
||||
if (widget.sources[currentIndex.value].sourceType ==
|
||||
SourceType.livePhoto)
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
DownloadUtils.downloadVideo(
|
||||
context,
|
||||
widget.sources[currentIndex.value].liveUrl!,
|
||||
);
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'保存 Live',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
if (widget.sources.length > 1)
|
||||
ListTile(
|
||||
onTap: () {
|
||||
@@ -593,6 +587,25 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
|
||||
dense: true,
|
||||
title: const Text('保存全部图片', style: TextStyle(fontSize: 14)),
|
||||
),
|
||||
if (widget.sources[currentIndex.value].sourceType ==
|
||||
SourceType.livePhoto)
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
DownloadUtils.downloadLivePhoto(
|
||||
context: context,
|
||||
url: widget.sources[currentIndex.value].url,
|
||||
liveUrl: widget.sources[currentIndex.value].liveUrl!,
|
||||
width: widget.sources[currentIndex.value].width!,
|
||||
height: widget.sources[currentIndex.value].height!,
|
||||
);
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'保存 Live Photo',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ 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: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';
|
||||
@@ -86,28 +87,65 @@ class DownloadUtils {
|
||||
return await requestStoragePer(context);
|
||||
}
|
||||
|
||||
static Future downloadVideo(BuildContext context, String url) async {
|
||||
static Future downloadLivePhoto({
|
||||
required BuildContext context,
|
||||
required String url,
|
||||
required String liveUrl,
|
||||
required int width,
|
||||
required int height,
|
||||
}) async {
|
||||
try {
|
||||
if (!await checkPermissionDependOnSdkInt(context)) {
|
||||
return;
|
||||
}
|
||||
SmartDialog.showLoading(msg: '正在下载');
|
||||
|
||||
String tmpPath = (await getTemporaryDirectory()).path;
|
||||
String time = DateTime.now()
|
||||
.toString()
|
||||
.replaceAll(' ', '_')
|
||||
.replaceAll(':', '-')
|
||||
.split('.')
|
||||
.first;
|
||||
late String imageName =
|
||||
"cover_$time.${url.split('.').lastOrNull ?? 'jpg'}";
|
||||
late String imagePath = '$tmpPath/$imageName';
|
||||
String videoName =
|
||||
"video_${DateTime.now().toString().replaceAll(' ', '_').replaceAll(':', '-').split('.').first}.${url.split('.').lastOrNull ?? 'mp4'}";
|
||||
String savePath = '${(await getTemporaryDirectory()).path}/$videoName';
|
||||
await Request.dio.download(url, savePath);
|
||||
SmartDialog.showLoading(msg: '正在保存');
|
||||
final SaveResult result = await SaverGallery.saveFile(
|
||||
filePath: savePath,
|
||||
fileName: videoName,
|
||||
androidRelativePath: "Pictures/PiliPlus",
|
||||
skipIfExists: false,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (result.isSuccess) {
|
||||
SmartDialog.showToast('「$videoName」已保存 ');
|
||||
"video_$time.${liveUrl.split('.').lastOrNull ?? 'mp4'}";
|
||||
String videoPath = '$tmpPath/$videoName';
|
||||
|
||||
await Request.dio.download(liveUrl, videoPath);
|
||||
|
||||
if (Platform.isIOS) {
|
||||
await Request.dio.download(url, imagePath);
|
||||
SmartDialog.showLoading(msg: '正在保存');
|
||||
bool success = await LivePhotoMaker.create(
|
||||
coverImage: imagePath,
|
||||
imagePath: null,
|
||||
voicePath: videoPath,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (success) {
|
||||
SmartDialog.showToast(' Live Photo 已保存 ');
|
||||
} else {
|
||||
SmartDialog.showToast('保存失败');
|
||||
}
|
||||
} else {
|
||||
SmartDialog.showToast('保存失败,${result.errorMessage}');
|
||||
SmartDialog.showLoading(msg: '正在保存');
|
||||
final SaveResult result = await SaverGallery.saveFile(
|
||||
filePath: videoPath,
|
||||
fileName: videoName,
|
||||
androidRelativePath: "Pictures/PiliPlus",
|
||||
skipIfExists: false,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (result.isSuccess) {
|
||||
SmartDialog.showToast(' 已保存 ');
|
||||
} else {
|
||||
SmartDialog.showToast('保存失败,${result.errorMessage}');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1079,6 +1079,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
live_photo_maker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: live_photo_maker
|
||||
sha256: "9af3965bd9d2ab55b0d4d0a1e4041fdcc9ef6c6c44543c8412667541a054f58b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.6"
|
||||
logger:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -180,6 +180,7 @@ dependencies:
|
||||
brotli: ^0.6.0
|
||||
expandable: ^5.0.1
|
||||
flex_seed_scheme: ^3.4.1
|
||||
live_photo_maker: ^0.0.6
|
||||
|
||||
dependency_overrides:
|
||||
screen_brightness: ^2.0.1
|
||||
|
||||
Reference in New Issue
Block a user