From 53d1df38f5a070018b21b5eacd9da5c7f3327768 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Thu, 25 May 2023 13:39:33 +0100 Subject: [PATCH 1/9] Fixed popup overflow by suggestions Wrapped the popup content in a SingleChildScrollView; Constrained the height of the popup; Changed the `MistakeBuilderCallback` typedef to match the signature of the `LanguageToolMistakePopup` unnamed constructor for simpler interoperability. --- lib/domain/typedefs.dart | 11 +-- lib/utils/mistake_popup.dart | 132 +++++++++++++++++++++++------------ 2 files changed, 92 insertions(+), 51 deletions(-) diff --git a/lib/domain/typedefs.dart b/lib/domain/typedefs.dart index 353381b..41ca87e 100644 --- a/lib/domain/typedefs.dart +++ b/lib/domain/typedefs.dart @@ -4,11 +4,12 @@ import 'package:languagetool_textfield/domain/mistake.dart'; import 'package:languagetool_textfield/utils/popup_overlay_renderer.dart'; /// Callback used to build popup body -typedef MistakeBuilderCallback = Widget Function( - PopupOverlayRenderer popupRenderer, - Mistake mistake, - ColoredTextEditingController controller, -); +typedef MistakeBuilderCallback = Widget Function({ + required PopupOverlayRenderer popupRenderer, + required Mistake mistake, + required ColoredTextEditingController controller, + required Offset mistakePosition, +}); /// Function called after mistake was clicked typedef ShowPopupCallback = void Function( diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index b669add..dcda017 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:languagetool_textfield/domain/typedefs.dart'; import 'package:languagetool_textfield/languagetool_textfield.dart'; @@ -21,16 +23,18 @@ class MistakePopup { Offset popupPosition, ColoredTextEditingController controller, ) { + final MistakeBuilderCallback builder = + mistakeBuilder ?? LanguageToolMistakePopup.new; + popupRenderer.render( context, position: popupPosition, - popupBuilder: (context) => - mistakeBuilder?.call(popupRenderer, mistake, controller) ?? - LanguageToolMistakePopup( - popupRenderer: popupRenderer, - mistake: mistake, - controller: controller, - ), + popupBuilder: (context) => builder.call( + popupRenderer: popupRenderer, + mistake: mistake, + controller: controller, + mistakePosition: popupPosition, + ), ); } } @@ -43,6 +47,8 @@ class LanguageToolMistakePopup extends StatelessWidget { required this.popupRenderer, required this.mistake, required this.controller, + required this.mistakePosition, + this.maxHeight = double.infinity, }); /// Renderer used to display this window. @@ -54,6 +60,14 @@ class LanguageToolMistakePopup extends StatelessWidget { /// Controller of the text where mistake was found final ColoredTextEditingController controller; + /// An on-screen position of the mistake + final Offset mistakePosition; + + /// A maximum height of the popup. + /// If infinity, the popup will use all the available height between the + /// [mistakePosition] and the furthest border of the layout constraints. + final double maxHeight; + @override Widget build(BuildContext context) { const _borderRadius = 10.0; @@ -61,53 +75,79 @@ class LanguageToolMistakePopup extends StatelessWidget { const _mistakeMessageFontSize = 15.0; const _replacementButtonsSpacing = 10.0; + const padding = 10.0; + const paddingCount = 4; + const paddingSum = padding * paddingCount; + + final availableSpace = _calculateAvailableSpace( + context, + paddings: paddingSum, + ); + return Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.all(padding), decoration: BoxDecoration( boxShadow: const [BoxShadow(color: Colors.grey, blurRadius: 20)], color: Colors.white, borderRadius: BorderRadius.circular(_borderRadius), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - // mistake type - Text( - mistake.type.name, - style: TextStyle( - color: Colors.grey.shade700, - fontSize: _mistakeNameFontSize, - fontWeight: FontWeight.w500, + constraints: BoxConstraints(maxHeight: availableSpace), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // mistake type + Text( + mistake.type.name, + style: TextStyle( + color: Colors.grey.shade700, + fontSize: _mistakeNameFontSize, + fontWeight: FontWeight.w500, + ), ), - ), - const SizedBox(height: 10), - - // mistake message - Text( - mistake.message, - style: const TextStyle(fontSize: _mistakeMessageFontSize), - ), - const SizedBox(height: 10), - - // replacements - Wrap( - spacing: _replacementButtonsSpacing, - direction: Axis.horizontal, - children: mistake.replacements - .map( - (replacement) => ElevatedButton( - onPressed: () { - controller.replaceMistake(mistake, replacement); - popupRenderer.dismiss(); - }, - child: Text(replacement), - ), - ) - .toList(growable: false), - ), - ], + const SizedBox(height: padding), + + // mistake message + Text( + mistake.message, + style: const TextStyle(fontSize: _mistakeMessageFontSize), + ), + const SizedBox(height: padding), + + // replacements + Wrap( + spacing: _replacementButtonsSpacing, + runSpacing: _replacementButtonsSpacing, + direction: Axis.horizontal, + children: mistake.replacements + .map( + (replacement) => ElevatedButton( + onPressed: () { + controller.replaceMistake(mistake, replacement); + popupRenderer.dismiss(); + }, + child: Text(replacement), + ), + ) + .toList(growable: false), + ), + ], + ), ), ); } + + double _calculateAvailableSpace( + BuildContext context, { + required double paddings, + }) { + final mediaQuery = MediaQuery.of(context); + + final availableSpaceBottom = + mediaQuery.size.height - mistakePosition.dy - paddings; + final availableSpaceTop = mistakePosition.dy - paddings; + + return min(max(availableSpaceBottom, availableSpaceTop), maxHeight); + } } From 47056f9d5ba847f5da014af6ec4fe5305258e542 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Thu, 25 May 2023 16:16:17 +0100 Subject: [PATCH 2/9] Improved performance with many suggestions Changed `Wrap` to `SliverList.builder` with a `CustomScrollView` --- lib/utils/mistake_popup.dart | 88 +++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index dcda017..439337a 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -73,7 +73,6 @@ class LanguageToolMistakePopup extends StatelessWidget { const _borderRadius = 10.0; const _mistakeNameFontSize = 13.0; const _mistakeMessageFontSize = 15.0; - const _replacementButtonsSpacing = 10.0; const padding = 10.0; const paddingCount = 4; @@ -92,48 +91,55 @@ class LanguageToolMistakePopup extends StatelessWidget { borderRadius: BorderRadius.circular(_borderRadius), ), constraints: BoxConstraints(maxHeight: availableSpace), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - // mistake type - Text( - mistake.type.name, - style: TextStyle( - color: Colors.grey.shade700, - fontSize: _mistakeNameFontSize, - fontWeight: FontWeight.w500, - ), + child: CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // mistake type + Text( + mistake.type.name, + style: TextStyle( + color: Colors.grey.shade700, + fontSize: _mistakeNameFontSize, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: padding), + + // mistake message + Text( + mistake.message, + style: const TextStyle(fontSize: _mistakeMessageFontSize), + ), + const SizedBox(height: padding), + ], ), - const SizedBox(height: padding), + ), + SliverList.builder( + itemCount: mistake.replacements.length, + itemBuilder: _suggestionsListBuilder, + ), + ], + ), + ); + } - // mistake message - Text( - mistake.message, - style: const TextStyle(fontSize: _mistakeMessageFontSize), - ), - const SizedBox(height: padding), - - // replacements - Wrap( - spacing: _replacementButtonsSpacing, - runSpacing: _replacementButtonsSpacing, - direction: Axis.horizontal, - children: mistake.replacements - .map( - (replacement) => ElevatedButton( - onPressed: () { - controller.replaceMistake(mistake, replacement); - popupRenderer.dismiss(); - }, - child: Text(replacement), - ), - ) - .toList(growable: false), - ), - ], - ), + Widget _suggestionsListBuilder(BuildContext _, int index) { + const replacementButtonsSpacing = 10.0; + + final replacement = mistake.replacements[index]; + + return Padding( + padding: const EdgeInsets.all(replacementButtonsSpacing / 2), + child: ElevatedButton( + onPressed: () { + controller.replaceMistake(mistake, replacement); + popupRenderer.dismiss(); + }, + child: Text(replacement), ), ); } From d6c2903373c62277867a99e70dfd469ca9c271d8 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Thu, 25 May 2023 17:20:36 +0100 Subject: [PATCH 3/9] Undid SliverList builder method extraction --- lib/utils/mistake_popup.dart | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index 439337a..b8c0730 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -73,6 +73,7 @@ class LanguageToolMistakePopup extends StatelessWidget { const _borderRadius = 10.0; const _mistakeNameFontSize = 13.0; const _mistakeMessageFontSize = 15.0; + const _replacementButtonsSpacing = 10.0; const padding = 10.0; const paddingCount = 4; @@ -120,30 +121,26 @@ class LanguageToolMistakePopup extends StatelessWidget { ), SliverList.builder( itemCount: mistake.replacements.length, - itemBuilder: _suggestionsListBuilder, + itemBuilder: (context, index) { + final replacement = mistake.replacements[index]; + + return Padding( + padding: const EdgeInsets.all(_replacementButtonsSpacing / 2), + child: ElevatedButton( + onPressed: () { + controller.replaceMistake(mistake, replacement); + popupRenderer.dismiss(); + }, + child: Text(replacement), + ), + ); + }, ), ], ), ); } - Widget _suggestionsListBuilder(BuildContext _, int index) { - const replacementButtonsSpacing = 10.0; - - final replacement = mistake.replacements[index]; - - return Padding( - padding: const EdgeInsets.all(replacementButtonsSpacing / 2), - child: ElevatedButton( - onPressed: () { - controller.replaceMistake(mistake, replacement); - popupRenderer.dismiss(); - }, - child: Text(replacement), - ), - ); - } - double _calculateAvailableSpace( BuildContext context, { required double paddings, From 6c590b537783fa53bd8a4a76ee331f4403e38d98 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Fri, 26 May 2023 11:14:46 +0100 Subject: [PATCH 4/9] Moved `LanguageToolMistakePopup` fields up for them to be before the constructor. --- lib/utils/mistake_popup.dart | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index b8c0730..1a8e3d1 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -41,16 +41,6 @@ class MistakePopup { /// Default mistake window that looks similar to LanguageTool popup class LanguageToolMistakePopup extends StatelessWidget { - /// [LanguageToolMistakePopup] constructor - const LanguageToolMistakePopup({ - super.key, - required this.popupRenderer, - required this.mistake, - required this.controller, - required this.mistakePosition, - this.maxHeight = double.infinity, - }); - /// Renderer used to display this window. final PopupOverlayRenderer popupRenderer; @@ -68,6 +58,16 @@ class LanguageToolMistakePopup extends StatelessWidget { /// [mistakePosition] and the furthest border of the layout constraints. final double maxHeight; + /// [LanguageToolMistakePopup] constructor + const LanguageToolMistakePopup({ + super.key, + required this.popupRenderer, + required this.mistake, + required this.controller, + required this.mistakePosition, + this.maxHeight = double.infinity, + }); + @override Widget build(BuildContext context) { const _borderRadius = 10.0; From 05f37a074bf46dd67de65224410ad96e19291312 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Fri, 26 May 2023 12:38:58 +0100 Subject: [PATCH 5/9] Fixed `SliverList` taking all the vertical space --- lib/utils/mistake_popup.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index 1a8e3d1..771d154 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -93,6 +93,7 @@ class LanguageToolMistakePopup extends StatelessWidget { ), constraints: BoxConstraints(maxHeight: availableSpace), child: CustomScrollView( + shrinkWrap: true, slivers: [ SliverToBoxAdapter( child: Column( From d873e26c27aeb968741f76099f3a92a4f68083e7 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Fri, 26 May 2023 13:11:46 +0100 Subject: [PATCH 6/9] Fixed paddings --- lib/utils/mistake_popup.dart | 4 +--- lib/utils/popup_overlay_renderer.dart | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index 771d154..a691d2f 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -76,12 +76,10 @@ class LanguageToolMistakePopup extends StatelessWidget { const _replacementButtonsSpacing = 10.0; const padding = 10.0; - const paddingCount = 4; - const paddingSum = padding * paddingCount; final availableSpace = _calculateAvailableSpace( context, - paddings: paddingSum, + paddings: defaultPopupVerticalPadding + defaultPopupHorizontalPadding, ); return Container( diff --git a/lib/utils/popup_overlay_renderer.dart b/lib/utils/popup_overlay_renderer.dart index 9cf980f..8a4b86f 100644 --- a/lib/utils/popup_overlay_renderer.dart +++ b/lib/utils/popup_overlay_renderer.dart @@ -6,10 +6,10 @@ import 'package:flutter/material.dart'; const defaultPopupWidth = 250.0; /// defaultHorizontalPadding -const defaultHorizontalPadding = 10.0; +const defaultPopupHorizontalPadding = 10.0; /// defaultVerticalMargin -const defaultVerticalPadding = 30.0; +const defaultPopupVerticalPadding = 30.0; /// Renderer used to show popup window overlay class PopupOverlayRenderer { @@ -79,8 +79,8 @@ class PopupOverlayLayoutDelegate extends SingleChildLayoutDelegate { const PopupOverlayLayoutDelegate( this.position, { this.width = defaultPopupWidth, - this.horizontalPadding = defaultHorizontalPadding, - this.verticalPadding = defaultVerticalPadding, + this.horizontalPadding = defaultPopupHorizontalPadding, + this.verticalPadding = defaultPopupVerticalPadding, }); @override From ebb3b364a24c2b669d0af1630f673e4c5ab88db4 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Mon, 29 May 2023 11:59:53 +0100 Subject: [PATCH 7/9] Moved popup constraints and margins into the popup --- lib/utils/mistake_popup.dart | 144 +++++++++++++++----------- lib/utils/popup_overlay_renderer.dart | 43 ++------ 2 files changed, 89 insertions(+), 98 deletions(-) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index a691d2f..bb34bca 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -41,6 +41,10 @@ class MistakePopup { /// Default mistake window that looks similar to LanguageTool popup class LanguageToolMistakePopup extends StatelessWidget { + static const double _defaultVerticalMargin = 25.0; + static const double _defaultHorizontalMargin = 10.0; + static const double _defaultMaxWidth = 250.0; + /// Renderer used to display this window. final PopupOverlayRenderer popupRenderer; @@ -53,11 +57,21 @@ class LanguageToolMistakePopup extends StatelessWidget { /// An on-screen position of the mistake final Offset mistakePosition; + /// A maximum width of the popup. + /// If infinity, the popup will use all the available horizontal space. + final double maxWidth; + /// A maximum height of the popup. /// If infinity, the popup will use all the available height between the /// [mistakePosition] and the furthest border of the layout constraints. final double maxHeight; + /// Horizontal popup margin. + final double horizontalMargin; + + /// Vertical popup margin. + final double verticalMargin; + /// [LanguageToolMistakePopup] constructor const LanguageToolMistakePopup({ super.key, @@ -65,7 +79,10 @@ class LanguageToolMistakePopup extends StatelessWidget { required this.mistake, required this.controller, required this.mistakePosition, + this.maxWidth = _defaultMaxWidth, this.maxHeight = double.infinity, + this.horizontalMargin = _defaultHorizontalMargin, + this.verticalMargin = _defaultVerticalMargin, }); @override @@ -77,78 +94,81 @@ class LanguageToolMistakePopup extends StatelessWidget { const padding = 10.0; - final availableSpace = _calculateAvailableSpace( - context, - paddings: defaultPopupVerticalPadding + defaultPopupHorizontalPadding, - ); + final availableSpace = _calculateAvailableSpace(context); - return Container( - padding: const EdgeInsets.all(padding), - decoration: BoxDecoration( - boxShadow: const [BoxShadow(color: Colors.grey, blurRadius: 20)], - color: Colors.white, - borderRadius: BorderRadius.circular(_borderRadius), + return ConstrainedBox( + constraints: BoxConstraints( + maxWidth: maxWidth, + maxHeight: availableSpace, ), - constraints: BoxConstraints(maxHeight: availableSpace), - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - SliverToBoxAdapter( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - // mistake type - Text( - mistake.type.name, - style: TextStyle( - color: Colors.grey.shade700, - fontSize: _mistakeNameFontSize, - fontWeight: FontWeight.w500, + child: Container( + margin: EdgeInsets.symmetric( + horizontal: horizontalMargin, + vertical: verticalMargin, + ), + padding: const EdgeInsets.all(padding), + decoration: BoxDecoration( + boxShadow: const [BoxShadow(color: Colors.grey, blurRadius: 20)], + color: Colors.white, + borderRadius: BorderRadius.circular(_borderRadius), + ), + child: CustomScrollView( + shrinkWrap: true, + slivers: [ + SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // mistake type + Text( + mistake.type.name, + style: TextStyle( + color: Colors.grey.shade700, + fontSize: _mistakeNameFontSize, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: padding), + + // mistake message + Text( + mistake.message, + style: const TextStyle(fontSize: _mistakeMessageFontSize), + ), + const SizedBox(height: padding), + ], + ), + ), + SliverList.builder( + itemCount: mistake.replacements.length, + itemBuilder: (context, index) { + final replacement = mistake.replacements[index]; + + return Padding( + padding: const EdgeInsets.all(_replacementButtonsSpacing / 2), + child: ElevatedButton( + onPressed: () { + controller.replaceMistake(mistake, replacement); + popupRenderer.dismiss(); + }, + child: Text(replacement), ), - ), - const SizedBox(height: padding), - - // mistake message - Text( - mistake.message, - style: const TextStyle(fontSize: _mistakeMessageFontSize), - ), - const SizedBox(height: padding), - ], + ); + }, ), - ), - SliverList.builder( - itemCount: mistake.replacements.length, - itemBuilder: (context, index) { - final replacement = mistake.replacements[index]; - - return Padding( - padding: const EdgeInsets.all(_replacementButtonsSpacing / 2), - child: ElevatedButton( - onPressed: () { - controller.replaceMistake(mistake, replacement); - popupRenderer.dismiss(); - }, - child: Text(replacement), - ), - ); - }, - ), - ], + ], + ), ), ); } - double _calculateAvailableSpace( - BuildContext context, { - required double paddings, - }) { + double _calculateAvailableSpace(BuildContext context) { + // final margins = horizontalMargin * 2 + verticalMargin * 2; final mediaQuery = MediaQuery.of(context); - final availableSpaceBottom = - mediaQuery.size.height - mistakePosition.dy - paddings; - final availableSpaceTop = mistakePosition.dy - paddings; + final availableSpaceBottom = mediaQuery.size.height - mistakePosition.dy; + final availableSpaceTop = mistakePosition.dy; return min(max(availableSpaceBottom, availableSpaceTop), maxHeight); } diff --git a/lib/utils/popup_overlay_renderer.dart b/lib/utils/popup_overlay_renderer.dart index 8a4b86f..291b040 100644 --- a/lib/utils/popup_overlay_renderer.dart +++ b/lib/utils/popup_overlay_renderer.dart @@ -2,24 +2,12 @@ import 'dart:math'; import 'package:flutter/material.dart'; -/// defaultPopupWidth -const defaultPopupWidth = 250.0; - -/// defaultHorizontalPadding -const defaultPopupHorizontalPadding = 10.0; - -/// defaultVerticalMargin -const defaultPopupVerticalPadding = 30.0; - /// Renderer used to show popup window overlay class PopupOverlayRenderer { OverlayEntry? _overlayEntry; - /// Max width of popup window - final double width; - /// [PopupOverlayRenderer] constructor - PopupOverlayRenderer({this.width = defaultPopupWidth}); + PopupOverlayRenderer(); /// Render overlay entry on the screen with dismiss logic OverlayEntry render( @@ -38,10 +26,7 @@ class PopupOverlayRenderer { children: [ CustomSingleChildLayout( delegate: PopupOverlayLayoutDelegate(position), - child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: width), - child: popupBuilder(context), - ), + child: popupBuilder(context), ), ], ), @@ -63,25 +48,11 @@ class PopupOverlayRenderer { /// Class that calculates where to place popup window on the screen class PopupOverlayLayoutDelegate extends SingleChildLayoutDelegate { - /// max width of popup window - final double width; - /// desired position of popup window final Offset position; - /// padding of screen for popup window - final double horizontalPadding; - - /// vertical distance to offset from [position] - final double verticalPadding; - /// [PopupOverlayLayoutDelegate] constructor - const PopupOverlayLayoutDelegate( - this.position, { - this.width = defaultPopupWidth, - this.horizontalPadding = defaultPopupHorizontalPadding, - this.verticalPadding = defaultPopupVerticalPadding, - }); + const PopupOverlayLayoutDelegate(this.position); @override Offset getPositionForChild(Size size, Size childSize) { @@ -96,21 +67,21 @@ class PopupOverlayLayoutDelegate extends SingleChildLayoutDelegate { ); double dx = _popupRect.left; // limiting X offset - dx = max(horizontalPadding, dx); + dx = max(0, dx); final rightBorderPosition = dx + childSize.width; final rightScreenBorderOverflow = rightBorderPosition - size.width; if (rightScreenBorderOverflow >= 0) { - dx -= rightScreenBorderOverflow + horizontalPadding; + dx -= rightScreenBorderOverflow; } // under the desired position - double dy = position.dy + verticalPadding; + double dy = max(0, position.dy); final bottomBorderPosition = dy + childSize.height; final bottomScreenBorderOverflow = bottomBorderPosition - size.height; // if not enough space underneath, rendering above the desired position if (bottomScreenBorderOverflow >= 0) { final newBottomBorderPosition = position.dy - childSize.height; - dy = newBottomBorderPosition - verticalPadding; + dy = newBottomBorderPosition; } return Offset(dx, dy); From b60603a83bcdec17fae077bebe24e9baa349fc4a Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Mon, 29 May 2023 12:01:38 +0100 Subject: [PATCH 8/9] Fixed incorrect placement of the popup In cases when its size was calculated to fill the available space pixel-perfect. --- lib/utils/popup_overlay_renderer.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/popup_overlay_renderer.dart b/lib/utils/popup_overlay_renderer.dart index 291b040..7ec71f5 100644 --- a/lib/utils/popup_overlay_renderer.dart +++ b/lib/utils/popup_overlay_renderer.dart @@ -70,7 +70,7 @@ class PopupOverlayLayoutDelegate extends SingleChildLayoutDelegate { dx = max(0, dx); final rightBorderPosition = dx + childSize.width; final rightScreenBorderOverflow = rightBorderPosition - size.width; - if (rightScreenBorderOverflow >= 0) { + if (rightScreenBorderOverflow > 0) { dx -= rightScreenBorderOverflow; } @@ -79,7 +79,7 @@ class PopupOverlayLayoutDelegate extends SingleChildLayoutDelegate { final bottomBorderPosition = dy + childSize.height; final bottomScreenBorderOverflow = bottomBorderPosition - size.height; // if not enough space underneath, rendering above the desired position - if (bottomScreenBorderOverflow >= 0) { + if (bottomScreenBorderOverflow > 0) { final newBottomBorderPosition = position.dy - childSize.height; dy = newBottomBorderPosition; } From 35138c861d18490f79d9bcee3fa15b41024d1dc8 Mon Sep 17 00:00:00 2001 From: Dmytro Popov Date: Mon, 29 May 2023 15:23:13 +0100 Subject: [PATCH 9/9] Removed the commented out code --- lib/utils/mistake_popup.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/utils/mistake_popup.dart b/lib/utils/mistake_popup.dart index bb34bca..cb0f78c 100644 --- a/lib/utils/mistake_popup.dart +++ b/lib/utils/mistake_popup.dart @@ -164,7 +164,6 @@ class LanguageToolMistakePopup extends StatelessWidget { } double _calculateAvailableSpace(BuildContext context) { - // final margins = horizontalMargin * 2 + verticalMargin * 2; final mediaQuery = MediaQuery.of(context); final availableSpaceBottom = mediaQuery.size.height - mistakePosition.dy;