FunyMeeAI/lib/features/history/history_media_save.dart
2026-04-13 22:25:08 +08:00

86 lines
2.4 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:gal/gal.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
/// 与 [GenerateResultScreen] 保存相册逻辑一致,供 History 卡片 Download 使用。
Future<void> saveHistoryMediaToGallery({
required BuildContext context,
required String taskId,
required String resultUrl,
}) async {
final u = resultUrl.trim();
if (!u.startsWith('http://') && !u.startsWith('https://')) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Invalid media URL',
style: GoogleFonts.inter(fontWeight: FontWeight.w600),
),
),
);
}
return;
}
try {
final ok = await Gal.hasAccess();
if (!ok) {
await Gal.requestAccess();
}
final uri = Uri.parse(u);
final res = await http.get(uri);
if (res.statusCode < 200 || res.statusCode >= 300) {
throw HttpException('HTTP ${res.statusCode}');
}
final isVideo = historyUrlLooksLikeVideo(u);
final ext = isVideo ? historyGuessVideoExt(u) : '.jpg';
final file = File(
'${Directory.systemTemp.path}/funymee_hist_${taskId}_$ext',
);
await file.writeAsBytes(res.bodyBytes);
if (isVideo) {
await Gal.putVideo(file.path);
} else {
await Gal.putImage(file.path);
}
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Saved to Photos',
style: GoogleFonts.inter(fontWeight: FontWeight.w600),
),
),
);
} on GalException catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(e.type.message)));
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Save failed: $e')),
);
}
}
bool historyUrlLooksLikeVideo(String url) {
if (url.isEmpty) return false;
final lower = url.toLowerCase();
const hints = ['.mp4', '.m3u8', '.webm', '.mov', '.mkv', '.avi'];
return hints.any((h) => lower.contains(h));
}
String historyGuessVideoExt(String url) {
final lower = url.toLowerCase();
if (lower.contains('.webm')) return '.webm';
if (lower.contains('.mov')) return '.mov';
if (lower.contains('.m3u8')) return '.mp4';
return '.mp4';
}