smart_image_container.dart 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import 'dart:io';
  2. import 'package:flutter/material.dart';
  3. import 'package:cached_network_image/cached_network_image.dart';
  4. import 'package:flutter_cache_manager/flutter_cache_manager.dart';
  5. import '../../main.dart';
  6. class SmartImageContainer extends StatefulWidget {
  7. final String imageUrl;
  8. const SmartImageContainer({super.key, required this.imageUrl});
  9. @override
  10. State<SmartImageContainer> createState() => _SmartImageContainerState();
  11. }
  12. class _SmartImageContainerState extends State<SmartImageContainer> {
  13. Size? _imageSize;
  14. ImageStream? _imageStream;
  15. ImageStreamListener? _imageListener;
  16. @override
  17. void initState() {
  18. super.initState();
  19. _loadCachedImageDimensions();
  20. }
  21. void _loadCachedImageDimensions() async {
  22. try {
  23. final response = await imageCacheManager.getFileFromCache(widget.imageUrl);
  24. if (response is FileInfo && mounted) {
  25. final image = Image.file(File(response.file.path));
  26. _processImage(image);
  27. }
  28. else if (response is DownloadProgress) {
  29. // Handle download progress if needed
  30. }
  31. } catch (e) {
  32. if (mounted) {
  33. setState(() => _imageSize = null);
  34. }
  35. }
  36. }
  37. void _processImage(Image image) {
  38. _imageStream = image.image.resolve(ImageConfiguration.empty);
  39. _imageListener = ImageStreamListener((ImageInfo info, _) {
  40. if (!mounted) return;
  41. setState(() {
  42. _imageSize = Size(
  43. info.image.width.toDouble(),
  44. info.image.height.toDouble(),
  45. );
  46. });
  47. });
  48. _imageStream!.addListener(_imageListener!);
  49. }
  50. @override
  51. void dispose() {
  52. _imageStream?.removeListener(_imageListener!);
  53. super.dispose();
  54. }
  55. @override
  56. Widget build(BuildContext context) {
  57. return LayoutBuilder(
  58. builder: (context, constraints) {
  59. final maxWidth = constraints.maxWidth;
  60. double calculatedWidth = maxWidth;
  61. double calculatedHeight = maxWidth;
  62. if (_imageSize != null) {
  63. if (_imageSize!.width > maxWidth) {
  64. final ratio = _imageSize!.height / _imageSize!.width;
  65. calculatedHeight = maxWidth * ratio;
  66. } else {
  67. calculatedWidth = _imageSize!.width;
  68. calculatedHeight = _imageSize!.height;
  69. }
  70. }
  71. return AnimatedContainer(
  72. duration: const Duration(milliseconds: 300),
  73. width: calculatedWidth,
  74. height: calculatedHeight,
  75. child: CachedNetworkImage(
  76. cacheManager: imageCacheManager,
  77. imageUrl: widget.imageUrl,
  78. fit: BoxFit.contain,
  79. placeholder: (context, url) => _buildLoadingPlaceholder(maxWidth),
  80. errorWidget: (context, url, error) =>
  81. _buildErrorPlaceholder(maxWidth),
  82. ),
  83. );
  84. },
  85. );
  86. }
  87. Widget _buildLoadingPlaceholder(double maxWidth) {
  88. return Container(
  89. width: maxWidth,
  90. height: maxWidth * 0.75,
  91. color: Colors.grey[200],
  92. child: const Center(child: CircularProgressIndicator()),
  93. );
  94. }
  95. Widget _buildErrorPlaceholder(double maxWidth) {
  96. return Container(
  97. width: maxWidth,
  98. height: maxWidth * 0.75,
  99. color: Colors.red[100],
  100. child: const Icon(Icons.error_outline, color: Colors.red),
  101. );
  102. }
  103. }