From f6434f0b5f6ddbb58b0897b9108031f941efad4e Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Sat, 30 Jan 2021 19:12:11 +0900 Subject: [PATCH] obsolete files: give error hint on viewer, allow deleting from media store --- .../model/provider/MediaStoreImageProvider.kt | 2 +- .../viewer/visual/entry_page_view.dart | 10 +++- lib/widgets/viewer/visual/error.dart | 50 +++++++++++++++---- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt index b87c55f49..cf90f1b5d 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt @@ -186,7 +186,7 @@ class MediaStoreImageProvider : ImageProvider() { override suspend fun delete(context: Context, uri: Uri, path: String?) { path ?: throw Exception("failed to delete file because path is null") - if (requireAccessPermission(context, path)) { + if (File(path).exists() && requireAccessPermission(context, path)) { // if the file is on SD card, calling the content resolver `delete()` removes the entry from the Media Store // but it doesn't delete the file, even if the app has the permission val df = getDocumentFile(context, path, uri) diff --git a/lib/widgets/viewer/visual/entry_page_view.dart b/lib/widgets/viewer/visual/entry_page_view.dart index 30b4f3830..ea17a2478 100644 --- a/lib/widgets/viewer/visual/entry_page_view.dart +++ b/lib/widgets/viewer/visual/entry_page_view.dart @@ -129,7 +129,10 @@ class _EntryPageViewState extends State { } else if (entry.canDecode) { child = _buildRasterView(); } - child ??= ErrorView(onTap: () => onTap?.call(null)); + child ??= ErrorView( + entry: entry, + onTap: () => onTap?.call(null), + ); return widget.heroTag != null ? Hero( @@ -146,7 +149,10 @@ class _EntryPageViewState extends State { child: RasterImageView( entry: entry, viewStateNotifier: _viewStateNotifier, - errorBuilder: (context, error, stackTrace) => ErrorView(onTap: () => onTap?.call(null)), + errorBuilder: (context, error, stackTrace) => ErrorView( + entry: entry, + onTap: () => onTap?.call(null), + ), ), ); } diff --git a/lib/widgets/viewer/visual/error.dart b/lib/widgets/viewer/visual/error.dart index fbee7fb3b..f16192aed 100644 --- a/lib/widgets/viewer/visual/error.dart +++ b/lib/widgets/viewer/visual/error.dart @@ -1,26 +1,54 @@ +import 'dart:io'; + +import 'package:aves/model/entry.dart'; import 'package:aves/theme/icons.dart'; import 'package:aves/widgets/collection/empty.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -class ErrorView extends StatelessWidget { +class ErrorView extends StatefulWidget { + final AvesEntry entry; final VoidCallback onTap; - const ErrorView({@required this.onTap}); + const ErrorView({ + @required this.entry, + @required this.onTap, + }); + + @override + _ErrorViewState createState() => _ErrorViewState(); +} + +class _ErrorViewState extends State { + Future _exists; + + AvesEntry get entry => widget.entry; + + @override + void initState() { + super.initState(); + _exists = entry.path != null ? File(entry.path).exists() : SynchronousFuture(true); + } @override Widget build(BuildContext context) { return GestureDetector( - onTap: () => onTap?.call(), - // use a `Container` with a dummy color to make it expand - // so that we can also detect taps around the title `Text` + onTap: () => widget.onTap?.call(), + // use container to expand constraints, so that the user can tap anywhere child: Container( - color: Colors.transparent, - child: EmptyContent( - icon: AIcons.error, - text: 'Oops!', - alignment: Alignment.center, - ), + // opaque to cover potential lower quality layer below + color: Colors.black, + child: FutureBuilder( + future: _exists, + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) return SizedBox(); + final exists = snapshot.data; + return EmptyContent( + icon: AIcons.error, + text: exists ? 'Oops!' : 'The file no longer exists.', + alignment: Alignment.center, + ); + }), ), ); }