diff --git a/lib/ui/thumbnail_widget.dart b/lib/ui/thumbnail_widget.dart index 0d29e8e28..92c158834 100644 --- a/lib/ui/thumbnail_widget.dart +++ b/lib/ui/thumbnail_widget.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:photos/core/cache/image_cache.dart'; import 'package:photos/core/cache/thumbnail_cache.dart'; +import 'package:photos/db/files_db.dart'; import 'package:photos/models/file.dart'; import 'package:logging/logging.dart'; import 'package:photos/core/constants.dart'; import 'package:photos/models/file_type.dart'; +import 'package:photos/repositories/file_repository.dart'; import 'package:photos/utils/file_util.dart'; class ThumbnailWidget extends StatefulWidget { @@ -26,14 +28,21 @@ class _ThumbnailWidgetState extends State { color: Colors.grey[800], ); + File _file; bool _hasLoadedThumbnail = false; bool _isLoadingThumbnail = false; bool _encounteredErrorLoadingThumbnail = false; ImageProvider _imageProvider; + @override + void initState() { + _file = widget.file; + super.initState(); + } + @override Widget build(BuildContext context) { - if (widget.file.localID == null) { + if (_file.localID == null) { _loadNetworkImage(); } else { _loadLocalImage(context); @@ -48,7 +57,7 @@ class _ThumbnailWidgetState extends State { var content; if (image != null) { - if (widget.file.fileType == FileType.video) { + if (_file.fileType == FileType.video) { content = Stack( children: [ image, @@ -79,14 +88,21 @@ class _ThumbnailWidgetState extends State { !_isLoadingThumbnail) { _isLoadingThumbnail = true; final cachedSmallThumbnail = - ThumbnailLruCache.get(widget.file, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.get(_file, THUMBNAIL_SMALL_SIZE); if (cachedSmallThumbnail != null) { _imageProvider = Image.memory(cachedSmallThumbnail).image; _hasLoadedThumbnail = true; } else { - widget.file.getAsset().then((asset) async { - if (asset == null) { - await deleteFiles([widget.file]); + _file.getAsset().then((asset) async { + if (asset == null || !(await asset.exists)) { + if (_file.uploadedFileID != null) { + _file.localID = null; + FilesDB.instance.update(_file); + _loadNetworkImage(); + } else { + FilesDB.instance.deleteLocalFile(_file.localID); + FileRepository.instance.reloadFiles(); + } return; } asset @@ -107,7 +123,7 @@ class _ThumbnailWidgetState extends State { } }); } - ThumbnailLruCache.put(widget.file, THUMBNAIL_SMALL_SIZE, data); + ThumbnailLruCache.put(_file, THUMBNAIL_SMALL_SIZE, data); }); }).catchError((e) { _logger.warning("Could not load image: ", e); @@ -122,13 +138,13 @@ class _ThumbnailWidgetState extends State { !_encounteredErrorLoadingThumbnail && !_isLoadingThumbnail) { _isLoadingThumbnail = true; - final cachedThumbnail = ThumbnailFileLruCache.get(widget.file); + final cachedThumbnail = ThumbnailFileLruCache.get(_file); if (cachedThumbnail != null) { _imageProvider = Image.file(cachedThumbnail).image; _hasLoadedThumbnail = true; return; } - getThumbnailFromServer(widget.file).then((file) { + getThumbnailFromServer(_file).then((file) { final imageProvider = Image.file(file).image; if (mounted) { precacheImage(imageProvider, context).then((value) { @@ -139,7 +155,7 @@ class _ThumbnailWidgetState extends State { }); } }).catchError((e) { - _logger.severe("Could not load image " + widget.file.toString()); + _logger.severe("Could not load image " + _file.toString()); _encounteredErrorLoadingThumbnail = true; }); } diff --git a/lib/ui/video_widget.dart b/lib/ui/video_widget.dart index 794900456..fdb9d4ab0 100644 --- a/lib/ui/video_widget.dart +++ b/lib/ui/video_widget.dart @@ -38,38 +38,47 @@ class _VideoWidgetState extends State { void initState() { super.initState(); if (widget.file.localID == null) { - if (!widget.file.isEncrypted) { - _setVideoPlayerController(url: widget.file.getStreamUrl()); - _videoPlayerController.addListener(() { - if (_videoPlayerController.value.hasError) { - _logger.warning(_videoPlayerController.value.errorDescription); - showToast( - "The video has not been processed yet. Downloading the original one...", - toastLength: Toast.LENGTH_SHORT); - _setVideoPlayerController(url: widget.file.getDownloadUrl()); - } - }); - } else { - getFileFromServer( - widget.file, - progressCallback: (count, total) { - setState(() { - _progress = count / total; - if (_progress == 1) { - showToast("Decrypting video...", - toastLength: Toast.LENGTH_SHORT); - } - }); - }, - ).then((file) { - _setVideoPlayerController(file: file); - }); - } + _loadNetworkVideo(); } else { - widget.file.getAsset().then((asset) { - asset.getMediaUrl().then((url) { - _setVideoPlayerController(url: url); - }); + widget.file.getAsset().then((asset) async { + if (asset == null || !(await asset.exists)) { + if (widget.file.uploadedFileID != null) { + _loadNetworkVideo(); + } + } else { + asset.getMediaUrl().then((url) { + _setVideoPlayerController(url: url); + }); + } + }); + } + } + + void _loadNetworkVideo() { + if (!widget.file.isEncrypted) { + _setVideoPlayerController(url: widget.file.getStreamUrl()); + _videoPlayerController.addListener(() { + if (_videoPlayerController.value.hasError) { + _logger.warning(_videoPlayerController.value.errorDescription); + showToast( + "The video has not been processed yet. Downloading the original one...", + toastLength: Toast.LENGTH_SHORT); + _setVideoPlayerController(url: widget.file.getDownloadUrl()); + } + }); + } else { + getFileFromServer( + widget.file, + progressCallback: (count, total) { + setState(() { + _progress = count / total; + if (_progress == 1) { + showToast("Decrypting video...", toastLength: Toast.LENGTH_SHORT); + } + }); + }, + ).then((file) { + _setVideoPlayerController(file: file); }); } } diff --git a/lib/ui/zoomable_image.dart b/lib/ui/zoomable_image.dart index 4b22bc75c..21d153ae0 100644 --- a/lib/ui/zoomable_image.dart +++ b/lib/ui/zoomable_image.dart @@ -6,7 +6,9 @@ import 'package:logging/logging.dart'; import 'package:photos/core/cache/image_cache.dart'; import 'package:photos/core/cache/thumbnail_cache.dart'; import 'package:photos/core/cache/thumbnail_cache_manager.dart'; +import 'package:photos/db/files_db.dart'; import 'package:photos/models/file.dart'; +import 'package:photos/repositories/file_repository.dart'; import 'package:photos/ui/loading_widget.dart'; import 'package:photo_view/photo_view.dart'; import 'package:photos/core/constants.dart'; @@ -44,6 +46,7 @@ class _ZoomableImageState extends State @override void initState() { + _photo = widget.photo; _scaleStateChangedCallback = (value) { if (widget.shouldDisableScroll != null) { widget.shouldDisableScroll(value != PhotoViewScaleState.initial); @@ -54,7 +57,6 @@ class _ZoomableImageState extends State @override Widget build(BuildContext context) { - _photo = widget.photo; if (_photo.localID == null) { _loadNetworkImage(); } else { @@ -136,9 +138,17 @@ class _ZoomableImageState extends State _onLargeThumbnailLoaded(Image.memory(cachedThumbnail).image, context); } else { _photo.getAsset().then((asset) { + if (asset == null) { + // Deleted file + return; + } asset .thumbDataWithSize(THUMBNAIL_LARGE_SIZE, THUMBNAIL_LARGE_SIZE) .then((data) { + if (data == null) { + // Deleted file + return; + } _onLargeThumbnailLoaded(Image.memory(data).image, context); ThumbnailLruCache.put(_photo, THUMBNAIL_LARGE_SIZE, data); }); @@ -152,7 +162,19 @@ class _ZoomableImageState extends State if (cachedFile != null) { _onFinalImageLoaded(Image.file(cachedFile).image, context); } else { - _photo.getAsset().then((asset) { + _photo.getAsset().then((asset) async { + if (asset == null || !(await asset.exists)) { + _logger.info("File was deleted " + _photo.toString()); + if (_photo.uploadedFileID != null) { + _photo.localID = null; + FilesDB.instance.update(_photo); + _loadNetworkImage(); + } else { + FilesDB.instance.deleteLocalFile(_photo.localID); + FileRepository.instance.reloadFiles(); + } + return; + } asset.file.then((file) { if (mounted) { _onFinalImageLoaded(Image.file(file).image, context); diff --git a/lib/utils/file_sync_util.dart b/lib/utils/file_sync_util.dart index 939c60e57..7a900c578 100644 --- a/lib/utils/file_sync_util.dart +++ b/lib/utils/file_sync_util.dart @@ -4,6 +4,8 @@ import 'package:logging/logging.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:photos/models/file.dart'; +final _logger = Logger("FileSyncUtil"); + Future> getDeviceFiles(int fromTime, int toTime) async { final pathEntities = await _getGalleryList(fromTime, toTime); final files = List(); @@ -58,7 +60,7 @@ Future _addToPhotos( files.add(file); } } catch (e) { - Logger("FileSyncUtil").severe(e); + _logger.severe(e); } } }