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 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'; }