diff --git a/app/lib/widget/viewer.dart b/app/lib/widget/viewer.dart index ee5f9ccb..61ce5dc9 100644 --- a/app/lib/widget/viewer.dart +++ b/app/lib/widget/viewer.dart @@ -29,6 +29,7 @@ import 'package:nc_photos/flutter_util.dart'; import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/live_photo_util.dart'; import 'package:nc_photos/platform/features.dart' as features; +import 'package:nc_photos/set_as_handler.dart'; import 'package:nc_photos/share_handler.dart'; import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/theme.dart'; @@ -183,6 +184,10 @@ class _WrappedViewerState extends State<_WrappedViewer> selector: (state) => state.slideshowRequest, listener: _onSlideshowRequest, ), + _BlocListenerT( + selector: (state) => state.setAsRequest, + listener: _onSetAsRequest, + ), _BlocListenerT( selector: (state) => state.error, listener: (context, error) { @@ -257,6 +262,19 @@ class _WrappedViewerState extends State<_WrappedViewer> context.addEvent(_RequestPage(newIndex)); } } + + void _onSetAsRequest( + BuildContext context, + Unique<_SetAsRequest?> setAsRequest, + ) { + if (setAsRequest.value == null) { + return; + } + SetAsHandler( + KiwiContainer().resolve(), + context: context, + ).setAsFile(setAsRequest.value!.account, setAsRequest.value!.file); + } } typedef _BlocBuilder = BlocBuilder<_Bloc, _State>; diff --git a/app/lib/widget/viewer.g.dart b/app/lib/widget/viewer.g.dart index 296409be..fb56c6d1 100644 --- a/app/lib/widget/viewer.g.dart +++ b/app/lib/widget/viewer.g.dart @@ -38,6 +38,7 @@ abstract class $_StateCopyWithWorker { Unique? imageEnhancerRequest, Unique<_ShareRequest?>? shareRequest, Unique<_SlideshowRequest?>? slideshowRequest, + Unique<_SetAsRequest?>? setAsRequest, ExceptionEvent? error}); } @@ -70,6 +71,7 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker { dynamic imageEnhancerRequest, dynamic shareRequest, dynamic slideshowRequest, + dynamic setAsRequest, dynamic error = copyWithNull}) { return _State( fileIdOrders: fileIdOrders as List? ?? that.fileIdOrders, @@ -121,6 +123,8 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker { shareRequest as Unique<_ShareRequest?>? ?? that.shareRequest, slideshowRequest: slideshowRequest as Unique<_SlideshowRequest?>? ?? that.slideshowRequest, + setAsRequest: + setAsRequest as Unique<_SetAsRequest?>? ?? that.setAsRequest, error: error == copyWithNull ? that.error : error as ExceptionEvent?); } @@ -202,7 +206,7 @@ extension _$_PageViewStateNpLog on _PageViewState { extension _$_StateToString on _State { String _$toString() { // ignore: unnecessary_string_interpolations - return "_State {fileIdOrders: $fileIdOrders, files: {length: ${files.length}}, fileStates: {length: ${fileStates.length}}, index: $index, currentFile: ${currentFile == null ? null : "${currentFile!.fdPath}"}, currentFileState: $currentFileState, collection: $collection, collectionItemsController: $collectionItemsController, collectionItems: ${collectionItems == null ? null : "{length: ${collectionItems!.length}}"}, isShowDetailPane: $isShowDetailPane, isClosingDetailPane: $isClosingDetailPane, isDetailPaneActive: $isDetailPaneActive, openDetailPaneRequest: $openDetailPaneRequest, closeDetailPane: $closeDetailPane, isZoomed: $isZoomed, isInitialLoad: $isInitialLoad, isShowAppBar: $isShowAppBar, appBarButtons: [length: ${appBarButtons.length}], bottomAppBarButtons: [length: ${bottomAppBarButtons.length}], pendingRemovePage: $pendingRemovePage, imageEditorRequest: $imageEditorRequest, imageEnhancerRequest: $imageEnhancerRequest, shareRequest: $shareRequest, slideshowRequest: $slideshowRequest, error: $error}"; + return "_State {fileIdOrders: $fileIdOrders, files: {length: ${files.length}}, fileStates: {length: ${fileStates.length}}, index: $index, currentFile: ${currentFile == null ? null : "${currentFile!.fdPath}"}, currentFileState: $currentFileState, collection: $collection, collectionItemsController: $collectionItemsController, collectionItems: ${collectionItems == null ? null : "{length: ${collectionItems!.length}}"}, isShowDetailPane: $isShowDetailPane, isClosingDetailPane: $isClosingDetailPane, isDetailPaneActive: $isDetailPaneActive, openDetailPaneRequest: $openDetailPaneRequest, closeDetailPane: $closeDetailPane, isZoomed: $isZoomed, isInitialLoad: $isInitialLoad, isShowAppBar: $isShowAppBar, appBarButtons: [length: ${appBarButtons.length}], bottomAppBarButtons: [length: ${bottomAppBarButtons.length}], pendingRemovePage: $pendingRemovePage, imageEditorRequest: $imageEditorRequest, imageEnhancerRequest: $imageEnhancerRequest, shareRequest: $shareRequest, slideshowRequest: $slideshowRequest, setAsRequest: $setAsRequest, error: $error}"; } } @@ -374,6 +378,13 @@ extension _$_StartSlideshowToString on _StartSlideshow { } } +extension _$_SetAsToString on _SetAs { + String _$toString() { + // ignore: unnecessary_string_interpolations + return "_SetAs {fileId: $fileId}"; + } +} + extension _$_OpenDetailPaneToString on _OpenDetailPane { String _$toString() { // ignore: unnecessary_string_interpolations diff --git a/app/lib/widget/viewer/app_bar.dart b/app/lib/widget/viewer/app_bar.dart index 1ccf8fb4..c34490b8 100644 --- a/app/lib/widget/viewer/app_bar.dart +++ b/app/lib/widget/viewer/app_bar.dart @@ -161,5 +161,13 @@ Widget? _buildAppBarButton( return const _AppBarDownloadButton(); case ViewerAppBarButtonType.delete: return collection == null ? const _AppBarDeleteButton() : null; + case ViewerAppBarButtonType.archive: + return currentFile?.fdIsArchived == true + ? const _AppBarUnarchiveButton() + : const _AppBarArchiveButton(); + case ViewerAppBarButtonType.slideshow: + return const _AppBarSlideshowButton(); + case ViewerAppBarButtonType.setAs: + return const _AppBarSetAsButton(); } } diff --git a/app/lib/widget/viewer/app_bar_buttons.dart b/app/lib/widget/viewer/app_bar_buttons.dart index 63aeacd4..ee2737a7 100644 --- a/app/lib/widget/viewer/app_bar_buttons.dart +++ b/app/lib/widget/viewer/app_bar_buttons.dart @@ -9,6 +9,9 @@ enum ViewerAppBarButtonType { enhance, download, delete, + archive, + slideshow, + setAs, ; static ViewerAppBarButtonType fromValue(int value) => @@ -158,3 +161,67 @@ class _AppBarDeleteButton extends StatelessWidget { ); } } + +class _AppBarUnarchiveButton extends StatelessWidget { + const _AppBarUnarchiveButton(); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon(Icons.unarchive_outlined), + tooltip: L10n.global().unarchiveTooltip, + onPressed: () { + context.state.currentFile?.fdId + .let((id) => context.addEvent(_Unarchive(id))); + }, + ); + } +} + +class _AppBarArchiveButton extends StatelessWidget { + const _AppBarArchiveButton(); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon(Icons.archive_outlined), + tooltip: L10n.global().archiveTooltip, + onPressed: () { + context.state.currentFile?.fdId + .let((id) => context.addEvent(_Archive(id))); + }, + ); + } +} + +class _AppBarSlideshowButton extends StatelessWidget { + const _AppBarSlideshowButton(); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon(Icons.slideshow_outlined), + tooltip: L10n.global().slideshowTooltip, + onPressed: () { + context.state.currentFile?.fdId + .let((id) => context.addEvent(_StartSlideshow(id))); + }, + ); + } +} + +class _AppBarSetAsButton extends StatelessWidget { + const _AppBarSetAsButton(); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon(Icons.launch), + tooltip: L10n.global().setAsTooltip, + onPressed: () { + context.state.currentFile?.fdId + .let((id) => context.addEvent(_SetAs(id))); + }, + ); + } +} diff --git a/app/lib/widget/viewer/bloc.dart b/app/lib/widget/viewer/bloc.dart index b97abfb1..454e2d61 100644 --- a/app/lib/widget/viewer/bloc.dart +++ b/app/lib/widget/viewer/bloc.dart @@ -45,6 +45,7 @@ class _Bloc extends Bloc<_Event, _State> on<_Delete>(_onDelete); on<_RemoveFromCollection>(_onRemoveFromCollection); on<_StartSlideshow>(_onStartSlideshow); + on<_SetAs>(_onSetAs); on<_OpenDetailPane>(_onOpenDetailPane); on<_CloseDetailPane>(_onCloseDetailPane); @@ -350,6 +351,20 @@ class _Bloc extends Bloc<_Event, _State> emit(state.copyWith(slideshowRequest: Unique(req))); } + void _onSetAs(_SetAs ev, _Emitter emit) { + _log.info(ev); + final f = state.files[ev.fileId]; + if (f == null) { + _log.severe("[_onSetAs] file is null: ${ev.fileId}"); + return; + } + final req = _SetAsRequest( + account: account, + file: f, + ); + emit(state.copyWith(setAsRequest: Unique(req))); + } + void _onOpenDetailPane(_OpenDetailPane ev, _Emitter emit) { _log.info(ev); emit(state.copyWith( diff --git a/app/lib/widget/viewer/state_event.dart b/app/lib/widget/viewer/state_event.dart index 9cb64fe0..7fa21373 100644 --- a/app/lib/widget/viewer/state_event.dart +++ b/app/lib/widget/viewer/state_event.dart @@ -28,6 +28,7 @@ class _State { required this.imageEnhancerRequest, required this.shareRequest, required this.slideshowRequest, + required this.setAsRequest, this.error, }); @@ -59,6 +60,7 @@ class _State { imageEnhancerRequest: Unique(null), shareRequest: Unique(null), slideshowRequest: Unique(null), + setAsRequest: Unique(null), ); @override @@ -94,6 +96,7 @@ class _State { final Unique imageEnhancerRequest; final Unique<_ShareRequest?> shareRequest; final Unique<_SlideshowRequest?> slideshowRequest; + final Unique<_SetAsRequest?> setAsRequest; final ExceptionEvent? error; } @@ -348,6 +351,16 @@ class _StartSlideshow implements _Event { final int fileId; } +@toString +class _SetAs implements _Event { + const _SetAs(this.fileId); + + @override + String toString() => _$toString(); + + final int fileId; +} + @toString class _OpenDetailPane implements _Event { const _OpenDetailPane(this.shouldAnimate); diff --git a/app/lib/widget/viewer/type.dart b/app/lib/widget/viewer/type.dart index 4db56e94..014de030 100644 --- a/app/lib/widget/viewer/type.dart +++ b/app/lib/widget/viewer/type.dart @@ -23,3 +23,13 @@ class _SlideshowRequest { final List files; final int startIndex; } + +class _SetAsRequest { + const _SetAsRequest({ + required this.account, + required this.file, + }); + + final Account account; + final FileDescriptor file; +}