mod: save as livephoto for ios

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-01-29 11:49:25 +08:00
parent cf2e8cec54
commit 74452cd622
5 changed files with 124 additions and 53 deletions

View File

@@ -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,
);
}

View File

@@ -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),
),
),
],
),
);

View File

@@ -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;

View File

@@ -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:

View File

@@ -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