Browse Source

Add support for renaming own collections

Neeraj Gupta 3 years ago
parent
commit
c6422c6a8b

+ 19 - 0
lib/services/collections_service.dart

@@ -231,6 +231,25 @@ class CollectionsService {
     }
   }
 
+  Future<void> renameCollection(Collection collection, String newName) async {
+    try {
+      final encryptedName = CryptoUtil.encryptSync(utf8.encode(newName), getCollectionKey(collection.id));
+      await _dio.post(
+        Configuration.instance.getHttpEndpoint() + "/collections/rename",
+        data: {
+          "collectionID": collection.id,
+          "encryptedName": Sodium.bin2base64(encryptedName.encryptedData),
+          "nameDecryptionNonce": Sodium.bin2base64(encryptedName.nonce)
+        },
+        options: Options(
+            headers: {"X-Auth-Token": Configuration.instance.getToken()}),
+      );
+    } catch (e, s) {
+      _logger.severe("failed to rename collection", e, s);
+      rethrow;
+    }
+  }
+
   Future<List<Collection>> _fetchCollections(int sinceTime) async {
     try {
       final response = await _dio.get(

+ 98 - 0
lib/ui/change_collection_name_dialog.dart

@@ -0,0 +1,98 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:photos/services/user_service.dart';
+import 'package:photos/utils/dialog_util.dart';
+import 'package:photos/utils/email_util.dart';
+import 'package:photos/utils/toast_util.dart';
+
+class ChangeCollectionNameDialog extends StatefulWidget {
+  final String name;
+
+  const ChangeCollectionNameDialog({Key key, this.name}) : super(key: key);
+
+  @override
+  _ChangeCollectionNameDialogState createState() =>
+      _ChangeCollectionNameDialogState();
+}
+
+class _ChangeCollectionNameDialogState
+    extends State<ChangeCollectionNameDialog> {
+  String _newCollectionName;
+
+  @override
+  void initState() {
+    super.initState();
+    _newCollectionName = widget.name;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AlertDialog(
+      title: Text("enter new album name"),
+      content: SingleChildScrollView(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.start,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            TextFormField(
+              decoration: InputDecoration(
+                hintText: 'album name',
+                hintStyle: TextStyle(
+                  color: Colors.white30,
+                ),
+                contentPadding: EdgeInsets.all(12),
+              ),
+              onChanged: (value) {
+                setState(() {
+                  _newCollectionName = value;
+                });
+              },
+              autocorrect: false,
+              keyboardType: TextInputType.text,
+              initialValue: _newCollectionName,
+              autofocus: true,
+            ),
+          ],
+        ),
+      ),
+      actions: [
+        TextButton(
+          child: Text(
+            "cancel",
+            style: TextStyle(
+              color: Colors.redAccent,
+            ),
+          ),
+          onPressed: () {
+            Navigator.of(context).pop(null);
+          },
+        ),
+        TextButton(
+          child: Text(
+            "rename",
+            style: TextStyle(
+              color: Colors.white,
+            ),
+          ),
+          onPressed: () {
+            if (_newCollectionName.trim().isEmpty) {
+              showErrorDialog(
+                  context, "empty name", "album name cannot be empty");
+              return;
+            }
+            if (_newCollectionName.trim().length > 100) {
+              showErrorDialog(context, "too large",
+                  "album name should be less than 100 characters");
+              return;
+            }
+            if (_newCollectionName.trim() == widget.name.trim()) {
+              Navigator.of(context).pop(null);
+              return;
+            }
+            Navigator.of(context).pop(_newCollectionName.trim());
+          },
+        ),
+      ],
+    );
+  }
+}

+ 41 - 9
lib/ui/gallery_app_bar_widget.dart

@@ -13,6 +13,7 @@ import 'package:photos/models/collection.dart';
 import 'package:photos/models/magic_metadata.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/services/collections_service.dart';
+import 'package:photos/ui/change_collection_name_dialog.dart';
 import 'package:photos/ui/create_collection_page.dart';
 import 'package:photos/ui/share_collection_widget.dart';
 import 'package:photos/utils/delete_file_util.dart';
@@ -85,11 +86,14 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
         elevation: 0,
         title: widget.type == GalleryAppBarType.homepage
             ? Container()
-            : Text(
-                widget.title,
-                style: TextStyle(
-                  color: Colors.white.withOpacity(0.80),
+            : TextButton(
+                child: Text(
+                  widget.title,
+                  style: TextStyle(
+                    color: Colors.white.withOpacity(0.80),
+                  ),
                 ),
+                onPressed: () => _renameAlbum(context),
               ),
         actions: _getDefaultActions(context),
       );
@@ -107,6 +111,33 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     );
   }
 
+  Future<dynamic> _renameAlbum(BuildContext context) async {
+    if (widget.type != GalleryAppBarType.owned_collection) {
+      return;
+    }
+    var result = await showDialog(
+                context: context,
+                builder: (BuildContext context) {
+                  return ChangeCollectionNameDialog(name: widget.title);
+                },
+                barrierColor: Colors.black.withOpacity(0.85),
+                // barrierDismissible: false,
+              );
+    if (result == null) {
+      return;
+    }
+
+    final dialog = createProgressDialog(context, "changing name...");
+    await dialog.show();
+    try {
+      await CollectionsService.instance.renameCollection(widget.collection, result);
+      await dialog.hide();
+    } catch(e,s) {
+      await dialog.hide();
+      showGenericErrorDialog(context);
+    }
+  }
+
   List<Widget> _getDefaultActions(BuildContext context) {
     List<Widget> actions = <Widget>[];
     if (Configuration.instance.hasConfiguredAccount() &&
@@ -268,7 +299,8 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
         },
         onSelected: (value) async {
           if (value == 1) {
-            await _handleVisibilityChangeRequest(context, showArchive ? kVisibilityArchive : kVisibilityVisible);
+            await _handleVisibilityChangeRequest(
+                context, showArchive ? kVisibilityArchive : kVisibilityVisible);
           }
         },
       ));
@@ -276,13 +308,13 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     return actions;
   }
 
-  Future<void> _handleVisibilityChangeRequest(BuildContext context,
-      int newVisibility) async {
+  Future<void> _handleVisibilityChangeRequest(
+      BuildContext context, int newVisibility) async {
     final dialog = createProgressDialog(context, "please wait...");
     await dialog.show();
     try {
-      await FileMagicService.instance.changeVisibility(
-          widget.selectedFiles.files.toList(), newVisibility);
+      await FileMagicService.instance
+          .changeVisibility(widget.selectedFiles.files.toList(), newVisibility);
       showToast(
           newVisibility == kVisibilityArchive
               ? "successfully archived"