Handle file deletions outside ente gracefully
This commit is contained in:
parent
19208e8d2f
commit
9b84413a68
4 changed files with 93 additions and 44 deletions
|
@ -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<ThumbnailWidget> {
|
|||
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<ThumbnailWidget> {
|
|||
|
||||
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<ThumbnailWidget> {
|
|||
!_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<ThumbnailWidget> {
|
|||
}
|
||||
});
|
||||
}
|
||||
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<ThumbnailWidget> {
|
|||
!_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<ThumbnailWidget> {
|
|||
});
|
||||
}
|
||||
}).catchError((e) {
|
||||
_logger.severe("Could not load image " + widget.file.toString());
|
||||
_logger.severe("Could not load image " + _file.toString());
|
||||
_encounteredErrorLoadingThumbnail = true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,38 +38,47 @@ class _VideoWidgetState extends State<VideoWidget> {
|
|||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ZoomableImage>
|
|||
|
||||
@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<ZoomableImage>
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_photo = widget.photo;
|
||||
if (_photo.localID == null) {
|
||||
_loadNetworkImage();
|
||||
} else {
|
||||
|
@ -136,9 +138,17 @@ class _ZoomableImageState extends State<ZoomableImage>
|
|||
_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<ZoomableImage>
|
|||
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);
|
||||
|
|
|
@ -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<List<File>> getDeviceFiles(int fromTime, int toTime) async {
|
||||
final pathEntities = await _getGalleryList(fromTime, toTime);
|
||||
final files = List<File>();
|
||||
|
@ -58,7 +60,7 @@ Future _addToPhotos(
|
|||
files.add(file);
|
||||
}
|
||||
} catch (e) {
|
||||
Logger("FileSyncUtil").severe(e);
|
||||
_logger.severe(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue