TF-2666 Apply new design for edit recipient card on web
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/smart_interaction_widget.dart';
|
||||
|
||||
class CardWithSmartInteractionOverlayView extends StatefulWidget {
|
||||
final Widget child;
|
||||
final double overlayWidth;
|
||||
final Widget Function(VoidCallback onClose) menuBuilder;
|
||||
|
||||
const CardWithSmartInteractionOverlayView({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.menuBuilder,
|
||||
this.overlayWidth = 361,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CardWithSmartInteractionOverlayView> createState() => _CardWithSmartInteractionOverlayViewState();
|
||||
}
|
||||
|
||||
class _CardWithSmartInteractionOverlayViewState
|
||||
extends State<CardWithSmartInteractionOverlayView>
|
||||
with SingleTickerProviderStateMixin {
|
||||
final LayerLink _layerLink = LayerLink();
|
||||
OverlayEntry? _overlayEntry;
|
||||
late AnimationController _controller;
|
||||
bool _isDisposed = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
reverseDuration: const Duration(milliseconds: 100),
|
||||
vsync: this,
|
||||
);
|
||||
}
|
||||
|
||||
void _showPopup() {
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (context) => Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: PointerInterceptor(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: _removePopup,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
width: widget.overlayWidth,
|
||||
child: CompositedTransformFollower(
|
||||
link: _layerLink,
|
||||
offset: const Offset(0, 40),
|
||||
showWhenUnlinked: false,
|
||||
child: FadeTransition(
|
||||
opacity: CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeOut,
|
||||
),
|
||||
child: ScaleTransition(
|
||||
scale: CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeOutBack,
|
||||
),
|
||||
alignment: Alignment.topLeft,
|
||||
child: widget.menuBuilder(_removePopup),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Overlay.maybeOf(context)?.insert(_overlayEntry!);
|
||||
_controller.forward();
|
||||
}
|
||||
|
||||
Future<void> _removePopup() async {
|
||||
if (_overlayEntry == null) return;
|
||||
|
||||
if (!_isDisposed && _controller.isAnimating == false) {
|
||||
await _controller.reverse();
|
||||
}
|
||||
|
||||
_overlayEntry?.remove();
|
||||
_overlayEntry = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_isDisposed = true;
|
||||
_controller.dispose();
|
||||
_overlayEntry?.remove();
|
||||
_overlayEntry = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CompositedTransformTarget(
|
||||
link: _layerLink,
|
||||
child: SmartInteractionWidget(
|
||||
onRightMouseClickAction: ({RelativeRect? position}) => _togglePopup(),
|
||||
onDoubleClickAction: ({RelativeRect? position}) => _togglePopup(),
|
||||
onLongPressAction: _togglePopup,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _togglePopup() {
|
||||
if (_overlayEntry == null) {
|
||||
_showPopup();
|
||||
} else {
|
||||
_removePopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,13 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart' hide OverlayEntry;
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
typedef OnRightMouseClickAction = void Function(RelativeRect position);
|
||||
typedef OnDoubleClickAction = void Function(RelativeRect position);
|
||||
typedef OnRightMouseClickAction = void Function({RelativeRect? position});
|
||||
typedef OnDoubleClickAction = void Function({RelativeRect? position});
|
||||
typedef OnLongPressAction = void Function();
|
||||
|
||||
class SmartInteractionWidget extends StatefulWidget {
|
||||
final Widget child;
|
||||
final bool usePosition;
|
||||
final OnRightMouseClickAction onRightMouseClickAction;
|
||||
final OnDoubleClickAction onDoubleClickAction;
|
||||
final OnLongPressAction onLongPressAction;
|
||||
@@ -21,6 +22,7 @@ class SmartInteractionWidget extends StatefulWidget {
|
||||
required this.onRightMouseClickAction,
|
||||
required this.onDoubleClickAction,
|
||||
required this.onLongPressAction,
|
||||
this.usePosition = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -73,8 +75,12 @@ class _SmartInteractionWidgetState extends State<SmartInteractionWidget> {
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
final relativeRect = _getRelativeRectFromOffset(context, localPosition);
|
||||
widget.onRightMouseClickAction(relativeRect);
|
||||
if (widget.usePosition) {
|
||||
final relativeRect = _getRelativeRectFromOffset(context, localPosition);
|
||||
widget.onRightMouseClickAction(position: relativeRect);
|
||||
} else {
|
||||
widget.onRightMouseClickAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,12 +119,14 @@ class _SmartInteractionWidgetState extends State<SmartInteractionWidget> {
|
||||
}
|
||||
|
||||
void _handleDoubleTap() {
|
||||
if (_lastPointerEventOffset != null) {
|
||||
if (widget.usePosition && _lastPointerEventOffset != null) {
|
||||
final relativeRect = _getRelativeRectFromOffset(
|
||||
context,
|
||||
_lastPointerEventOffset!,
|
||||
);
|
||||
widget.onDoubleClickAction(relativeRect);
|
||||
widget.onDoubleClickAction(position: relativeRect);
|
||||
} else {
|
||||
widget.onDoubleClickAction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,19 +135,28 @@ class _SmartInteractionWidgetState extends State<SmartInteractionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (PlatformInfo.isWeb) {
|
||||
return Listener(
|
||||
key: _childKey,
|
||||
onPointerDown: (event) {
|
||||
if (event.kind == PointerDeviceKind.mouse ||
|
||||
event.kind == PointerDeviceKind.touch) {
|
||||
_lastPointerEventOffset = event.position;
|
||||
}
|
||||
},
|
||||
child: GestureDetector(
|
||||
if (widget.usePosition) {
|
||||
return Listener(
|
||||
key: _childKey,
|
||||
onPointerDown: (event) {
|
||||
if (event.kind == PointerDeviceKind.mouse ||
|
||||
event.kind == PointerDeviceKind.touch) {
|
||||
_lastPointerEventOffset = event.position;
|
||||
}
|
||||
},
|
||||
child: GestureDetector(
|
||||
onDoubleTap: _handleDoubleTap,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return GestureDetector(
|
||||
key: _childKey,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onDoubleTap: _handleDoubleTap,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return GestureDetector(
|
||||
onLongPress: _handleLongPress,
|
||||
|
||||
Reference in New Issue
Block a user