showAsrPopupMenu function
Future<void>
showAsrPopupMenu({
- required BuildContext context,
- required GlobalKey<
State< targetKey,StatefulWidget> > - required List<
AsrPopupMenuAction> actions, - bool isSelf = false,
Show ASR popup menu above the target widget Returns when the menu is dismissed
Implementation
Future<void> showAsrPopupMenu({
required BuildContext context,
required GlobalKey targetKey,
required List<AsrPopupMenuAction> actions,
bool isSelf = false,
}) async {
final RenderBox? renderBox = targetKey.currentContext?.findRenderObject() as RenderBox?;
if (renderBox == null) return;
final Offset targetPosition = renderBox.localToGlobal(Offset.zero);
final Size targetSize = renderBox.size;
final Size screenSize = MediaQuery.of(context).size;
// Calculate menu position (above the target)
// Menu width estimation: ~3 items * 60px each = ~180px
// Menu height: icon(20) + spacing(4) + text(~12) + padding(8*2) = ~52px
const double menuWidth = 180;
const double menuHeight = 52;
const double verticalOffset = 4;
double left;
if (isSelf) {
// For self messages, align to the right
left = targetPosition.dx + targetSize.width - menuWidth;
} else {
// For other messages, align to the left
left = targetPosition.dx;
}
// Ensure menu stays within screen bounds
if (left < 8) left = 8;
if (left + menuWidth > screenSize.width - 8) {
left = screenSize.width - menuWidth - 8;
}
// Position above the target
double top = targetPosition.dy - menuHeight - verticalOffset;
// If not enough space above, show below
if (top < MediaQuery.of(context).padding.top + 8) {
top = targetPosition.dy + targetSize.height + verticalOffset;
}
final OverlayState overlayState = Overlay.of(context);
late OverlayEntry overlayEntry;
overlayEntry = OverlayEntry(
builder: (context) {
return Stack(
children: [
// Transparent barrier to dismiss menu
Positioned.fill(
child: GestureDetector(
onTap: () => overlayEntry.remove(),
behavior: HitTestBehavior.opaque,
child: Container(color: Colors.transparent),
),
),
// Menu
Positioned(
left: left,
top: top,
child: AsrPopupMenu(
actions: actions.map((action) {
return AsrPopupMenuAction(
label: action.label,
iconAsset: action.iconAsset,
onTap: () {
overlayEntry.remove();
action.onTap();
},
);
}).toList(),
),
),
],
);
},
);
overlayState.insert(overlayEntry);
}