import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:aesthetica_wallpaper/services/image_save_service.dart'; class SavePreviewDialog extends StatefulWidget { final GlobalKey repaintBoundaryKey; final String fileName; const SavePreviewDialog({ super.key, required this.repaintBoundaryKey, required this.fileName, }); @override State createState() => _SavePreviewDialogState(); } class _SavePreviewDialogState extends State { Uint8List? _previewImageBytes; bool _isRendering = true; bool _isSaving = false; String? _errorMessage; @override void initState() { super.initState(); _renderPreview(); } Future _renderPreview() async { try { setState(() { _isRendering = true; _errorMessage = null; }); // 使用更强的等待策略 await Future.delayed(const Duration(milliseconds: 200)); // 等待当前帧完成 await WidgetsBinding.instance.endOfFrame; // 额外等待确保渲染完成 await Future.delayed(const Duration(milliseconds: 1200)); // 增加到1.2秒 // 获取 RepaintBoundary final boundary = widget.repaintBoundaryKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; if (boundary == null) { throw Exception('无法获取RepaintBoundary'); } // 多次尝试等待绘制完成 int waitAttempts = 0; const maxWaitAttempts = 15; // 增加尝试次数 while (boundary.debugNeedsPaint && waitAttempts < maxWaitAttempts) { debugPrint('等待绘制完成... 尝试 ${waitAttempts + 1}/$maxWaitAttempts'); await Future.delayed( Duration(milliseconds: 400 * (waitAttempts + 1)), ); // 增加等待时间 waitAttempts++; } // 如果仍在绘制,尝试强制刷新 if (boundary.debugNeedsPaint) { debugPrint('强制刷新后再次尝试...'); // 触发重绘 WidgetsBinding.instance.addPostFrameCallback((_) {}); await Future.delayed(const Duration(milliseconds: 800)); // 最后一次检查 if (boundary.debugNeedsPaint) { throw Exception('渲染超时,建议使用"直接保存"功能'); } } // 捕获图片 final image = await boundary.toImage(pixelRatio: 2.0); final byteData = await image.toByteData(format: ui.ImageByteFormat.png); if (byteData == null) { throw Exception('无法生成预览图片'); } setState(() { _previewImageBytes = byteData.buffer.asUint8List(); _isRendering = false; }); } catch (e) { debugPrint('渲染预览失败: $e'); setState(() { _isRendering = false; _errorMessage = e.toString(); }); } } Future _saveImage() async { if (_previewImageBytes == null) return; setState(() { _isSaving = true; }); try { // 使用高分辨率重新捕获并保存 final success = await ImageSaveService.saveImageToGallery( widget.repaintBoundaryKey, fileName: widget.fileName, ); 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) { setState(() { _isSaving = false; _errorMessage = '保存失败: $e'; }); } } // 直接保存,跳过预览 Future _directSave() async { setState(() { _isSaving = true; }); try { // 直接使用原始保存服务 final success = await ImageSaveService.saveImageToGallery( widget.repaintBoundaryKey, fileName: widget.fileName, ); 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) { 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.preview, 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 (_isRendering) { 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), ), SizedBox(height: 8), Text( '复杂效果可能需要更长时间', style: TextStyle(color: Colors.grey, fontSize: 12), ), ], ), ); } 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), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: _renderPreview, style: ElevatedButton.styleFrom( backgroundColor: Colors.pinkAccent, foregroundColor: Colors.white, ), child: const Text('重新渲染'), ), ElevatedButton( onPressed: _directSave, style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, 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), ), ), ), ], ); } }