瀏覽代碼

Merge remote-tracking branch 'origin' into ui_updates

vishnukvmd 3 年之前
父節點
當前提交
d370735c70
共有 3 個文件被更改,包括 190 次插入4 次删除
  1. 21 0
      lib/services/collections_service.dart
  2. 98 0
      lib/ui/change_collection_name_dialog.dart
  3. 71 4
      lib/ui/gallery_app_bar_widget.dart

+ 21 - 0
lib/services/collections_service.dart

@@ -231,6 +231,27 @@ class CollectionsService {
     }
   }
 
+  Future<void> rename(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()}),
+      );
+      // trigger sync to fetch the latest name from server
+      sync();
+    } 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 a new 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, "name 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());
+          },
+        ),
+      ],
+    );
+  }
+}

+ 71 - 4
lib/ui/gallery_app_bar_widget.dart

@@ -4,6 +4,7 @@ import 'dart:io';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:fluttertoast/fluttertoast.dart';
+import 'package:intl/intl.dart';
 import 'package:logging/logging.dart';
 import 'package:page_transition/page_transition.dart';
 import 'package:photos/core/configuration.dart';
@@ -13,7 +14,9 @@ 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/password_entry_page.dart';
 import 'package:photos/ui/share_collection_widget.dart';
 import 'package:photos/utils/delete_file_util.dart';
 import 'package:photos/utils/dialog_util.dart';
@@ -54,6 +57,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
   final _logger = Logger("GalleryAppBar");
   StreamSubscription _userAuthEventSubscription;
   Function() _selectedFilesListener;
+  String _appBarTitle;
 
   @override
   void initState() {
@@ -65,6 +69,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
         Bus.instance.on<SubscriptionPurchasedEvent>().listen((event) {
       setState(() {});
     });
+    _appBarTitle = widget.title;
     super.initState();
   }
 
@@ -85,11 +90,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(
+                  _appBarTitle,
+                  style: TextStyle(
+                    color: Colors.white.withOpacity(0.80),
+                  ),
                 ),
+                onPressed: () => _renameAlbum(context),
               ),
         actions: _getDefaultActions(context),
       );
@@ -110,6 +118,38 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     );
   }
 
+  Future<dynamic> _renameAlbum(BuildContext context) async {
+    if (widget.type != GalleryAppBarType.owned_collection) {
+      return;
+    }
+    final result = await showDialog(
+      context: context,
+      builder: (BuildContext context) {
+        return ChangeCollectionNameDialog(name: _appBarTitle);
+      },
+      barrierColor: Colors.black.withOpacity(0.85),
+    );
+    // indicates user cancelled the rename request
+    if (result == null) {
+      return;
+    }
+
+    final dialog = createProgressDialog(context, "changing name...");
+    await dialog.show();
+    try {
+      await CollectionsService.instance
+          .rename(widget.collection, result);
+      await dialog.hide();
+      if (mounted) {
+        _appBarTitle = result;
+        setState(() {});
+      }
+    } catch (e) {
+      await dialog.hide();
+      showGenericErrorDialog(context);
+    }
+  }
+
   List<Widget> _getDefaultActions(BuildContext context) {
     List<Widget> actions = <Widget>[];
     if (Configuration.instance.hasConfiguredAccount() &&
@@ -127,6 +167,33 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
         ),
       );
     }
+    if (widget.type == GalleryAppBarType.owned_collection) {
+      actions.add(PopupMenuButton(
+        itemBuilder: (context) {
+          final List<PopupMenuItem> items = [];
+          items.add(
+            PopupMenuItem(
+              value: 1,
+              child: Row(
+                children: [
+                  Icon(Icons.drive_file_rename_outline),
+                  Padding(
+                    padding: EdgeInsets.all(8),
+                  ),
+                  Text("rename"),
+                ],
+              ),
+            ),
+          );
+          return items;
+        },
+        onSelected: (value) async {
+          if (value == 1) {
+            await _renameAlbum(context);
+          }
+        },
+      ));
+    }
     return actions;
   }