detail_dialog.dart 4.4 KB

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