Set/unset favorite in viewer

This commit is contained in:
Ming Ming 2022-01-25 18:17:19 +08:00
parent 3b8f0f09d4
commit abe997f274
7 changed files with 192 additions and 8 deletions

View file

@ -575,6 +575,7 @@ class FileRepo {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
}) =>
dataSrc.updateProperty(
account,
@ -582,6 +583,7 @@ class FileRepo {
metadata: metadata,
isArchived: isArchived,
overrideDateTime: overrideDateTime,
favorite: favorite,
);
/// See [FileDataSource.copy]
@ -642,6 +644,7 @@ abstract class FileDataSource {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
});
/// Copy [f] to [destination]

View file

@ -148,6 +148,7 @@ class FileWebdavDataSource implements FileDataSource {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
}) async {
_log.info("[updateProperty] ${f.path}");
if (metadata?.obj != null && metadata!.obj!.fileEtag != f.etag) {
@ -161,6 +162,7 @@ class FileWebdavDataSource implements FileDataSource {
if (overrideDateTime?.obj != null)
"app:override-date-time":
overrideDateTime!.obj!.toUtc().toIso8601String(),
if (favorite != null) "oc:favorite": favorite ? 1 : 0,
};
final removeProps = [
if (OrNull.isSetNull(metadata)) "app:metadata",
@ -171,6 +173,7 @@ class FileWebdavDataSource implements FileDataSource {
path: f.path,
namespaces: {
"com.nkming.nc_photos": "app",
"http://owncloud.org/ns": "oc",
},
set: setProps.isNotEmpty ? setProps : null,
remove: removeProps.isNotEmpty ? removeProps : null,
@ -373,6 +376,7 @@ class FileAppDbDataSource implements FileDataSource {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
}) {
_log.info("[updateProperty] ${f.path}");
return appDb.use((db) async {
@ -384,6 +388,7 @@ class FileAppDbDataSource implements FileDataSource {
metadata: metadata,
isArchived: isArchived,
overrideDateTime: overrideDateTime,
isFavorite: favorite,
);
final fileStore = transaction.objectStore(AppDb.file2StoreName);
await fileStore.put(AppDbFile2Entry.fromFile(account, newFile).toJson(),
@ -501,6 +506,7 @@ class FileCachedDataSource implements FileDataSource {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
}) async {
await _remoteSrc
.updateProperty(
@ -509,6 +515,7 @@ class FileCachedDataSource implements FileDataSource {
metadata: metadata,
isArchived: isArchived,
overrideDateTime: overrideDateTime,
favorite: favorite,
)
.then((_) => _appDbSrc.updateProperty(
account,
@ -516,6 +523,7 @@ class FileCachedDataSource implements FileDataSource {
metadata: metadata,
isArchived: isArchived,
overrideDateTime: overrideDateTime,
favorite: favorite,
));
// generate a new random token

View file

@ -1127,6 +1127,30 @@
"@collectionFavoritesLabel": {
"description": "Browse photos added to favorites"
},
"favoriteTooltip": "Favorite",
"@favoriteTooltip": {
"description": "Add photo to favorites"
},
"favoriteSuccessNotification": "Added to favorites",
"@favoriteSuccessNotification": {
"description": "Successfully added photos to favorites"
},
"favoriteFailureNotification": "Failed adding to favorites",
"@favoriteFailureNotification": {
"description": "Failed adding photos to favorites"
},
"unfavoriteTooltip": "Unfavorite",
"@unfavoriteTooltip": {
"description": "Remove photo to favorites"
},
"unfavoriteSuccessNotification": "Removed from favorites",
"@unfavoriteSuccessNotification": {
"description": "Successfully removed photos from favorites"
},
"unfavoriteFailureNotification": "Failed removing from favorites",
"@unfavoriteFailureNotification": {
"description": "Failed removing photos from favorites"
},
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
"@errorUnauthenticated": {

View file

@ -72,6 +72,12 @@
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification",
"errorAlbumDowngrade"
],
@ -162,6 +168,12 @@
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification",
"errorAlbumDowngrade"
],
@ -307,6 +319,12 @@
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification",
"errorAlbumDowngrade"
],
@ -335,6 +353,12 @@
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification",
"errorAlbumDowngrade"
],
@ -347,7 +371,13 @@
"convertAlbumTooltip",
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel"
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification"
],
"fr": [
@ -472,6 +502,12 @@
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification",
"errorAlbumDowngrade"
],
@ -484,7 +520,13 @@
"convertAlbumTooltip",
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel"
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification"
],
"ru": [
@ -582,6 +624,12 @@
"convertAlbumConfirmationDialogContent",
"convertAlbumSuccessNotification",
"collectionFavoritesLabel",
"favoriteTooltip",
"favoriteSuccessNotification",
"favoriteFailureNotification",
"unfavoriteTooltip",
"unfavoriteSuccessNotification",
"unfavoriteFailureNotification",
"errorAlbumDowngrade"
]
}

View file

@ -15,8 +15,12 @@ class UpdateProperty {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
}) async {
if (metadata == null && isArchived == null && overrideDateTime == null) {
if (metadata == null &&
isArchived == null &&
overrideDateTime == null &&
favorite == null) {
// ?
_log.warning("[call] Nothing to update");
return;
@ -32,6 +36,7 @@ class UpdateProperty {
metadata: metadata,
isArchived: isArchived,
overrideDateTime: overrideDateTime,
favorite: favorite,
);
int properties = 0;
@ -44,6 +49,9 @@ class UpdateProperty {
if (overrideDateTime != null) {
properties |= FilePropertyUpdatedEvent.propOverrideDateTime;
}
if (favorite != null) {
properties |= FilePropertyUpdatedEvent.propFavorite;
}
assert(properties != 0);
KiwiContainer()
.resolve<EventBus>()

View file

@ -5,17 +5,21 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/download_handler.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/notified_action.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/update_property.dart';
import 'package:nc_photos/widget/animated_visibility.dart';
import 'package:nc_photos/widget/disposable.dart';
import 'package:nc_photos/widget/handler/remove_selection_handler.dart';
@ -125,6 +129,9 @@ class _ViewerState extends State<Viewer>
}
Widget _buildAppBar(BuildContext context) {
final index =
_isViewerLoaded ? _viewerController.currentPage : widget.startIndex;
final file = widget.streamFiles[index];
return Wrap(
children: [
AnimatedVisibility(
@ -151,12 +158,25 @@ class _ViewerState extends State<Viewer>
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
actions: [
if (!_isDetailPaneActive && _canOpenDetailPane())
if (!_isDetailPaneActive && _canOpenDetailPane()) ...[
(_pageStates[index]?.favoriteOverride ?? file.isFavorite) ==
true
? IconButton(
icon: const Icon(Icons.star),
tooltip: L10n.global().unfavoriteTooltip,
onPressed: () => _onUnfavoritePressed(index),
)
: IconButton(
icon: const Icon(Icons.star_border),
tooltip: L10n.global().favoriteTooltip,
onPressed: () => _onFavoritePressed(index),
),
IconButton(
icon: const Icon(Icons.more_vert),
tooltip: L10n.global().detailsTooltip,
onPressed: _onDetailsPressed,
),
],
],
),
],
@ -454,6 +474,72 @@ class _ViewerState extends State<Viewer>
}
}
Future<void> _onFavoritePressed(int index) async {
if (_pageStates[index]!.isProcessingFavorite) {
_log.fine("[_onFavoritePressed] Process ongoing, ignored");
return;
}
final file = widget.streamFiles[_viewerController.currentPage];
final c = KiwiContainer().resolve<DiContainer>();
setState(() {
_pageStates[index]!.favoriteOverride = true;
});
_pageStates[index]!.isProcessingFavorite = true;
try {
await NotifiedAction(
() => UpdateProperty(c.fileRepo)(
widget.account,
file,
favorite: true,
),
null,
L10n.global().favoriteSuccessNotification,
failureText: L10n.global().favoriteFailureNotification,
)();
} catch (e, stackTrace) {
_log.shout(
"[_onFavoritePressed] Failed while UpdateProperty", e, stackTrace);
setState(() {
_pageStates[index]!.favoriteOverride = false;
});
}
_pageStates[index]!.isProcessingFavorite = false;
}
Future<void> _onUnfavoritePressed(int index) async {
if (_pageStates[index]!.isProcessingFavorite) {
_log.fine("[_onUnfavoritePressed] Process ongoing, ignored");
return;
}
final file = widget.streamFiles[_viewerController.currentPage];
final c = KiwiContainer().resolve<DiContainer>();
setState(() {
_pageStates[index]!.favoriteOverride = false;
});
_pageStates[index]!.isProcessingFavorite = true;
try {
await NotifiedAction(
() => UpdateProperty(c.fileRepo)(
widget.account,
file,
favorite: false,
),
null,
L10n.global().unfavoriteSuccessNotification,
failureText: L10n.global().unfavoriteFailureNotification,
)();
} catch (e, stackTrace) {
_log.shout(
"[_onUnfavoritePressed] Failed while UpdateProperty", e, stackTrace);
setState(() {
_pageStates[index]!.favoriteOverride = true;
});
}
_pageStates[index]!.isProcessingFavorite = false;
}
void _onDetailsPressed() {
if (!_isDetailPaneActive) {
setState(() {
@ -614,4 +700,7 @@ class _PageState {
ScrollController scrollController;
double? itemHeight;
bool hasLoaded = false;
bool isProcessingFavorite = false;
bool? favoriteOverride;
}

View file

@ -242,10 +242,14 @@ class MockFileRepo implements FileRepo {
}
@override
Future<void> updateProperty(Account account, File file,
{OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime}) {
Future<void> updateProperty(
Account account,
File file, {
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
bool? favorite,
}) {
throw UnimplementedError();
}
}