From d0c438268d3863cddc795d08ddc68f0ab46b12b0 Mon Sep 17 00:00:00 2001 From: csf Date: Thu, 8 Sep 2022 22:18:02 +0800 Subject: [PATCH] update overlay widgets on flutter desktop 1. add mobile actions 2. disable showChatIcon --- flutter/lib/common.dart | 59 ++++++++- flutter/lib/desktop/pages/remote_page.dart | 4 +- .../lib/desktop/widgets/remote_menubar.dart | 26 ++-- flutter/lib/mobile/pages/remote_page.dart | 19 +-- flutter/lib/mobile/widgets/overlay.dart | 121 ++++++------------ flutter/lib/models/chat_model.dart | 7 +- flutter/lib/models/model.dart | 7 +- 7 files changed, 126 insertions(+), 117 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 92ae17f9a..249b45a0c 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -14,6 +14,7 @@ import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; +import 'mobile/widgets/overlay.dart'; import 'models/model.dart'; import 'models/platform_model.dart'; @@ -294,9 +295,11 @@ class Dialog { class OverlayDialogManager { OverlayState? _overlayState; - Map _dialogs = Map(); + final Map _dialogs = {}; int _tagCount = 0; + OverlayEntry? _mobileActionsOverlayEntry; + /// By default OverlayDialogManager use global overlay OverlayDialogManager() { _overlayState = globalKey.currentState?.overlay; @@ -418,6 +421,60 @@ class OverlayDialogManager { ); }); } + + void resetMobileActionsOverlay({FFI? ffi}) { + if (_mobileActionsOverlayEntry == null) return; + hideMobileActionsOverlay(); + showMobileActionsOverlay(ffi: ffi); + } + + void showMobileActionsOverlay({FFI? ffi}) { + if (_mobileActionsOverlayEntry != null) return; + if (_overlayState == null) return; + + // compute overlay position + final screenW = MediaQuery.of(globalKey.currentContext!).size.width; + final screenH = MediaQuery.of(globalKey.currentContext!).size.height; + const double overlayW = 200; + const double overlayH = 45; + final left = (screenW - overlayW) / 2; + final top = screenH - overlayH - 80; + + final overlay = OverlayEntry(builder: (context) { + final session = ffi ?? gFFI; + return DraggableMobileActions( + position: Offset(left, top), + width: overlayW, + height: overlayH, + onBackPressed: () => session.tap(MouseButtons.right), + onHomePressed: () => session.tap(MouseButtons.wheel), + onRecentPressed: () async { + session.sendMouse('down', MouseButtons.wheel); + await Future.delayed(const Duration(milliseconds: 500)); + session.sendMouse('up', MouseButtons.wheel); + }, + onHidePressed: () => hideMobileActionsOverlay(), + ); + }); + _overlayState!.insert(overlay); + _mobileActionsOverlayEntry = overlay; + } + + void hideMobileActionsOverlay() { + if (_mobileActionsOverlayEntry != null) { + _mobileActionsOverlayEntry!.remove(); + _mobileActionsOverlayEntry = null; + return; + } + } + + void toggleMobileActionsOverlay({FFI? ffi}) { + if (_mobileActionsOverlayEntry == null) { + showMobileActionsOverlay(ffi: ffi); + } else { + hideMobileActionsOverlay(); + } + } } void showToast(String text, {Duration timeout = const Duration(seconds: 2)}) { diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 158028ab3..c03c2f3d4 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/gestures.dart'; @@ -16,7 +15,6 @@ import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; import '../widgets/remote_menubar.dart'; import '../../common.dart'; import '../../mobile/widgets/dialog.dart'; -import '../../mobile/widgets/overlay.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../../common/shared_state.dart'; @@ -107,7 +105,7 @@ class _RemotePageState extends State @override void dispose() { debugPrint("REMOTE PAGE dispose ${widget.id}"); - hideMobileActionsOverlay(); + _ffi.dialogManager.hideMobileActionsOverlay(); _ffi.listenToMouse(false); _mobileFocusNode.dispose(); _physicalFocusNode.dispose(); diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 28085246f..c5e74be12 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -6,7 +6,6 @@ import 'package:rxdart/rxdart.dart' as rxdart; import '../../common.dart'; import '../../mobile/widgets/dialog.dart'; -import '../../mobile/widgets/overlay.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../../common/shared_state.dart'; @@ -75,20 +74,17 @@ class _RemoteMenubarState extends State { final List menubarItems = []; if (!isWebDesktop) { menubarItems.add(_buildFullscreen(context)); - //if (widget.ffi.ffiModel.isPeerAndroid) { - menubarItems.add(IconButton( - tooltip: translate('Mobile Actions'), - color: _MenubarTheme.commonColor, - icon: const Icon(Icons.build), - onPressed: () { - if (mobileActionsOverlayEntry == null) { - showMobileActionsOverlay(); - } else { - hideMobileActionsOverlay(); - } - }, - )); - //} + if (widget.ffi.ffiModel.isPeerAndroid) { + menubarItems.add(IconButton( + tooltip: translate('Mobile Actions'), + color: _MenubarTheme.commonColor, + icon: const Icon(Icons.build), + onPressed: () { + widget.ffi.dialogManager + .toggleMobileActionsOverlay(ffi: widget.ffi); + }, + )); + } } menubarItems.add(_buildMonitor(context)); menubarItems.add(_buildControl(context)); diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index ceb3df0ff..419a98f3a 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -14,7 +14,6 @@ import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../widgets/dialog.dart'; import '../widgets/gestures.dart'; -import '../widgets/overlay.dart'; final initText = '\1' * 1024; @@ -64,7 +63,7 @@ class _RemotePageState extends State { @override void dispose() { - hideMobileActionsOverlay(); + gFFI.dialogManager.hideMobileActionsOverlay(); gFFI.listenToMouse(false); gFFI.invokeMethod("enable_soft_keyboard", true); _mobileFocusNode.dispose(); @@ -266,8 +265,9 @@ class _RemotePageState extends State { : SafeArea(child: OrientationBuilder(builder: (ctx, orientation) { if (_currentOrientation != orientation) { - Timer(Duration(milliseconds: 200), () { - resetMobileActionsOverlay(); + Timer(const Duration(milliseconds: 200), () { + gFFI.dialogManager + .resetMobileActionsOverlay(ffi: gFFI); _currentOrientation = orientation; gFFI.canvasModel.updateViewStyle(); }); @@ -422,14 +422,9 @@ class _RemotePageState extends State { ? [ IconButton( color: Colors.white, - icon: Icon(Icons.build), - onPressed: () { - if (mobileActionsOverlayEntry == null) { - showMobileActionsOverlay(); - } else { - hideMobileActionsOverlay(); - } - }, + icon: const Icon(Icons.build), + onPressed: () => gFFI.dialogManager + .toggleMobileActionsOverlay(ffi: gFFI), ) ] : [ diff --git a/flutter/lib/mobile/widgets/overlay.dart b/flutter/lib/mobile/widgets/overlay.dart index 976d9bb73..b8fd8f653 100644 --- a/flutter/lib/mobile/widgets/overlay.dart +++ b/flutter/lib/mobile/widgets/overlay.dart @@ -2,11 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import '../../models/chat_model.dart'; -import '../../models/model.dart'; import '../pages/chat_page.dart'; -OverlayEntry? mobileActionsOverlayEntry; - class DraggableChatWindow extends StatelessWidget { DraggableChatWindow( {this.position = Offset.zero, @@ -99,6 +96,7 @@ class DraggableMobileActions extends StatelessWidget { this.onBackPressed, this.onRecentPressed, this.onHomePressed, + this.onHidePressed, required this.width, required this.height}); @@ -108,6 +106,7 @@ class DraggableMobileActions extends StatelessWidget { final VoidCallback? onBackPressed; final VoidCallback? onHomePressed; final VoidCallback? onRecentPressed; + final VoidCallback? onHidePressed; @override Widget build(BuildContext context) { @@ -118,89 +117,49 @@ class DraggableMobileActions extends StatelessWidget { builder: (_, onPanUpdate) { return GestureDetector( onPanUpdate: onPanUpdate, - child: Container( - decoration: BoxDecoration( - color: MyTheme.accent.withOpacity(0.4), - borderRadius: BorderRadius.all(Radius.circular(15))), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - IconButton( - color: MyTheme.white, - onPressed: onBackPressed, - icon: Icon(Icons.arrow_back)), - IconButton( - color: MyTheme.white, - onPressed: onHomePressed, - icon: Icon(Icons.home)), - IconButton( - color: MyTheme.white, - onPressed: onRecentPressed, - icon: Icon(Icons.more_horiz)), - VerticalDivider( - width: 0, - thickness: 2, - indent: 10, - endIndent: 10, + child: Card( + color: Colors.transparent, + shadowColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: MyTheme.accent.withOpacity(0.4), + borderRadius: BorderRadius.all(Radius.circular(15))), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton( + color: MyTheme.white, + onPressed: onBackPressed, + splashRadius: 20, + icon: const Icon(Icons.arrow_back)), + IconButton( + color: MyTheme.white, + onPressed: onHomePressed, + splashRadius: 20, + icon: const Icon(Icons.home)), + IconButton( + color: MyTheme.white, + onPressed: onRecentPressed, + splashRadius: 20, + icon: const Icon(Icons.more_horiz)), + const VerticalDivider( + width: 0, + thickness: 2, + indent: 10, + endIndent: 10, + ), + IconButton( + color: MyTheme.white, + onPressed: onHidePressed, + splashRadius: 20, + icon: const Icon(Icons.keyboard_arrow_down)), + ], ), - IconButton( - color: MyTheme.white, - onPressed: hideMobileActionsOverlay, - icon: Icon(Icons.keyboard_arrow_down)), - ], - ), - )); + ))); }); } } -resetMobileActionsOverlay() { - if (mobileActionsOverlayEntry == null) return; - hideMobileActionsOverlay(); - showMobileActionsOverlay(); -} - -showMobileActionsOverlay() { - if (mobileActionsOverlayEntry != null) return; - if (globalKey.currentContext == null || - globalKey.currentState == null || - globalKey.currentState!.overlay == null) return; - final globalOverlayState = globalKey.currentState!.overlay!; - - // compute overlay position - final screenW = MediaQuery.of(globalKey.currentContext!).size.width; - final screenH = MediaQuery.of(globalKey.currentContext!).size.height; - final double overlayW = 200; - final double overlayH = 45; - final left = (screenW - overlayW) / 2; - final top = screenH - overlayH - 80; - - final overlay = OverlayEntry(builder: (context) { - return DraggableMobileActions( - position: Offset(left, top), - width: overlayW, - height: overlayH, - onBackPressed: () => gFFI.tap(MouseButtons.right), - onHomePressed: () => gFFI.tap(MouseButtons.wheel), - onRecentPressed: () async { - gFFI.sendMouse('down', MouseButtons.wheel); - await Future.delayed(Duration(milliseconds: 500)); - gFFI.sendMouse('up', MouseButtons.wheel); - }, - ); - }); - globalOverlayState.insert(overlay); - mobileActionsOverlayEntry = overlay; -} - -hideMobileActionsOverlay() { - if (mobileActionsOverlayEntry != null) { - mobileActionsOverlayEntry!.remove(); - mobileActionsOverlayEntry = null; - return; - } -} - class Draggable extends StatefulWidget { Draggable( {this.checkKeyboard = false, diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index a9c791ef7..4bdf5826a 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -143,9 +143,12 @@ class ChatModel with ChangeNotifier { } toggleChatOverlay() { - if (chatIconOverlayEntry == null || chatWindowOverlayEntry == null) { + if ((!isDesktop && chatIconOverlayEntry == null) || + chatWindowOverlayEntry == null) { gFFI.invokeMethod("enable_soft_keyboard", true); - showChatIconOverlay(); + if (!isDesktop) { + showChatIconOverlay(); + } showChatWindowOverlay(); } else { hideChatIconOverlay(); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index e96eb35a3..e907f3ded 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -22,7 +22,6 @@ import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; import '../common.dart'; import '../common/shared_state.dart'; import '../mobile/widgets/dialog.dart'; -import '../mobile/widgets/overlay.dart'; import 'peer_model.dart'; import 'platform_model.dart'; @@ -267,8 +266,10 @@ class FfiModel with ChangeNotifier { if (isPeerAndroid) { _touchMode = true; - if (parent.target?.ffiModel.permissions['keyboard'] != false) { - Timer(const Duration(milliseconds: 100), showMobileActionsOverlay); + if (parent.target != null && + parent.target!.ffiModel.permissions['keyboard'] != false) { + Timer(const Duration(milliseconds: 100), + parent.target!.dialogManager.showMobileActionsOverlay); } } else { _touchMode =