diff --git a/flutter_hbb/lib/drag.dart b/flutter_hbb/lib/drag.dart new file mode 100644 index 000000000..551daa880 --- /dev/null +++ b/flutter_hbb/lib/drag.dart @@ -0,0 +1,104 @@ +import 'package:flutter/gestures.dart'; + +class MultiTouchGestureRecognizer extends MultiTapGestureRecognizer { + MultiTouchGestureRecognizerCallback onMultiTap; + var numberOfTouches = 0; + + MultiTouchGestureRecognizer() { + this + ..onTapDown = addTouch + ..onTapUp = removeTouch + ..onTapCancel = cancelTouch + ..onTap = captureDefaultTap; + } + + void addTouch(int pointer, TapDownDetails details) { + numberOfTouches++; + onMultiTap(numberOfTouches, true); + } + + void removeTouch(int pointer, TapUpDetails details) { + numberOfTouches--; + onMultiTap(numberOfTouches, false); + } + + void cancelTouch(int pointer) { + numberOfTouches = 0; + } + + void captureDefaultTap(int pointer) {} +} + +typedef MultiTouchGestureRecognizerCallback = void Function( + int touchCount, bool addOrRemove); + +typedef OnUpdate(DragUpdateDetails details); + +class CustomMultiDrag extends Drag { + CustomMultiDrag({this.events, this.offset}); + + List events; + Offset offset; + + @override + void update(DragUpdateDetails details) { + var n = events.length; + print('$n $details'); + } + + @override + void end(DragEndDetails details) { + super.end(details); + } +} + +typedef OnDisposeState(); + +// clone _ImmediatePointerState +class CustomPointerState extends MultiDragPointerState { + final OnDisposeState onDisposeState; + CustomPointerState(Offset initialPosition, PointerDeviceKind kind, + {this.onDisposeState}) + : super(initialPosition, kind); + + @override + void checkForResolutionAfterMove() { + assert(pendingDelta != null); + if (pendingDelta.distance > computeHitSlop(kind)) + resolve(GestureDisposition.accepted); + } + + @override + void accepted(GestureMultiDragStartCallback starter) { + starter(initialPosition); + } + + @override + void dispose() { + onDisposeState.call(); + super.dispose(); + } +} + +// clone ImmediateMultiDragGestureRecognizer +class CustomMultiDragGestureRecognizer + extends MultiDragGestureRecognizer { + var events = List(); + + /// Create a gesture recognizer for tracking multiple pointers at once. + CustomMultiDragGestureRecognizer({ + Object debugOwner, + PointerDeviceKind kind, + }) : super(debugOwner: debugOwner, kind: kind); + + @override + CustomPointerState createNewPointerState(PointerDownEvent event) { + events.add(event); + return CustomPointerState(event.position, event.kind, onDisposeState: () { + events.remove(event); + }); + } + + @override + String get debugDescription => 'custom_multidrag'; +} diff --git a/flutter_hbb/lib/remote_page.dart b/flutter_hbb/lib/remote_page.dart index b8cfbc699..c0a84b2b6 100644 --- a/flutter_hbb/lib/remote_page.dart +++ b/flutter_hbb/lib/remote_page.dart @@ -7,9 +7,10 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'dart:async'; import 'dart:math' as math; import 'package:tuple/tuple.dart'; -import 'common.dart'; -import 'model.dart'; import 'package:wakelock/wakelock.dart'; +import 'common.dart'; +import 'drag.dart'; +import 'model.dart'; class RemotePage extends StatefulWidget { RemotePage({Key key, this.id}) : super(key: key); @@ -26,6 +27,7 @@ class _RemotePageState extends State { bool _showBar = true; double _bottom = 0; bool _pan = false; + var _scaleMode = false; final FocusNode _focusNode = FocusNode(); @override @@ -162,106 +164,7 @@ class _RemotePageState extends State { ) : null, body: RawGestureDetector( - gestures: { - MultiTouchGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - MultiTouchGestureRecognizer>( - () => MultiTouchGestureRecognizer(), - (MultiTouchGestureRecognizer instance) { - instance.onMultiTap = ( - touchCount, - addOrRemove, - ) => - print('$touchCount, $addOrRemove'); - }, - ), - TapGestureRecognizer: - GestureRecognizerFactoryWithHandlers( - () => TapGestureRecognizer(), - (TapGestureRecognizer instance) { - instance.onTap = () { - print('tap'); - }; - }, - ), - ImmediateMultiDragGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - ImmediateMultiDragGestureRecognizer>( - () => ImmediateMultiDragGestureRecognizer(), - (ImmediateMultiDragGestureRecognizer instance) { - instance - ..onStart = (x) { - return CustomDrag(); - }; - }, - ), - LongPressGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - LongPressGestureRecognizer>( - () => LongPressGestureRecognizer(), - (LongPressGestureRecognizer instance) { - var x = 0.0; - var y = 0.0; - instance - ..onLongPressStart = (details) { - x = details.globalPosition.dx; - y = details.globalPosition.dy; - } - ..onLongPress = () { - print('long press'); - () async { - await showMenu( - context: context, - position: RelativeRect.fromLTRB(x, y, 0, 0), - items: [ - PopupMenuItem( - child: const Text('Doge'), value: 'Doge'), - PopupMenuItem( - child: const Text('Lion'), value: 'Lion'), - ], - elevation: 8.0, - ); - }(); - }; - }, - ), - PanGestureRecognizer: - GestureRecognizerFactoryWithHandlers( - () => PanGestureRecognizer(), - (PanGestureRecognizer instance) { - instance - ..onStart = (detail) { - print('pan start'); - } - ..onUpdate = (detail) { - print('$detail'); - }; - }, - ), - ScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers< - ScaleGestureRecognizer>( - () => ScaleGestureRecognizer(), - (ScaleGestureRecognizer instance) { - instance - ..onStart = (detail) { - print('scale start'); - } - ..onUpdate = (detail) { - print('$detail'); - }; - }, - ), - DoubleTapGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - DoubleTapGestureRecognizer>( - () => DoubleTapGestureRecognizer(), - (DoubleTapGestureRecognizer instance) { - instance.onDoubleTap = () { - print('double tap'); - }; - }, - ), - }, + gestures: buildGuestures(), child: FlutterEasyLoading( child: Container( color: MyTheme.canvasColor, @@ -288,6 +191,101 @@ class _RemotePageState extends State { )); } + Map buildGuestures() { + var m = { + TapGestureRecognizer: + GestureRecognizerFactoryWithHandlers( + () => TapGestureRecognizer(), + (TapGestureRecognizer instance) { + instance.onTap = () { + print('tap'); + }; + }, + ), + MultiTouchGestureRecognizer: + GestureRecognizerFactoryWithHandlers( + () => MultiTouchGestureRecognizer(), + (MultiTouchGestureRecognizer instance) { + instance.onMultiTap = ( + touchCount, + addOrRemove, + ) { + if (touchCount == 3 && addOrRemove) { + setState(() => _scaleMode = !_scaleMode); + } + }; + }, + ), + CustomMultiDragGestureRecognizer: GestureRecognizerFactoryWithHandlers< + CustomMultiDragGestureRecognizer>( + () => CustomMultiDragGestureRecognizer(), + (CustomMultiDragGestureRecognizer instance) { + instance + ..onStart = (offset) { + return CustomMultiDrag(events: instance.events, offset: offset); + }; + }, + ), + LongPressGestureRecognizer: + GestureRecognizerFactoryWithHandlers( + () => LongPressGestureRecognizer(), + (LongPressGestureRecognizer instance) { + var x = 0.0; + var y = 0.0; + instance + ..onLongPressStart = (details) { + x = details.globalPosition.dx; + y = details.globalPosition.dy; + } + ..onLongPress = () { + print('long press'); + () async { + await showMenu( + context: context, + position: RelativeRect.fromLTRB(x, y, 0, 0), + items: [ + PopupMenuItem( + child: const Text('Doge'), value: 'Doge'), + PopupMenuItem( + child: const Text('Lion'), value: 'Lion'), + ], + elevation: 8.0, + ); + }(); + }; + }, + ), + ScaleGestureRecognizer: + GestureRecognizerFactoryWithHandlers( + () => ScaleGestureRecognizer(), + (ScaleGestureRecognizer instance) { + instance + ..onStart = (detail) { + print('scale start'); + } + ..onUpdate = (detail) { + print('$detail'); + }; + }, + ), + DoubleTapGestureRecognizer: + GestureRecognizerFactoryWithHandlers( + () => DoubleTapGestureRecognizer(), + (DoubleTapGestureRecognizer instance) { + instance.onDoubleTap = () { + print('double tap'); + }; + }, + ), + }; + if (_scaleMode) { + m.remove(CustomMultiDragGestureRecognizer); + } else { + m.remove(ScaleGestureRecognizer); + } + return m; + } + void close() { msgbox('', 'Close', 'Are you sure to close the connection?', context); } @@ -503,52 +501,3 @@ void showActions(BuildContext context) { true, 0); } - -class MultiTouchGestureRecognizer extends MultiTapGestureRecognizer { - MultiTouchGestureRecognizerCallback onMultiTap; - var numberOfTouches = 0; - - MultiTouchGestureRecognizer() { - this - ..onTapDown = addTouch - ..onTapUp = removeTouch - ..onTapCancel = cancelTouch - ..onTap = captureDefaultTap; - } - - void addTouch(int pointer, TapDownDetails details) { - numberOfTouches++; - onMultiTap(numberOfTouches, true); - } - - void removeTouch(int pointer, TapUpDetails details) { - numberOfTouches--; - onMultiTap(numberOfTouches, false); - } - - void cancelTouch(int pointer) { - numberOfTouches--; - print('$numberOfTouches x'); - } - - void captureDefaultTap(int pointer) { - print('$pointer'); - } -} - -typedef MultiTouchGestureRecognizerCallback = void Function( - int touchCount, bool addOrRemove); - -typedef OnUpdate(DragUpdateDetails details); - -class CustomDrag extends Drag { - @override - void update(DragUpdateDetails details) { - print('xx $details'); - } - - @override - void end(DragEndDetails details) { - super.end(details); - } -}