Browse Source

feat: Only show the change cover button and delete button when it's hovering. (#2145)

* feat: Only show the change cover button and delete button when it's hovering.

* feat: Only show the change cover button and delete button when it's hovering

---------

Co-authored-by: gitstart <[email protected]>
GitStart 2 years ago
parent
commit
473eb8bcbe

BIN
frontend/appflowy_flutter/assets/test/workspaces/cover_image.zip


+ 54 - 0
frontend/appflowy_flutter/integration_test/cover_image_test.dart

@@ -0,0 +1,54 @@
+import 'package:flowy_infra_ui/widget/rounded_button.dart';
+import 'package:flutter/gestures.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'util/util.dart';
+
+/// Integration tests for an empty board. The [TestWorkspaceService] will load
+/// a workspace from an empty board `assets/test/workspaces/board.zip` for all
+/// tests.
+///
+/// To create another integration test with a preconfigured workspace.
+/// Use the following steps.
+/// 1. Create a new workspace from the AppFlowy launch screen.
+/// 2. Modify the workspace until it is suitable as the starting point for
+///    the integration test you need to land.
+/// 3. Use a zip utility program to zip the workspace folder that you created.
+/// 4. Add the zip file under `assets/test/workspaces/`
+/// 5. Add a new enumeration to [TestWorkspace] in `integration_test/utils/data.dart`.
+///    For example, if you added a workspace called `empty_calendar.zip`,
+///    then [TestWorkspace] should have the following value:
+/// ```dart
+/// enum TestWorkspace {
+///   board('board'),
+///   empty_calendar('empty_calendar');
+///
+///   /* code */
+/// }
+/// ```
+/// 6. Double check that the .zip file that you added is included as an asset in
+///    the pubspec.yaml file under appflowy_flutter.
+void main() {
+  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+  const service = TestWorkspaceService(TestWorkspace.coverImage);
+
+  group('cover image', () {
+    setUpAll(() async => await service.setUpAll());
+    setUp(() async => await service.setUp());
+
+    testWidgets(
+        'hovering on cover image will display change and delete cover image buttons',
+        (tester) async {
+      await tester.initializeAppFlowy();
+      expect(find.byType(Image), findsOneWidget);
+
+      final TestPointer pointer = TestPointer(1, PointerDeviceKind.mouse);
+      final imageFinder = find.byType(Image);
+      Offset offset = tester.getCenter(imageFinder);
+
+      pointer.hover(offset);
+      expect(find.byType(RoundedTextButton), findsOneWidget);
+    });
+  });
+}

+ 2 - 1
frontend/appflowy_flutter/integration_test/util/data.dart

@@ -9,7 +9,8 @@ import 'package:shared_preferences/shared_preferences.dart';
 
 enum TestWorkspace {
   board("board"),
-  emptyDocument("empty_document");
+  emptyDocument("empty_document"),
+  coverImage("cover_image");
 
   const TestWorkspace(this._name);
 

+ 62 - 35
frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/cover/cover_node_widget.dart

@@ -393,21 +393,32 @@ class _CoverImageState extends State<_CoverImage> {
         mainAxisSize: MainAxisSize.min,
         children: [
           AppFlowyPopover(
+            onClose: () {
+              setOverlayButtonsHidden(true);
+            },
             offset: const Offset(-125, 10),
             controller: popoverController,
             direction: PopoverDirection.bottomWithCenterAligned,
             constraints: BoxConstraints.loose(const Size(380, 450)),
             margin: EdgeInsets.zero,
-            child: RoundedTextButton(
-              onPressed: () {
-                popoverController.show();
-              },
-              hoverColor: Theme.of(context).colorScheme.surface,
-              textColor: Theme.of(context).colorScheme.tertiary,
-              fillColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
-              width: 120,
-              height: 28,
-              title: LocaleKeys.document_plugins_cover_changeCover.tr(),
+            child: Visibility(
+              maintainState: true,
+              maintainAnimation: true,
+              maintainSize: true,
+              visible: !isOverlayButtonsHidden,
+              child: RoundedTextButton(
+                onPressed: () {
+                  popoverController.show();
+                  setOverlayButtonsHidden(true);
+                },
+                hoverColor: Theme.of(context).colorScheme.surface,
+                textColor: Theme.of(context).colorScheme.onSurface,
+                fillColor:
+                    Theme.of(context).colorScheme.surface.withOpacity(0.8),
+                width: 120,
+                height: 28,
+                title: LocaleKeys.document_plugins_cover_changeCover.tr(),
+              ),
             ),
             popupBuilder: (BuildContext popoverContext) {
               return ChangeCoverPopover(
@@ -418,18 +429,24 @@ class _CoverImageState extends State<_CoverImage> {
             },
           ),
           const SizedBox(width: 10),
-          FlowyIconButton(
-            fillColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
-            hoverColor: Theme.of(context).colorScheme.surface,
-            iconPadding: const EdgeInsets.all(5),
-            width: 28,
-            icon: svgWidget(
-              'editor/delete',
-              color: Theme.of(context).colorScheme.tertiary,
+          Visibility(
+            maintainAnimation: true,
+            maintainSize: true,
+            maintainState: true,
+            visible: !isOverlayButtonsHidden,
+            child: FlowyIconButton(
+              fillColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
+              hoverColor: Theme.of(context).colorScheme.surface,
+              iconPadding: const EdgeInsets.all(5),
+              width: 28,
+              icon: svgWidget(
+                'editor/delete',
+                color: Theme.of(context).colorScheme.onSurface,
+              ),
+              onPressed: () {
+                widget.onCoverChanged(CoverSelectionType.initial, null);
+              },
             ),
-            onPressed: () {
-              widget.onCoverChanged(CoverSelectionType.initial, null);
-            },
           ),
         ],
       ),
@@ -477,20 +494,30 @@ class _CoverImageState extends State<_CoverImage> {
         break;
     }
 //OverflowBox needs to be wraped by a widget with constraints(or from its parent) first,otherwise it will occur an error
-    return SizedBox(
-      height: height,
-      child: OverflowBox(
-        maxWidth: screenSize.width,
-        child: Stack(
-          children: [
-            Container(
-              padding: const EdgeInsets.only(bottom: 10),
-              height: double.infinity,
-              width: double.infinity,
-              child: coverImage,
-            ),
-            hasCover ? _buildCoverOverlayButtons(context) : const SizedBox()
-          ],
+    return MouseRegion(
+      onEnter: (event) {
+        setOverlayButtonsHidden(false);
+      },
+      onExit: (event) {
+        setOverlayButtonsHidden(true);
+      },
+      child: SizedBox(
+        height: height,
+        child: OverflowBox(
+          maxWidth: screenSize.width,
+          child: Stack(
+            children: [
+              Container(
+                padding: const EdgeInsets.only(bottom: 10),
+                height: double.infinity,
+                width: double.infinity,
+                child: coverImage,
+              ),
+              hasCover
+                  ? _buildCoverOverlayButtons(context)
+                  : const SizedBox.shrink()
+            ],
+          ),
         ),
       ),
     );