thumbnail_widget.dart 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import 'package:flutter/material.dart';
  2. import 'package:photos/core/cache/image_cache.dart';
  3. import 'package:photos/core/cache/thumbnail_cache.dart';
  4. import 'package:photos/file_repository.dart';
  5. import 'package:photos/models/file.dart';
  6. import 'package:logging/logging.dart';
  7. import 'package:photos/core/constants.dart';
  8. import 'package:photos/models/file_type.dart';
  9. import 'package:photos/utils/file_util.dart';
  10. class ThumbnailWidget extends StatefulWidget {
  11. final File file;
  12. final BoxFit fit;
  13. const ThumbnailWidget(
  14. this.file, {
  15. Key key,
  16. this.fit = BoxFit.cover,
  17. }) : super(key: key);
  18. @override
  19. _ThumbnailWidgetState createState() => _ThumbnailWidgetState();
  20. }
  21. class _ThumbnailWidgetState extends State<ThumbnailWidget> {
  22. static final _logger = Logger("ThumbnailWidget");
  23. static final Widget loadingWidget = Container(
  24. alignment: Alignment.center,
  25. color: Colors.grey[800],
  26. );
  27. bool _hasLoadedThumbnail = false;
  28. bool _isLoadingThumbnail = false;
  29. bool _encounteredErrorLoadingThumbnail = false;
  30. ImageProvider _imageProvider;
  31. @override
  32. Widget build(BuildContext context) {
  33. if (widget.file.localID == null) {
  34. _loadNetworkImage();
  35. } else {
  36. _loadLocalImage(context);
  37. }
  38. var image;
  39. if (_imageProvider != null) {
  40. image = Image(
  41. image: _imageProvider,
  42. fit: widget.fit,
  43. );
  44. }
  45. var content;
  46. if (image != null) {
  47. if (widget.file.fileType == FileType.video) {
  48. content = Stack(
  49. children: [
  50. image,
  51. Icon(Icons.play_circle_outline),
  52. ],
  53. fit: StackFit.expand,
  54. );
  55. } else {
  56. content = image;
  57. }
  58. }
  59. return Stack(
  60. children: [
  61. loadingWidget,
  62. AnimatedOpacity(
  63. opacity: content == null ? 0 : 1.0,
  64. duration: Duration(milliseconds: 400),
  65. child: content,
  66. ),
  67. ],
  68. fit: StackFit.expand,
  69. );
  70. }
  71. void _loadLocalImage(BuildContext context) {
  72. if (!_hasLoadedThumbnail &&
  73. !_encounteredErrorLoadingThumbnail &&
  74. !_isLoadingThumbnail) {
  75. _isLoadingThumbnail = true;
  76. final cachedSmallThumbnail =
  77. ThumbnailLruCache.get(widget.file, THUMBNAIL_SMALL_SIZE);
  78. if (cachedSmallThumbnail != null) {
  79. _imageProvider = Image.memory(cachedSmallThumbnail).image;
  80. _hasLoadedThumbnail = true;
  81. } else {
  82. widget.file.getAsset().then((asset) async {
  83. if (asset == null) {
  84. await deleteFiles([widget.file]);
  85. await FileRepository.instance.reloadFiles();
  86. return;
  87. }
  88. asset
  89. .thumbDataWithSize(THUMBNAIL_SMALL_SIZE, THUMBNAIL_SMALL_SIZE)
  90. .then((data) {
  91. if (data != null && mounted) {
  92. final imageProvider = Image.memory(data).image;
  93. precacheImage(imageProvider, context).then((value) {
  94. if (mounted) {
  95. setState(() {
  96. _imageProvider = imageProvider;
  97. _hasLoadedThumbnail = true;
  98. });
  99. }
  100. });
  101. }
  102. ThumbnailLruCache.put(widget.file, THUMBNAIL_SMALL_SIZE, data);
  103. });
  104. }).catchError((e) {
  105. _logger.warning("Could not load image: ", e);
  106. _encounteredErrorLoadingThumbnail = true;
  107. });
  108. }
  109. }
  110. }
  111. void _loadNetworkImage() {
  112. if (!_hasLoadedThumbnail &&
  113. !_encounteredErrorLoadingThumbnail &&
  114. !_isLoadingThumbnail) {
  115. _isLoadingThumbnail = true;
  116. final cachedThumbnail = ThumbnailFileLruCache.get(widget.file);
  117. if (cachedThumbnail != null) {
  118. _imageProvider = Image.file(cachedThumbnail).image;
  119. _hasLoadedThumbnail = true;
  120. return;
  121. }
  122. getThumbnailFromServer(widget.file).then((file) {
  123. final imageProvider = Image.file(file).image;
  124. if (mounted) {
  125. precacheImage(imageProvider, context).then((value) {
  126. if (mounted) {
  127. setState(() {
  128. _imageProvider = imageProvider;
  129. _hasLoadedThumbnail = true;
  130. });
  131. }
  132. }).catchError((e) {
  133. _logger.severe("Could not load image " + widget.file.toString());
  134. _encounteredErrorLoadingThumbnail = true;
  135. });
  136. }
  137. });
  138. }
  139. }
  140. @override
  141. void didUpdateWidget(ThumbnailWidget oldWidget) {
  142. super.didUpdateWidget(oldWidget);
  143. if (widget.file.generatedID != oldWidget.file.generatedID) {
  144. setState(() {
  145. _hasLoadedThumbnail = false;
  146. _isLoadingThumbnail = false;
  147. _imageProvider = null;
  148. });
  149. }
  150. }
  151. }