Przeglądaj źródła

Add support for changing cover photo

Neeraj Gupta 2 lat temu
rodzic
commit
1bea43897b

+ 1 - 0
lib/events/files_updated_event.dart

@@ -25,4 +25,5 @@ enum EventType {
   unarchived,
   hide,
   unhide,
+  coverChanged,
 }

+ 10 - 0
lib/ui/viewer/gallery/gallery_app_bar_widget.dart

@@ -27,6 +27,7 @@ import "package:photos/ui/map/map_screen.dart";
 import 'package:photos/ui/sharing/album_participants_page.dart';
 import 'package:photos/ui/sharing/share_collection_page.dart';
 import 'package:photos/ui/tools/free_space_page.dart';
+import "package:photos/ui/viewer/gallery/pick_cover_photo.dart";
 import 'package:photos/utils/data_util.dart';
 import 'package:photos/utils/dialog_util.dart';
 import 'package:photos/utils/magic_util.dart';
@@ -460,6 +461,8 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
               await _leaveAlbum(context);
             } else if (value == AlbumPopupAction.freeUpSpace) {
               await _deleteBackedUpFiles(context);
+            } else if (value == AlbumPopupAction.setCover) {
+              await setCoverPhoto(context);
             } else if (value == AlbumPopupAction.sort) {
               await _showSortOption(context);
             } else if (value == AlbumPopupAction.sharedArchive) {
@@ -487,6 +490,13 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     return actions;
   }
 
