grid_item.dart 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import 'package:cached_network_image/cached_network_image.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:fluttertoast/fluttertoast.dart';
  4. import 'package:puzzleweave/collection/detail_dialog.dart';
  5. import 'package:puzzleweave/config/device.dart';
  6. import 'package:puzzleweave/l10n/app_localizations.dart';
  7. import 'package:puzzleweave/models/items.dart';
  8. import 'package:puzzleweave/skin/skin.dart';
  9. import 'package:provider/provider.dart';
  10. class GridItem extends StatefulWidget {
  11. final ListItem item;
  12. final bool lock;
  13. final int index;
  14. const GridItem({super.key, required this.item, required this.lock, required this.index});
  15. @override
  16. State<StatefulWidget> createState() {
  17. return _GridItemState();
  18. }
  19. }
  20. class _GridItemState extends State<GridItem> {
  21. @override
  22. void initState() {
  23. super.initState();
  24. }
  25. @override
  26. void dispose() {
  27. super.dispose();
  28. }
  29. @override
  30. Widget build(BuildContext context) {
  31. return Stack(
  32. children: [
  33. Hero(
  34. tag: widget.item.id,
  35. child: Material(
  36. color: Colors.transparent,
  37. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
  38. elevation: 1,
  39. clipBehavior: Clip.hardEdge,
  40. child: Listener(
  41. child: GestureDetector(
  42. onTapUp: (details) {
  43. if (widget.lock) {
  44. Fluttertoast.showToast(
  45. msg: AppLocalizations.of(context)!.collectionLocked,
  46. toastLength: Toast.LENGTH_SHORT,
  47. gravity: ToastGravity.CENTER,
  48. timeInSecForIosWeb: 1,
  49. backgroundColor: SkinHelper.slotBorderColor,
  50. textColor: Colors.white,
  51. fontSize: 16.0,
  52. );
  53. } else {
  54. // 跳转到大图页面 (以全屏 Dialog 形式)
  55. Navigator.push(
  56. context,
  57. PageRouteBuilder(
  58. opaque: false, // 允许背景半透明
  59. pageBuilder: (context, animation, secondaryAnimation) => FadeTransition(
  60. opacity: animation,
  61. child: ImageDetailDialog(item: widget.item),
  62. ),
  63. ),
  64. );
  65. }
  66. },
  67. child: LayoutBuilder(
  68. builder: (context, constraints) {
  69. if (widget.lock) {
  70. return _buildLockedPlaceholder(constraints.biggest);
  71. } else {
  72. return _buildImage(constraints.biggest);
  73. }
  74. },
  75. ),
  76. ),
  77. ),
  78. ),
  79. ),
  80. Positioned(
  81. bottom: 0,
  82. right: 0,
  83. child: DecoratedBox(
  84. decoration: BoxDecoration(
  85. color: SkinHelper.color5,
  86. borderRadius: const BorderRadius.only(bottomRight: Radius.circular(4), topLeft: Radius.circular(10)),
  87. ),
  88. child: Padding(
  89. padding: const EdgeInsets.all(6),
  90. child: Text(
  91. badgeStr,
  92. style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
  93. ),
  94. ),
  95. ),
  96. ),
  97. ],
  98. );
  99. }
  100. String get badgeStr => '${widget.index * 25 + 1}-${(widget.index + 1) * 25}';
  101. Widget _buildImage(Size size) {
  102. final device = context.read<Device>();
  103. int cacheWidth = (size.width * device.devicePixelRatio).toInt();
  104. int cacheHeight = (size.height * device.devicePixelRatio).toInt();
  105. if (widget.item is AssetItem) {
  106. AssetItem assetItem = widget.item as AssetItem;
  107. return Image.asset(assetItem.thumb, cacheWidth: cacheWidth, cacheHeight: cacheHeight);
  108. } else {
  109. return network(widget.item, size.width, size.height, cacheWidth, cacheHeight);
  110. }
  111. }
  112. Widget network(ListItem item, double width, double height, int cacheWidth, int cacheHeight) {
  113. return CachedNetworkImage(
  114. imageUrl: item.thumb,
  115. fit: BoxFit.fill,
  116. width: width,
  117. height: height,
  118. memCacheWidth: cacheWidth,
  119. memCacheHeight: cacheHeight,
  120. // placeholder: (context, url) => JigsawPiece.placeHolder(scale: 0.6),
  121. );
  122. }
  123. Widget _buildLockedPlaceholder(Size size) {
  124. return Container(
  125. width: size.width,
  126. height: size.height,
  127. decoration: BoxDecoration(color: SkinHelper.slotBorderColor, borderRadius: BorderRadius.circular(8)),
  128. child: const Center(
  129. child: Icon(
  130. Icons.lock,
  131. size: 60, // 锁图标大小
  132. color: Colors.white, // 锁图标颜色
  133. ),
  134. ),
  135. );
  136. }
  137. }