import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; class DirectSaveDialog extends StatefulWidget { final GlobalKey previewKey; // 编辑器预览的key final GlobalKey pureImageKey; // 纯净图片的key final String fileName; const DirectSaveDialog({ super.key, required this.previewKey, required this.pureImageKey, required this.fileName, }); @override State createState() => _DirectSaveDialogState(); } class _DirectSaveDialogState extends State { Uint8List? _previewImageBytes; bool _isCapturing = true; bool _isSaving = false; String? _errorMessage; @override void initState() { super.initState(); _capturePreviewImage(); } Future _capturePreviewImage() async { try { setState(() { _isCapturing = true; _errorMessage = null; }); // 直接从编辑器预览中捕获图片,不需要等待渲染 final boundary = widget.previewKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; if (boundary == null) { throw Exception('无法获取预览图片'); } // 立即捕获,因为预览已经是渲染好的 final image = await boundary.toImage(pixelRatio: 1.5); // 适中的分辨率用于预览 final byteData = await image.toByteData(format: ui.ImageByteFormat.png); if (byteData == null) { throw Exception('无法生成预览图片'); } setState(() { _previewImageBytes = byteData.buffer.asUint8List(); _isCapturing = false; }); } catch (e) { debugPrint('捕获预览失败: $e'); setState(() { _isCapturing = false; _errorMessage = e.toString(); }); } } Future _saveImage() async { setState(() { _isSaving = true; }); try { // 使用纯净图片key进行高质量保存 final boundary = widget.pureImageKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; if (boundary == null) { throw Exception('无法获取保存图片'); } // 直接捕获纯净图片 final image = await boundary.toImage(pixelRatio: 3.0); // 高分辨率保存 final byteData = await image.toByteData(format: ui.ImageByteFormat.png); if (byteData == null) { throw Exception('无法生成保存图片'); } final pngBytes = byteData.buffer.asUint8List(); // 直接保存字节数据到相册 final result = await ImageGallerySaver.saveImage( pngBytes, name: widget.fileName, quality: 100, ); final success = result['isSuccess'] == true; if (mounted) { Navigator.of(context).pop(); // 关闭对话框 // 显示结果 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(success ? '✅ 壁纸已保存到相册!' : '❌ 保存失败,请重试'), backgroundColor: success ? Colors.green : Colors.red, duration: const Duration(seconds: 3), ), ); } } catch (e) { debugPrint('保存失败: $e'); setState(() { _isSaving = false; _errorMessage = '保存失败: $e'; }); } } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.transparent, child: Container( width: MediaQuery.of(context).size.width * 0.9, height: MediaQuery.of(context).size.height * 0.8, decoration: BoxDecoration( color: Colors.grey[900], borderRadius: BorderRadius.circular(20), ), child: Column( children: [ // 标题栏 Container( padding: const EdgeInsets.all(20), decoration: const BoxDecoration( gradient: LinearGradient( colors: [Colors.pinkAccent, Colors.purpleAccent], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20), ), ), child: Row( children: [ const Icon(Icons.save_alt, color: Colors.white, size: 24), const SizedBox(width: 12), const Expanded( child: Text( '保存确认', style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), ), ), IconButton( icon: const Icon(Icons.close, color: Colors.white), onPressed: () => Navigator.of(context).pop(), ), ], ), ), // 预览区域 Expanded( child: Container( margin: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.black, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[700]!, width: 2), ), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: _buildPreviewContent(), ), ), ), // 按钮区域 Container( padding: const EdgeInsets.all(20), child: _buildButtons(), ), ], ), ), ); } Widget _buildPreviewContent() { if (_isCapturing) { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(color: Colors.pinkAccent, strokeWidth: 3), SizedBox(height: 16), Text( '正在获取预览...', style: TextStyle(color: Colors.white, fontSize: 16), ), ], ), ); } if (_errorMessage != null) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, color: Colors.red, size: 48), const SizedBox(height: 16), const Text( '获取预览失败', style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Text( _errorMessage!, style: TextStyle(color: Colors.grey[400], fontSize: 14), textAlign: TextAlign.center, ), ), const SizedBox(height: 20), ElevatedButton( onPressed: _capturePreviewImage, style: ElevatedButton.styleFrom( backgroundColor: Colors.pinkAccent, foregroundColor: Colors.white, ), child: const Text('重新获取'), ), ], ), ); } if (_previewImageBytes != null) { return Stack( fit: StackFit.expand, children: [ Image.memory(_previewImageBytes!, fit: BoxFit.contain), if (_isSaving) Container( color: Colors.black.withValues(alpha: 0.7), child: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator( color: Colors.pinkAccent, strokeWidth: 3, ), SizedBox(height: 16), Text( '正在保存到相册...', style: TextStyle(color: Colors.white, fontSize: 16), ), ], ), ), ), ], ); } return const SizedBox.shrink(); } Widget _buildButtons() { if (_errorMessage != null) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('取消', style: TextStyle(color: Colors.grey)), ), ], ); } if (_previewImageBytes == null) { return const SizedBox.shrink(); } return Row( children: [ Expanded( child: TextButton( onPressed: _isSaving ? null : () => Navigator.of(context).pop(), child: const Text('取消', style: TextStyle(color: Colors.grey)), ), ), const SizedBox(width: 16), Expanded( flex: 2, child: ElevatedButton( onPressed: _isSaving ? null : _saveImage, style: ElevatedButton.styleFrom( backgroundColor: Colors.pinkAccent, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: _isSaving ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Text( '保存到相册', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), ), ], ); } }