кнопки всегда тапабельны + тройной канал доставки для drag-to-select
This commit is contained in:
@@ -1705,7 +1705,6 @@ class _LongPressBubble extends StatefulWidget {
|
||||
class _LongPressBubbleState extends State<_LongPressBubble> {
|
||||
final GlobalKey _boundaryKey = GlobalKey();
|
||||
MessageActionsController? _controller;
|
||||
int? _lastPointerId;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -1715,9 +1714,6 @@ class _LongPressBubbleState extends State<_LongPressBubble> {
|
||||
}
|
||||
|
||||
void _onLongPressStart(LongPressStartDetails details) {
|
||||
final pointerId = _lastPointerId;
|
||||
if (pointerId == null) return;
|
||||
|
||||
final ctx = _boundaryKey.currentContext;
|
||||
if (ctx == null) return;
|
||||
final renderObject = ctx.findRenderObject();
|
||||
@@ -1738,7 +1734,7 @@ class _LongPressBubbleState extends State<_LongPressBubble> {
|
||||
Haptics.medium();
|
||||
|
||||
final controller = MessageActionsController();
|
||||
controller.attach(details.globalPosition, pointerId: pointerId);
|
||||
controller.attach(details.globalPosition);
|
||||
_controller = controller;
|
||||
|
||||
Navigator.of(ctx)
|
||||
@@ -1764,10 +1760,15 @@ class _LongPressBubbleState extends State<_LongPressBubble> {
|
||||
Widget build(BuildContext context) {
|
||||
return Listener(
|
||||
behavior: HitTestBehavior.deferToChild,
|
||||
onPointerDown: (event) => _lastPointerId = event.pointer,
|
||||
onPointerMove: (event) => _controller?.updatePointer(event.position),
|
||||
onPointerUp: (event) => _controller?.commit(),
|
||||
onPointerCancel: (event) => _controller?.commit(),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.deferToChild,
|
||||
onLongPressStart: _onLongPressStart,
|
||||
onLongPressMoveUpdate: (d) =>
|
||||
_controller?.updatePointer(d.globalPosition),
|
||||
onLongPressEnd: (_) => _controller?.commit(),
|
||||
child: RepaintBoundary(
|
||||
key: _boundaryKey,
|
||||
child: widget.child,
|
||||
|
||||
@@ -10,33 +10,35 @@ import '../../core/utils/haptics.dart';
|
||||
import 'custom_notification.dart';
|
||||
|
||||
class MessageActionsController extends ChangeNotifier {
|
||||
int? _pointerId;
|
||||
Offset? pointer;
|
||||
Offset? initialPointer;
|
||||
bool committed = false;
|
||||
bool movedSignificantly = false;
|
||||
bool _attached = false;
|
||||
|
||||
void attach(Offset initial, {int? pointerId}) {
|
||||
void attach(Offset initial) {
|
||||
if (_attached) return;
|
||||
_attached = true;
|
||||
_pointerId = pointerId;
|
||||
initialPointer = initial;
|
||||
pointer = initial;
|
||||
GestureBinding.instance.pointerRouter.addGlobalRoute(_onPointerEvent);
|
||||
}
|
||||
|
||||
void updatePointer(Offset p) {
|
||||
if (committed) return;
|
||||
pointer = p;
|
||||
if (initialPointer != null &&
|
||||
!movedSignificantly &&
|
||||
(p - initialPointer!).distance > 18) {
|
||||
movedSignificantly = true;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void _onPointerEvent(PointerEvent event) {
|
||||
if (committed) return;
|
||||
if (_pointerId != null && event.pointer != _pointerId) return;
|
||||
if (event is PointerMoveEvent) {
|
||||
pointer = event.position;
|
||||
if (initialPointer != null &&
|
||||
!movedSignificantly &&
|
||||
(event.position - initialPointer!).distance > 18) {
|
||||
movedSignificantly = true;
|
||||
}
|
||||
notifyListeners();
|
||||
updatePointer(event.position);
|
||||
} else if (event is PointerUpEvent || event is PointerCancelEvent) {
|
||||
commit();
|
||||
}
|
||||
@@ -127,7 +129,6 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> {
|
||||
bool _initialized = false;
|
||||
|
||||
int _hoveredIndex = -1;
|
||||
bool _tapMode = false;
|
||||
bool _committedFired = false;
|
||||
|
||||
@override
|
||||
@@ -186,7 +187,7 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> {
|
||||
}
|
||||
|
||||
void _onControllerUpdate() {
|
||||
if (!mounted || _tapMode) return;
|
||||
if (!mounted) return;
|
||||
|
||||
final p = widget.controller.pointer;
|
||||
if (p != null) {
|
||||
@@ -213,13 +214,11 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> {
|
||||
}
|
||||
|
||||
void _onCommit() {
|
||||
if (_hoveredIndex != -1) {
|
||||
if (_hoveredIndex != -1 && widget.controller.movedSignificantly) {
|
||||
Haptics.medium();
|
||||
_actions[_hoveredIndex].onTap();
|
||||
} else if (widget.controller.movedSignificantly) {
|
||||
_close();
|
||||
} else {
|
||||
setState(() => _tapMode = true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +254,7 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> {
|
||||
final bubbleScale = 1.0 + 0.05 * t;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: _tapMode ? _close : null,
|
||||
onTap: _close,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Stack(
|
||||
children: [
|
||||
@@ -326,7 +325,6 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> {
|
||||
child: _ActionButton(
|
||||
action: _actions[i],
|
||||
highlighted: isHovered,
|
||||
tapEnabled: _tapMode,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -394,11 +392,9 @@ class _Action {
|
||||
class _ActionButton extends StatelessWidget {
|
||||
final _Action action;
|
||||
final bool highlighted;
|
||||
final bool tapEnabled;
|
||||
const _ActionButton({
|
||||
required this.action,
|
||||
required this.highlighted,
|
||||
required this.tapEnabled,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -425,12 +421,10 @@ class _ActionButton extends StatelessWidget {
|
||||
shape: const CircleBorder(),
|
||||
child: InkWell(
|
||||
customBorder: const CircleBorder(),
|
||||
onTap: tapEnabled
|
||||
? () {
|
||||
Haptics.tap();
|
||||
action.onTap();
|
||||
}
|
||||
: null,
|
||||
onTap: () {
|
||||
Haptics.tap();
|
||||
action.onTap();
|
||||
},
|
||||
child: Center(
|
||||
child: Icon(action.icon, color: iconColor, size: 24),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user