TF-4195 Fix comments of coderabbit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class HoverSubmenuController {
|
||||
HoverSubmenuController({
|
||||
this.exitDelay = const Duration(milliseconds: 120),
|
||||
});
|
||||
|
||||
final Duration exitDelay;
|
||||
|
||||
final ValueNotifier<bool> isHovering = ValueNotifier(false);
|
||||
|
||||
int _hoverRefCount = 0;
|
||||
Timer? _exitTimer;
|
||||
|
||||
void enter() {
|
||||
_exitTimer?.cancel();
|
||||
_hoverRefCount++;
|
||||
if (!isHovering.value) {
|
||||
isHovering.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
void exit() {
|
||||
_hoverRefCount = (_hoverRefCount - 1).clamp(0, 999);
|
||||
|
||||
if (_hoverRefCount == 0) {
|
||||
_exitTimer?.cancel();
|
||||
_exitTimer = Timer(exitDelay, () {
|
||||
if (_hoverRefCount == 0) {
|
||||
isHovering.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_exitTimer?.cancel();
|
||||
isHovering.dispose();
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ class PopupMenuActionGroupWidget with PopupContextMenuActionMixin {
|
||||
child: PopupMenuItemActionWidget(
|
||||
menuAction: menuAction,
|
||||
menuActionClick: (menuAction) {
|
||||
submenuController?.hide();
|
||||
Navigator.pop(context);
|
||||
onActionSelected(menuAction);
|
||||
},
|
||||
@@ -60,7 +61,11 @@ class PopupMenuActionGroupWidget with PopupContextMenuActionMixin {
|
||||
],
|
||||
];
|
||||
|
||||
return openPopupMenuAction(context, position, popupMenuItems);
|
||||
try {
|
||||
await openPopupMenuAction(context, position, popupMenuItems);
|
||||
} finally {
|
||||
submenuController?.hide();
|
||||
}
|
||||
}
|
||||
|
||||
void _showPopupSubmenu({
|
||||
@@ -69,8 +74,9 @@ class PopupMenuActionGroupWidget with PopupContextMenuActionMixin {
|
||||
required PopupSubmenuController submenuController,
|
||||
required Widget submenu,
|
||||
}) {
|
||||
final renderBox = itemKey.currentContext?.findRenderObject() as RenderBox?;
|
||||
if (renderBox == null) return;
|
||||
final renderObject = itemKey.currentContext?.findRenderObject();
|
||||
if (renderObject is! RenderBox) return;
|
||||
final renderBox = renderObject;
|
||||
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
final rect = offset & renderBox.size;
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/base/model/popup_menu_item_action.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_menu/hover_submenu_controller.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/popup_menu_item_email_action.dart';
|
||||
|
||||
class PopupMenuItemActionWidget extends StatefulWidget {
|
||||
@@ -28,14 +29,15 @@ class PopupMenuItemActionWidget extends StatefulWidget {
|
||||
|
||||
class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||
GlobalKey? _itemKey;
|
||||
ValueNotifier<bool>? _hoverItemNotifier;
|
||||
HoverSubmenuController? _hoverController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.menuAction is PopupMenuItemEmailAction) {
|
||||
if (widget.menuAction is PopupMenuItemEmailAction &&
|
||||
widget.menuAction.action == EmailActionType.labelAs) {
|
||||
_itemKey = GlobalKey();
|
||||
_hoverItemNotifier = ValueNotifier(false);
|
||||
_hoverController = HoverSubmenuController();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +135,8 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||
return PointerInterceptor(
|
||||
child: MouseRegion(
|
||||
onEnter: (_) {
|
||||
if (_hoverItemNotifier != null) {
|
||||
_hoverItemNotifier?.value = true;
|
||||
}
|
||||
_hoverController?.enter();
|
||||
|
||||
if (_itemKey != null) {
|
||||
widget.onHoverShowSubmenu?.call(_itemKey!);
|
||||
} else {
|
||||
@@ -143,9 +144,7 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||
}
|
||||
},
|
||||
onExit: (_) {
|
||||
if (_hoverItemNotifier != null) {
|
||||
_hoverItemNotifier?.value = false;
|
||||
}
|
||||
_hoverController?.exit();
|
||||
},
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
@@ -172,26 +171,23 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||
),
|
||||
if (isSelected && selectedIconWidget != null)
|
||||
selectedIconWidget,
|
||||
if (_hoverItemNotifier != null)
|
||||
if (_hoverController != null)
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _hoverItemNotifier!,
|
||||
builder: (_, value, __) {
|
||||
if (value) {
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsetsDirectional.only(start: 16),
|
||||
child: SvgPicture.asset(
|
||||
specificMenuAction.hoverIcon,
|
||||
width: specificMenuAction.hoverIconSize,
|
||||
height: specificMenuAction.hoverIconSize,
|
||||
colorFilter: specificMenuAction.hoverIconColor
|
||||
.asFilter(),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
valueListenable: _hoverController!.isHovering,
|
||||
builder: (_, isHovering, __) {
|
||||
if (!isHovering) return const SizedBox.shrink();
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsetsDirectional.only(start: 16),
|
||||
child: SvgPicture.asset(
|
||||
specificMenuAction.hoverIcon,
|
||||
width: specificMenuAction.hoverIconSize,
|
||||
height: specificMenuAction.hoverIconSize,
|
||||
colorFilter: specificMenuAction.hoverIconColor
|
||||
.asFilter(),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
@@ -210,9 +206,7 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||
onTap: () => widget.menuAction.onClick(widget.menuActionClick),
|
||||
hoverColor: AppColor.popupMenuItemHovered,
|
||||
onHover: (_) {
|
||||
if (_hoverItemNotifier != null) {
|
||||
_hoverItemNotifier?.value = false;
|
||||
}
|
||||
_hoverController?.exit();
|
||||
widget.onHoverOtherItem?.call();
|
||||
},
|
||||
child: Container(
|
||||
@@ -245,9 +239,9 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_hoverItemNotifier != null) {
|
||||
_hoverItemNotifier?.dispose();
|
||||
_hoverItemNotifier = null;
|
||||
if (_hoverController != null) {
|
||||
_hoverController?.dispose();
|
||||
_hoverController = null;
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum SubmenuDirection { left, right, auto }
|
||||
@@ -18,7 +20,12 @@ class PopupSubmenuController {
|
||||
}) {
|
||||
hide();
|
||||
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final overlayState = Overlay.maybeOf(context, rootOverlay: true);
|
||||
if (overlayState == null) return;
|
||||
|
||||
final mediaSize = MediaQuery.sizeOf(context);
|
||||
final screenWidth = mediaSize.width;
|
||||
final screenHeight = mediaSize.height;
|
||||
|
||||
final rightPosition = anchor.right + offset;
|
||||
final leftPosition = anchor.left - submenuWidth - offset;
|
||||
@@ -42,10 +49,16 @@ class PopupSubmenuController {
|
||||
}
|
||||
}
|
||||
|
||||
final clampedLeft = finalLeft
|
||||
.clamp(0.0, math.max(0.0, screenWidth - submenuWidth))
|
||||
.toDouble();
|
||||
final availableHeight = math.max(0.0, screenHeight - anchor.top);
|
||||
final finalHeight = math.min(submenuMaxHeight, availableHeight);
|
||||
|
||||
_submenuEntry = OverlayEntry(
|
||||
builder: (_) {
|
||||
return PositionedDirectional(
|
||||
start: finalLeft,
|
||||
start: clampedLeft,
|
||||
top: anchor.top,
|
||||
child: MouseRegion(
|
||||
onExit: (_) => hide(),
|
||||
@@ -57,7 +70,7 @@ class PopupSubmenuController {
|
||||
),
|
||||
child: SizedBox(
|
||||
width: submenuWidth,
|
||||
height: submenuMaxHeight,
|
||||
height: finalHeight,
|
||||
child: submenu,
|
||||
),
|
||||
),
|
||||
@@ -66,7 +79,7 @@ class PopupSubmenuController {
|
||||
},
|
||||
);
|
||||
|
||||
Overlay.maybeOf(context)?.insert(_submenuEntry!);
|
||||
overlayState.insert(_submenuEntry!);
|
||||
}
|
||||
|
||||
void hide() {
|
||||
|
||||
Reference in New Issue
Block a user