+  Future<void> setCoverPhoto(BuildContext context) async {
+    final file = await showPickCoverPhotoSheet(context, widget.collection!);
+    if (file != null) {
+      changeCoverPhoto(context, widget.collection!, file);
+    }
+  }
+
   Future<void> showOnMap() async {
     final bool result = await requestForMapEnable(context);
     if (result) {

+ 181 - 0
lib/ui/viewer/gallery/pick_cover_photo.dart

@@ -0,0 +1,181 @@
+import "dart:math";
+
+import "package:flutter/material.dart";
+import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
+import "package:photos/core/event_bus.dart";
+import "package:photos/db/files_db.dart";
+import "package:photos/events/collection_updated_event.dart";
+import "package:photos/generated/l10n.dart";
+import "package:photos/models/collection.dart";
+import "package:photos/models/file.dart";
+import "package:photos/models/file_load_result.dart";
+import "package:photos/models/selected_files.dart";
+import "package:photos/services/ignored_files_service.dart";
+import "package:photos/theme/colors.dart";
+import "package:photos/theme/ente_theme.dart";
+import "package:photos/ui/components/bottom_of_title_bar_widget.dart";
+import "package:photos/ui/components/buttons/button_widget.dart";
+import "package:photos/ui/components/models/button_type.dart";
+import "package:photos/ui/components/title_bar_title_widget.dart";
+import "package:photos/ui/viewer/gallery/gallery.dart";
+
+Future<File?> showPickCoverPhotoSheet(
+  BuildContext context,
+  Collection collection,
+) async {
+  return await showBarModalBottomSheet(
+    context: context,
+    builder: (context) {
+      return PickCoverPhotoWidget(collection);
+    },
+    shape: const RoundedRectangleBorder(
+      side: BorderSide(width: 0),
+      borderRadius: BorderRadius.vertical(
+        top: Radius.circular(5),
+      ),
+    ),
+    topControl: const SizedBox.shrink(),
+    backgroundColor: getEnteColorScheme(context).backgroundElevated,
+    barrierColor: backdropFaintDark,
+    enableDrag: false,
+  );
+}
+
+class PickCoverPhotoWidget extends StatelessWidget {
+  final Collection collection;
+
+  const PickCoverPhotoWidget(
+    this.collection, {
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final ValueNotifier<bool> isFileSelected = ValueNotifier(false);
+    final selectedFiles = SelectedFiles();
+    selectedFiles.addListener(() {
+      isFileSelected.value = selectedFiles.files.isNotEmpty;
+    });
+
+    return Padding(
+      padding: const EdgeInsets.all(0),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: [
+          ConstrainedBox(
+            constraints: BoxConstraints(
+              maxWidth: min(428, MediaQuery.of(context).size.width),
+            ),
+            child: Padding(
+              padding: const EdgeInsets.fromLTRB(0, 32, 0, 8),
+              child: Column(
+                mainAxisSize: MainAxisSize.max,
+                children: [
+                  Expanded(
+                    child: Column(
+                      children: [
+                        BottomOfTitleBarWidget(
+                          title: const TitleBarTitleWidget(
+                            title: "Select cover photo",
+                          ),
+                          caption: collection.displayName,
+                        ),
+                        Expanded(
+                          child: Gallery(
+                            asyncLoader: (
+                              creationStartTime,
+                              creationEndTime, {
+                              limit,
+                              asc,
+                            }) async {
+                              final FileLoadResult result =
+                                  await FilesDB.instance.getFilesInCollection(
+                                collection.id,
+                                creationStartTime,
+                                creationEndTime,
+                                limit: limit,
+                                asc: asc,
+                              );
+                              // hide ignored files from home page UI
+                              final ignoredIDs =
+                                  await IgnoredFilesService.instance.ignoredIDs;
+                              result.files.removeWhere(
+                                (f) =>
+                                    f.uploadedFileID == null &&
+                                    IgnoredFilesService.instance
+                                        .shouldSkipUpload(ignoredIDs, f),
+                              );
+                              return result;
+                            },
+                            reloadEvent:
+                                Bus.instance.on<CollectionUpdatedEvent>().where(
+                                      (event) =>
+                                          event.collectionID == collection.id,
+                                    ),
+                            tagPrefix: "pick_center_point_gallery",
+                            selectedFiles: selectedFiles,
+                            limitSelectionToOne: true,
+                            showSelectAllByDefault: false,
+                            sortAsyncFn: () =>
+                                collection.pubMagicMetadata.asc ?? false,
+                          ),
+                        ),
+                      ],
+                    ),
+                  ),
+                  SafeArea(
+                    child: Container(
+                      //inner stroke of 1pt + 15 pts of top padding = 16 pts
+                      padding: const EdgeInsets.fromLTRB(16, 15, 16, 8),
+                      decoration: BoxDecoration(
+                        border: Border(
+                          top: BorderSide(
+                            color: getEnteColorScheme(context).strokeFaint,
+                          ),
+                        ),
+                      ),
+                      child: Column(
+                        children: [
+                          ValueListenableBuilder(
+                            valueListenable: isFileSelected,
+                            builder: (context, bool value, _) {
+                              return AnimatedSwitcher(
+                                duration: const Duration(milliseconds: 300),
+                                switchInCurve: Curves.easeInOutExpo,
+                                switchOutCurve: Curves.easeInOutExpo,
+                                child: ButtonWidget(
+                                  key: ValueKey(value),
+                                  isDisabled: !value,
+                                  buttonType: ButtonType.neutral,
+                                  labelText: S.of(context).useSelectedPhoto,
+                                  onTap: () async {
+                                    final selectedFile =
+                                        selectedFiles.files.first;
+                                    Navigator.pop(context, selectedFile);
+                                  },
+                                ),
+                              );
+                            },
+                          ),
+                          const SizedBox(height: 8),
+                          ButtonWidget(
+                            buttonType: ButtonType.secondary,
+                            buttonAction: ButtonAction.cancel,
+                            labelText: S.of(context).cancel,
+                            onTap: () async {
+                              Navigator.of(context).pop();
+                            },
+                          ),
+                        ],
+                      ),
+                    ),
+                  )
+                ],
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 26 - 0
lib/utils/magic_util.dart

@@ -3,6 +3,8 @@ import 'package:logging/logging.dart';
 import 'package:path/path.dart';
 import 'package:photos/core/event_bus.dart';
 import "package:photos/events/collection_meta_event.dart";
+import "package:photos/events/collection_updated_event.dart";
+import "package:photos/events/files_updated_event.dart";
 import 'package:photos/events/force_reload_home_gallery_event.dart';
 import "package:photos/generated/l10n.dart";
 import 'package:photos/models/collection.dart';
@@ -103,6 +105,30 @@ Future<void> changeSortOrder(
   }
 }
 
+Future<void> changeCoverPhoto(
+  BuildContext context,
+  Collection collection,
+  File file,
+) async {
+  try {
+    final Map<String, dynamic> update = {"coverID": file.uploadedFileID};
+    await CollectionsService.instance
+        .updatePublicMagicMetadata(collection, update);
+    Bus.instance.fire(
+      CollectionUpdatedEvent(
+        collection.id,
+        <File>[],
+        "cover_change",
+        type: EventType.coverChanged,
+      ),
+    );
+  } catch (e, s) {
+    _logger.severe("failed to update cover", e, s);
+    showShortToast(context, S.of(context).somethingWentWrong);
+    rethrow;
+  }
+}
+
 Future<bool> editTime(
   BuildContext context,
   List<File> files,