From 49574d3ff0b31300de196d7c8854622e8df1e45f Mon Sep 17 00:00:00 2001
From: "Lucas.Xu" <lucas.xu@appflowy.io>
Date: Wed, 7 Dec 2022 10:59:28 +0800
Subject: [PATCH] fix: [Bug] Text formatting toolbar disappear under layout
 #1542

---
 .../src/render/toolbar/toolbar_widget.dart    |  3 ++
 .../lib/src/service/selection_service.dart    | 30 +++++++++++++++++--
 .../lib/src/service/toolbar_service.dart      |  5 ++--
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_widget.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_widget.dart
index d987b2f87b..2a03d96140 100644
--- a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_widget.dart
+++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_widget.dart
@@ -16,12 +16,14 @@ class ToolbarWidget extends StatefulWidget {
     required this.layerLink,
     required this.offset,
     required this.items,
+    this.aligment = Alignment.topLeft,
   }) : super(key: key);
 
   final EditorState editorState;
   final LayerLink layerLink;
   final Offset offset;
   final List<ToolbarItem> items;
+  final Alignment aligment;
 
   @override
   State<ToolbarWidget> createState() => _ToolbarWidgetState();
@@ -39,6 +41,7 @@ class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
         link: widget.layerLink,
         showWhenUnlinked: true,
         offset: widget.offset,
+        followerAnchor: widget.aligment,
         child: _buildToolbar(context),
       ),
     );
diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart
index 86d39ba826..22de73c429 100644
--- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart
+++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart
@@ -388,9 +388,11 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
 
     // TODO: need to be refactored.
     Offset? toolbarOffset;
+    Alignment? alignment;
     LayerLink? layerLink;
     final editorOffset =
         editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
+    final editorSize = editorState.renderBox?.size ?? Size.zero;
 
     final backwardNodes =
         selection.isBackward ? nodes : nodes.reversed.toList(growable: false);
@@ -438,10 +440,33 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
         // TODO: Need to compute more precise location.
         if ((selectionRect.topLeft.dy - editorOffset.dy) <=
             baseToolbarOffset.dy) {
-          toolbarOffset ??= rect.bottomLeft;
+          if (selectionRect.topLeft.dx <=
+              editorSize.width / 3.0 + editorOffset.dx) {
+            toolbarOffset ??= rect.bottomLeft;
+            alignment ??= Alignment.topLeft;
+          } else if (selectionRect.topRight.dx >=
+              editorSize.width * 2.0 / 3.0 + editorOffset.dx) {
+            toolbarOffset ??= rect.bottomRight;
+            alignment ??= Alignment.topRight;
+          } else {
+            toolbarOffset ??= rect.bottomCenter;
+            alignment ??= Alignment.topCenter;
+          }
         } else {
-          toolbarOffset ??= rect.topLeft - baseToolbarOffset;
+          if (selectionRect.topLeft.dx <=
+              editorSize.width / 3.0 + editorOffset.dx) {
+            toolbarOffset ??= rect.topLeft - baseToolbarOffset;
+            alignment ??= Alignment.topLeft;
+          } else if (selectionRect.topRight.dx >=
+              editorSize.width * 2.0 / 3.0 + editorOffset.dx) {
+            toolbarOffset ??= rect.topRight - baseToolbarOffset;
+            alignment ??= Alignment.topRight;
+          } else {
+            toolbarOffset ??= rect.topCenter - baseToolbarOffset;
+            alignment ??= Alignment.topCenter;
+          }
         }
+
         layerLink ??= node.layerLink;
 
         final overlay = OverlayEntry(
@@ -460,6 +485,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
     if (toolbarOffset != null && layerLink != null) {
       editorState.service.toolbarService?.showInOffset(
         toolbarOffset,
+        alignment!,
         layerLink,
       );
     }
diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart
index 8991d0a30a..9b9d002cd1 100644
--- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart
+++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart
@@ -8,7 +8,7 @@ import 'package:appflowy_editor/src/extensions/object_extensions.dart';
 
 abstract class AppFlowyToolbarService {
   /// Show the toolbar widget beside the offset.
-  void showInOffset(Offset offset, LayerLink layerLink);
+  void showInOffset(Offset offset, Alignment alignment, LayerLink layerLink);
 
   /// Hide the toolbar widget.
   void hide();
@@ -37,7 +37,7 @@ class _FlowyToolbarState extends State<FlowyToolbar>
   final _toolbarWidgetKey = GlobalKey(debugLabel: '_toolbar_widget');
 
   @override
-  void showInOffset(Offset offset, LayerLink layerLink) {
+  void showInOffset(Offset offset, Alignment alignment, LayerLink layerLink) {
     hide();
     final items = _filterItems(defaultToolbarItems);
     if (items.isEmpty) {
@@ -50,6 +50,7 @@ class _FlowyToolbarState extends State<FlowyToolbar>
         layerLink: layerLink,
         offset: offset,
         items: items,
+        aligment: alignment,
       ),
     );
     Overlay.of(context)?.insert(_toolbarOverlay!);