Skip to content

Commit c8bf127

Browse files
dab246hoangdat
authored andcommitted
feat(ai-scribe): Fix alignment of prompt when AI button at very right of composer or response have long result but at the bottom of composer
1 parent 10ff32e commit c8bf127

File tree

3 files changed

+76
-27
lines changed

3 files changed

+76
-27
lines changed
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import 'package:flutter/cupertino.dart';
2-
31
class AnchoredSuggestionLayoutResult {
4-
final Offset offset;
52
final double availableHeight;
6-
final double? top;
7-
final double? bottom;
3+
final double left;
4+
final double bottom;
85

96
const AnchoredSuggestionLayoutResult({
10-
required this.offset,
7+
required this.left,
8+
required this.bottom,
119
required this.availableHeight,
12-
this.top,
13-
this.bottom,
1410
});
1511
}

scribe/lib/scribe/ai/presentation/utils/modal/anchored_modal_layout_calculator.dart

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import 'dart:math';
2-
31
import 'package:flutter/animation.dart';
42
import 'package:scribe/scribe.dart';
53

@@ -145,10 +143,11 @@ class AnchoredModalLayoutCalculator {
145143
required Size screenSize,
146144
required Offset anchorPosition,
147145
required Size anchorSize,
148-
required double modalMaxHeight,
146+
required Size menuSize,
149147
ModalPlacement? preferredPlacement,
150148
double gap = 8,
151-
double padding = AIScribeSizes.screenEdgePadding,
149+
double verticalOffset = 6,
150+
double padding = 8,
152151
}) {
153152
final isTop = preferredPlacement == ModalPlacement.top;
154153

@@ -157,25 +156,79 @@ class AnchoredModalLayoutCalculator {
157156
final positionBottom = screenSize.height - anchorPosition.dy + gap;
158157

159158
return AnchoredSuggestionLayoutResult(
160-
offset: Offset(
161-
anchorPosition.dx,
162-
positionBottom,
163-
),
164159
availableHeight: availableHeight,
160+
left: anchorPosition.dx,
165161
bottom: positionBottom,
166162
);
167163
}
168164

169-
final spaceBelow = screenSize.height - anchorPosition.dy - padding - gap;
170-
final positionTop = anchorPosition.dx + anchorSize.width + gap;
165+
late ModalPlacement placement;
166+
167+
if (preferredPlacement != null &&
168+
_canPlace(
169+
placement: preferredPlacement,
170+
screen: screenSize,
171+
anchor: anchorPosition,
172+
anchorSize: anchorSize,
173+
menu: menuSize,
174+
gap: gap,
175+
)) {
176+
placement = preferredPlacement;
177+
} else {
178+
final fallbackOrder = [
179+
ModalPlacement.right,
180+
ModalPlacement.bottom,
181+
ModalPlacement.top,
182+
ModalPlacement.left,
183+
];
184+
185+
placement = fallbackOrder.firstWhere(
186+
(p) => _canPlace(
187+
placement: p,
188+
screen: screenSize,
189+
anchor: anchorPosition,
190+
anchorSize: anchorSize,
191+
menu: menuSize,
192+
gap: gap,
193+
),
194+
orElse: () => ModalPlacement.right,
195+
);
196+
}
197+
198+
late double left;
199+
late double bottom;
200+
201+
switch (placement) {
202+
case ModalPlacement.right:
203+
left = anchorPosition.dx + anchorSize.width + gap;
204+
bottom = anchorPosition.dy + verticalOffset;
205+
break;
206+
207+
case ModalPlacement.bottom:
208+
left = anchorPosition.dx;
209+
bottom = anchorPosition.dy + anchorSize.height + gap + verticalOffset;
210+
break;
211+
212+
case ModalPlacement.top:
213+
left = anchorPosition.dx;
214+
bottom = anchorPosition.dy - menuSize.height - gap + verticalOffset;
215+
break;
216+
case ModalPlacement.left:
217+
left = anchorPosition.dx - menuSize.width - gap;
218+
bottom = anchorPosition.dy + verticalOffset;
219+
break;
220+
}
221+
222+
left = left.clamp(padding, screenSize.width - menuSize.width - padding);
223+
bottom = bottom.clamp(
224+
padding,
225+
screenSize.height - menuSize.height - padding,
226+
);
171227

172228
return AnchoredSuggestionLayoutResult(
173-
offset: Offset(
174-
positionTop,
175-
anchorPosition.dy,
176-
),
177-
availableHeight: min(spaceBelow, modalMaxHeight),
178-
top: anchorPosition.dy,
229+
availableHeight: menuSize.height,
230+
left: left,
231+
bottom: bottom,
179232
);
180233
}
181234
}

scribe/lib/scribe/ai/presentation/widgets/modal/ai_scribe_suggestion_widget.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ class _AiScribeSuggestionWidgetState extends State<AiScribeSuggestionWidget> {
104104
screenSize: screenSize,
105105
anchorPosition: widget.buttonPosition!,
106106
anchorSize: widget.buttonSize!,
107-
modalMaxHeight: modalMaxHeight,
107+
menuSize: Size(modalWidth, modalMaxHeight),
108108
preferredPlacement: widget.preferredPlacement,
109+
padding: AIScribeSizes.screenEdgePadding,
109110
);
110111

111112
return PointerInterceptor(
@@ -118,8 +119,7 @@ class _AiScribeSuggestionWidgetState extends State<AiScribeSuggestionWidget> {
118119
),
119120
),
120121
PositionedDirectional(
121-
start: layout.offset.dx,
122-
top: layout.top,
122+
start: layout.left,
123123
bottom: layout.bottom,
124124
child: _buildModalContainer(
125125
width: modalWidth,

0 commit comments

Comments
 (0)