detail_dialog.dart 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // collection/collection_screen.dart
  2. import 'package:flutter/material.dart';
  3. import 'package:image_puzzle/config/device.dart';
  4. import 'package:image_puzzle/models/download.dart';
  5. import 'package:image_puzzle/models/items.dart';
  6. import 'dart:ui' as ui;
  7. import 'package:provider/provider.dart';
  8. class ImageDetailDialog extends StatefulWidget {
  9. final ListItem item;
  10. const ImageDetailDialog({super.key, required this.item});
  11. @override
  12. State<StatefulWidget> createState() => _ImageDetailDialog();
  13. }
  14. class _ImageDetailDialog extends State<ImageDetailDialog> {
  15. bool _isLoading = true;
  16. ui.Image? image;
  17. String? _error; // 新增错误状态
  18. @override
  19. void initState() {
  20. super.initState();
  21. loadImage();
  22. }
  23. void loadImage() async {
  24. try {
  25. Device device = context.read<Device>();
  26. double dpr = device.devicePixelRatio;
  27. // 计算最佳尺寸(屏幕宽度90%,按2:3比例计算高度)
  28. final bestWidth = (device.screenSize.width * 0.9 * dpr).round();
  29. final bestHeight = (bestWidth * 3 / 2).round();
  30. ItemLoader itemLoader = ItemLoader.load(widget.item);
  31. final loadedImage = await itemLoader.getImageBySize(bestWidth, bestHeight);
  32. if (mounted) {
  33. setState(() {
  34. image = loadedImage;
  35. _isLoading = false;
  36. _error = null;
  37. });
  38. }
  39. } catch (e) {
  40. if (mounted) {
  41. setState(() {
  42. _isLoading = false;
  43. _error = "图片加载失败";
  44. });
  45. }
  46. }
  47. }
  48. @override
  49. Widget build(BuildContext context) {
  50. final device = context.read<Device>();
  51. final screenWidth = device.screenSize.width;
  52. return Scaffold(
  53. // 背景设为黑色半透明,突出图片
  54. backgroundColor: Colors.black.withOpacity(0.8),
  55. body: Stack(
  56. children: [
  57. // 主内容区:加载中/错误/图片
  58. Center(child: _buildContent(screenWidth)),
  59. // 左上角关闭按钮
  60. Positioned(
  61. top: device.appBarHeight + 16, // 适配状态栏高度
  62. left: 16,
  63. child: _buildCloseButton(),
  64. ),
  65. ],
  66. ),
  67. );
  68. }
  69. // 构建主体内容(加载中/错误/图片)
  70. Widget _buildContent(double screenWidth) {
  71. if (_isLoading) {
  72. // 加载状态:居中显示进度条
  73. return const CircularProgressIndicator(color: Colors.white, strokeWidth: 3);
  74. }
  75. if (_error != null) {
  76. // 错误状态:显示错误信息和重试按钮
  77. return Column(
  78. mainAxisAlignment: MainAxisAlignment.center,
  79. children: [
  80. const Icon(Icons.error_outline, color: Colors.red, size: 48),
  81. const SizedBox(height: 16),
  82. Text(_error!, style: const TextStyle(color: Colors.white, fontSize: 18)),
  83. TextButton(
  84. onPressed: loadImage,
  85. child: const Text("重试", style: TextStyle(color: Colors.blue, fontSize: 16)),
  86. ),
  87. ],
  88. );
  89. }
  90. return ConstrainedBox(
  91. constraints: BoxConstraints(
  92. maxWidth: screenWidth * 0.9, // 最大宽度为屏幕90%
  93. ),
  94. child: ClipRRect(
  95. borderRadius: BorderRadius.circular(16), // 圆角大小(可自定义,如12、16)
  96. // 可选:添加边框+背景,让圆角更有层次感
  97. child: DecoratedBox(
  98. decoration: BoxDecoration(
  99. color: Colors.grey[900], // 图片加载前的背景色(避免白边)
  100. // 可选:添加边框
  101. border: Border.all(
  102. color: Colors.white.withOpacity(0.3), // 边框颜色(半透明白色)
  103. width: 2, // 边框宽度
  104. ),
  105. ),
  106. child: RawImage(image: image!, fit: BoxFit.contain, alignment: Alignment.center),
  107. ),
  108. ),
  109. );
  110. }
  111. // 构建关闭按钮
  112. Widget _buildCloseButton() {
  113. return GestureDetector(
  114. onTap: () => Navigator.pop(context),
  115. child: Container(
  116. width: 40,
  117. height: 40,
  118. decoration: BoxDecoration(
  119. color: Colors.black54, // 半透黑背景
  120. shape: BoxShape.circle,
  121. ),
  122. child: const Icon(Icons.close, color: Colors.white, size: 24),
  123. ),
  124. );
  125. }
  126. }