fix: mobile actions, position (#8446)
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
a9e0ea8520
commit
40cb59336f
flutter/lib
@ -718,7 +718,21 @@ class OverlayDialogManager {
|
|||||||
int _tagCount = 0;
|
int _tagCount = 0;
|
||||||
|
|
||||||
OverlayEntry? _mobileActionsOverlayEntry;
|
OverlayEntry? _mobileActionsOverlayEntry;
|
||||||
RxBool mobileActionsOverlayVisible = false.obs;
|
RxBool mobileActionsOverlayVisible = true.obs;
|
||||||
|
|
||||||
|
setMobileActionsOverlayVisible(bool v, {store = true}) {
|
||||||
|
if (store) {
|
||||||
|
bind.setLocalFlutterOption(k: kOptionShowMobileAction, v: v ? 'Y' : 'N');
|
||||||
|
}
|
||||||
|
// No need to read the value from local storage after setting it.
|
||||||
|
// It better to toggle the value directly.
|
||||||
|
mobileActionsOverlayVisible.value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadMobileActionsOverlayVisible() {
|
||||||
|
mobileActionsOverlayVisible.value =
|
||||||
|
bind.getLocalFlutterOption(k: kOptionShowMobileAction) != 'N';
|
||||||
|
}
|
||||||
|
|
||||||
void setOverlayState(OverlayKeyState overlayKeyState) {
|
void setOverlayState(OverlayKeyState overlayKeyState) {
|
||||||
_overlayKeyState = overlayKeyState;
|
_overlayKeyState = overlayKeyState;
|
||||||
@ -865,14 +879,14 @@ class OverlayDialogManager {
|
|||||||
);
|
);
|
||||||
overlayState.insert(overlay);
|
overlayState.insert(overlay);
|
||||||
_mobileActionsOverlayEntry = overlay;
|
_mobileActionsOverlayEntry = overlay;
|
||||||
mobileActionsOverlayVisible.value = true;
|
setMobileActionsOverlayVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideMobileActionsOverlay() {
|
void hideMobileActionsOverlay({store = true}) {
|
||||||
if (_mobileActionsOverlayEntry != null) {
|
if (_mobileActionsOverlayEntry != null) {
|
||||||
_mobileActionsOverlayEntry!.remove();
|
_mobileActionsOverlayEntry!.remove();
|
||||||
_mobileActionsOverlayEntry = null;
|
_mobileActionsOverlayEntry = null;
|
||||||
mobileActionsOverlayVisible.value = false;
|
setMobileActionsOverlayVisible(false, store: store);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -891,21 +905,27 @@ class OverlayDialogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
makeMobileActionsOverlayEntry(VoidCallback? onHide, {FFI? ffi}) {
|
makeMobileActionsOverlayEntry(VoidCallback? onHide, {FFI? ffi}) {
|
||||||
final position = SimpleWrapper(Offset(0, 0));
|
|
||||||
makeMobileActions(BuildContext context, double s) {
|
makeMobileActions(BuildContext context, double s) {
|
||||||
final scale = s < 0.85 ? 0.85 : s;
|
final scale = s < 0.85 ? 0.85 : s;
|
||||||
final session = ffi ?? gFFI;
|
final session = ffi ?? gFFI;
|
||||||
// compute overlay position
|
|
||||||
final screenW = MediaQuery.of(context).size.width;
|
|
||||||
final screenH = MediaQuery.of(context).size.height;
|
|
||||||
const double overlayW = 200;
|
const double overlayW = 200;
|
||||||
const double overlayH = 45;
|
const double overlayH = 45;
|
||||||
final left = (screenW - overlayW * scale) / 2;
|
computeOverlayPosition() {
|
||||||
final top = screenH - (overlayH + 80) * scale;
|
final screenW = MediaQuery.of(context).size.width;
|
||||||
position.value = Offset(left, top);
|
final screenH = MediaQuery.of(context).size.height;
|
||||||
|
final left = (screenW - overlayW * scale) / 2;
|
||||||
|
final top = screenH - (overlayH + 80) * scale;
|
||||||
|
return Offset(left, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (draggablePositions.mobileActions.isInvalid()) {
|
||||||
|
draggablePositions.mobileActions.update(computeOverlayPosition());
|
||||||
|
} else {
|
||||||
|
draggablePositions.mobileActions.tryAdjust(overlayW, overlayH, scale);
|
||||||
|
}
|
||||||
return DraggableMobileActions(
|
return DraggableMobileActions(
|
||||||
scale: scale,
|
scale: scale,
|
||||||
position: position,
|
position: draggablePositions.mobileActions,
|
||||||
width: overlayW,
|
width: overlayW,
|
||||||
height: overlayH,
|
height: overlayH,
|
||||||
onBackPressed: () => session.inputModel.tap(MouseButtons.right),
|
onBackPressed: () => session.inputModel.tap(MouseButtons.right),
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:debounce_throttle/debounce_throttle.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -26,9 +28,12 @@ class DraggableChatWindow extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (draggablePositions.chatWindow.isInvalid()) {
|
||||||
|
draggablePositions.chatWindow.update(position);
|
||||||
|
}
|
||||||
return isIOS
|
return isIOS
|
||||||
? IOSDraggable(
|
? IOSDraggable(
|
||||||
position: position,
|
position: draggablePositions.chatWindow,
|
||||||
chatModel: chatModel,
|
chatModel: chatModel,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@ -45,7 +50,7 @@ class DraggableChatWindow extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: Draggable(
|
: Draggable(
|
||||||
checkKeyboard: true,
|
checkKeyboard: true,
|
||||||
position: SimpleWrapper(position),
|
position: draggablePositions.chatWindow,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
chatModel: chatModel,
|
chatModel: chatModel,
|
||||||
@ -176,7 +181,7 @@ class DraggableMobileActions extends StatelessWidget {
|
|||||||
required this.scale});
|
required this.scale});
|
||||||
|
|
||||||
final double scale;
|
final double scale;
|
||||||
final SimpleWrapper<Offset> position;
|
final DraggableKeyPosition position;
|
||||||
final double width;
|
final double width;
|
||||||
final double height;
|
final double height;
|
||||||
final VoidCallback? onBackPressed;
|
final VoidCallback? onBackPressed;
|
||||||
@ -241,6 +246,92 @@ class DraggableMobileActions extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DraggableKeyPosition {
|
||||||
|
final String key;
|
||||||
|
Offset _pos;
|
||||||
|
late Debouncer<int> _debouncerStore;
|
||||||
|
DraggableKeyPosition(this.key)
|
||||||
|
: _pos = DraggablePositions.kInvalidDraggablePosition;
|
||||||
|
|
||||||
|
get pos => _pos;
|
||||||
|
|
||||||
|
_loadPosition(String k) {
|
||||||
|
final value = bind.getLocalFlutterOption(k: k);
|
||||||
|
if (value.isNotEmpty) {
|
||||||
|
final parts = value.split(',');
|
||||||
|
if (parts.length == 2) {
|
||||||
|
return Offset(double.parse(parts[0]), double.parse(parts[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DraggablePositions.kInvalidDraggablePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
load() {
|
||||||
|
_pos = _loadPosition(key);
|
||||||
|
_debouncerStore = Debouncer<int>(const Duration(milliseconds: 500),
|
||||||
|
onChanged: (v) => _store(), initialValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(Offset pos) {
|
||||||
|
_pos = pos;
|
||||||
|
_triggerStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust position to keep it in the screen
|
||||||
|
// Only used for desktop and web desktop
|
||||||
|
tryAdjust(double w, double h, double scale) {
|
||||||
|
final size = MediaQuery.of(Get.context!).size;
|
||||||
|
w = w * scale;
|
||||||
|
h = h * scale;
|
||||||
|
double x = _pos.dx;
|
||||||
|
double y = _pos.dy;
|
||||||
|
if (x + w > size.width) {
|
||||||
|
x = size.width - w;
|
||||||
|
}
|
||||||
|
final tabBarHeight = isDesktop ? kDesktopRemoteTabBarHeight : 0;
|
||||||
|
if (y + h > (size.height - tabBarHeight)) {
|
||||||
|
y = size.height - tabBarHeight - h;
|
||||||
|
}
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
if (x != _pos.dx || y != _pos.dy) {
|
||||||
|
update(Offset(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isInvalid() {
|
||||||
|
return _pos == DraggablePositions.kInvalidDraggablePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
_triggerStore() => _debouncerStore.value = _debouncerStore.value + 1;
|
||||||
|
_store() {
|
||||||
|
bind.setLocalFlutterOption(k: key, v: '${_pos.dx},${_pos.dy}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DraggablePositions {
|
||||||
|
static const kChatWindow = 'draggablePositionChat';
|
||||||
|
static const kMobileActions = 'draggablePositionMobile';
|
||||||
|
static const kIOSDraggable = 'draggablePositionIOS';
|
||||||
|
|
||||||
|
static const kInvalidDraggablePosition = Offset(-999999, -999999);
|
||||||
|
final chatWindow = DraggableKeyPosition(kChatWindow);
|
||||||
|
final mobileActions = DraggableKeyPosition(kMobileActions);
|
||||||
|
final iOSDraggable = DraggableKeyPosition(kIOSDraggable);
|
||||||
|
|
||||||
|
load() {
|
||||||
|
chatWindow.load();
|
||||||
|
mobileActions.load();
|
||||||
|
iOSDraggable.load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DraggablePositions draggablePositions = DraggablePositions();
|
||||||
|
|
||||||
class Draggable extends StatefulWidget {
|
class Draggable extends StatefulWidget {
|
||||||
Draggable(
|
Draggable(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@ -255,7 +346,7 @@ class Draggable extends StatefulWidget {
|
|||||||
|
|
||||||
final bool checkKeyboard;
|
final bool checkKeyboard;
|
||||||
final bool checkScreenSize;
|
final bool checkScreenSize;
|
||||||
final SimpleWrapper<Offset> position;
|
final DraggableKeyPosition position;
|
||||||
final double width;
|
final double width;
|
||||||
final double height;
|
final double height;
|
||||||
final ChatModel? chatModel;
|
final ChatModel? chatModel;
|
||||||
@ -277,7 +368,7 @@ class _DraggableState extends State<Draggable> {
|
|||||||
_chatModel = widget.chatModel;
|
_chatModel = widget.chatModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
get position => widget.position.value;
|
get position => widget.position.pos;
|
||||||
|
|
||||||
void onPanUpdate(DragUpdateDetails d) {
|
void onPanUpdate(DragUpdateDetails d) {
|
||||||
final offset = d.delta;
|
final offset = d.delta;
|
||||||
@ -301,7 +392,7 @@ class _DraggableState extends State<Draggable> {
|
|||||||
y = position.dy + offset.dy;
|
y = position.dy + offset.dy;
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
widget.position.value = Offset(x, y);
|
widget.position.update(Offset(x, y));
|
||||||
});
|
});
|
||||||
_chatModel?.setChatWindowPosition(position);
|
_chatModel?.setChatWindowPosition(position);
|
||||||
}
|
}
|
||||||
@ -320,7 +411,7 @@ class _DraggableState extends State<Draggable> {
|
|||||||
// reset
|
// reset
|
||||||
if (_lastBottomHeight > 0 && bottomHeight == 0) {
|
if (_lastBottomHeight > 0 && bottomHeight == 0) {
|
||||||
setState(() {
|
setState(() {
|
||||||
widget.position.value = Offset(position.dx, _saveHeight);
|
widget.position.update(Offset(position.dx, _saveHeight));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +422,7 @@ class _DraggableState extends State<Draggable> {
|
|||||||
if (sumHeight + position.dy > contextHeight) {
|
if (sumHeight + position.dy > contextHeight) {
|
||||||
final y = contextHeight - sumHeight;
|
final y = contextHeight - sumHeight;
|
||||||
setState(() {
|
setState(() {
|
||||||
widget.position.value = Offset(position.dx, y);
|
widget.position.update(Offset(position.dx, y));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,14 +453,14 @@ class _DraggableState extends State<Draggable> {
|
|||||||
class IOSDraggable extends StatefulWidget {
|
class IOSDraggable extends StatefulWidget {
|
||||||
const IOSDraggable(
|
const IOSDraggable(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
this.position = Offset.zero,
|
|
||||||
this.chatModel,
|
this.chatModel,
|
||||||
|
required this.position,
|
||||||
required this.width,
|
required this.width,
|
||||||
required this.height,
|
required this.height,
|
||||||
required this.builder})
|
required this.builder})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
final Offset position;
|
final DraggableKeyPosition position;
|
||||||
final ChatModel? chatModel;
|
final ChatModel? chatModel;
|
||||||
final double width;
|
final double width;
|
||||||
final double height;
|
final double height;
|
||||||
@ -380,7 +471,6 @@ class IOSDraggable extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IOSDraggableState extends State<IOSDraggable> {
|
class IOSDraggableState extends State<IOSDraggable> {
|
||||||
late Offset _position;
|
|
||||||
late ChatModel? _chatModel;
|
late ChatModel? _chatModel;
|
||||||
late double _width;
|
late double _width;
|
||||||
late double _height;
|
late double _height;
|
||||||
@ -391,25 +481,26 @@ class IOSDraggableState extends State<IOSDraggable> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_position = widget.position;
|
|
||||||
_chatModel = widget.chatModel;
|
_chatModel = widget.chatModel;
|
||||||
_width = widget.width;
|
_width = widget.width;
|
||||||
_height = widget.height;
|
_height = widget.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get position => widget.position;
|
||||||
|
|
||||||
checkKeyboard() {
|
checkKeyboard() {
|
||||||
final bottomHeight = MediaQuery.of(context).viewInsets.bottom;
|
final bottomHeight = MediaQuery.of(context).viewInsets.bottom;
|
||||||
final currentVisible = bottomHeight != 0;
|
final currentVisible = bottomHeight != 0;
|
||||||
|
|
||||||
// save
|
// save
|
||||||
if (!_keyboardVisible && currentVisible) {
|
if (!_keyboardVisible && currentVisible) {
|
||||||
_saveHeight = _position.dy;
|
_saveHeight = position.value.dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset
|
// reset
|
||||||
if (_lastBottomHeight > 0 && bottomHeight == 0) {
|
if (_lastBottomHeight > 0 && bottomHeight == 0) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_position = Offset(_position.dx, _saveHeight);
|
position.value = Offset(position.value.dx, _saveHeight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,10 +508,10 @@ class IOSDraggableState extends State<IOSDraggable> {
|
|||||||
if (_keyboardVisible && currentVisible) {
|
if (_keyboardVisible && currentVisible) {
|
||||||
final sumHeight = bottomHeight + _height;
|
final sumHeight = bottomHeight + _height;
|
||||||
final contextHeight = MediaQuery.of(context).size.height;
|
final contextHeight = MediaQuery.of(context).size.height;
|
||||||
if (sumHeight + _position.dy > contextHeight) {
|
if (sumHeight + position.value.dy > contextHeight) {
|
||||||
final y = contextHeight - sumHeight;
|
final y = contextHeight - sumHeight;
|
||||||
setState(() {
|
setState(() {
|
||||||
_position = Offset(_position.dx, y);
|
position.value = Offset(position.value.dx, y);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,14 +526,14 @@ class IOSDraggableState extends State<IOSDraggable> {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned(
|
Positioned(
|
||||||
left: _position.dx,
|
left: position.value.dx,
|
||||||
top: _position.dy,
|
top: position.value.dy,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onPanUpdate: (details) {
|
onPanUpdate: (details) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_position += details.delta;
|
position.value += details.delta;
|
||||||
});
|
});
|
||||||
_chatModel?.setChatWindowPosition(_position);
|
_chatModel?.setChatWindowPosition(position.value);
|
||||||
},
|
},
|
||||||
child: Material(
|
child: Material(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -142,6 +142,8 @@ const String kOptionDisableFloatingWindow = "disable-floating-window";
|
|||||||
|
|
||||||
const String kOptionKeepScreenOn = "keep-screen-on";
|
const String kOptionKeepScreenOn = "keep-screen-on";
|
||||||
|
|
||||||
|
const String kOptionShowMobileAction = "showMobileActions";
|
||||||
|
|
||||||
const String kUrlActionClose = "close";
|
const String kUrlActionClose = "close";
|
||||||
|
|
||||||
const String kTabLabelHomePage = "Home";
|
const String kTabLabelHomePage = "Home";
|
||||||
|
@ -134,6 +134,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
|
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
|
||||||
if (!isWeb) bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
|
if (!isWeb) bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
|
||||||
_ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
|
_ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
|
||||||
|
_ffi.dialogManager.loadMobileActionsOverlayVisible();
|
||||||
// Session option should be set after models.dart/FFI.start
|
// Session option should be set after models.dart/FFI.start
|
||||||
_showRemoteCursor.value = bind.sessionGetToggleOptionSync(
|
_showRemoteCursor.value = bind.sessionGetToggleOptionSync(
|
||||||
sessionId: sessionId, arg: 'show-remote-cursor');
|
sessionId: sessionId, arg: 'show-remote-cursor');
|
||||||
@ -322,13 +323,6 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
if (!_ffi.ffiModel.isPeerAndroid) {
|
if (!_ffi.ffiModel.isPeerAndroid) {
|
||||||
return Offstage();
|
return Offstage();
|
||||||
} else {
|
} else {
|
||||||
if (_ffi.connType == ConnType.defaultConn &&
|
|
||||||
_ffi.ffiModel.permissions['keyboard'] != false) {
|
|
||||||
Timer(
|
|
||||||
Duration(milliseconds: 10),
|
|
||||||
() => _ffi.dialogManager
|
|
||||||
.mobileActionsOverlayVisible.value = true);
|
|
||||||
}
|
|
||||||
return Obx(() => Offstage(
|
return Obx(() => Offstage(
|
||||||
offstage: _ffi.dialogManager
|
offstage: _ffi.dialogManager
|
||||||
.mobileActionsOverlayVisible.isFalse,
|
.mobileActionsOverlayVisible.isFalse,
|
||||||
|
@ -579,8 +579,8 @@ class _MobileActionMenu extends StatelessWidget {
|
|||||||
return Obx(() => _IconMenuButton(
|
return Obx(() => _IconMenuButton(
|
||||||
assetName: 'assets/actions_mobile.svg',
|
assetName: 'assets/actions_mobile.svg',
|
||||||
tooltip: 'Mobile Actions',
|
tooltip: 'Mobile Actions',
|
||||||
onPressed: () =>
|
onPressed: () => ffi.dialogManager.setMobileActionsOverlayVisible(
|
||||||
ffi.dialogManager.mobileActionsOverlayVisible.toggle(),
|
!ffi.dialogManager.mobileActionsOverlayVisible.value),
|
||||||
color: ffi.dialogManager.mobileActionsOverlayVisible.isTrue
|
color: ffi.dialogManager.mobileActionsOverlayVisible.isTrue
|
||||||
? _ToolbarTheme.blueColor
|
? _ToolbarTheme.blueColor
|
||||||
: _ToolbarTheme.inactiveColor,
|
: _ToolbarTheme.inactiveColor,
|
||||||
|
@ -6,6 +6,7 @@ import 'package:bot_toast/bot_toast.dart';
|
|||||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hbb/common/widgets/overlay.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/install_page.dart';
|
import 'package:flutter_hbb/desktop/pages/install_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/server_page.dart';
|
import 'package:flutter_hbb/desktop/pages/server_page.dart';
|
||||||
@ -156,6 +157,7 @@ void runMobileApp() async {
|
|||||||
await initEnv(kAppTypeMain);
|
await initEnv(kAppTypeMain);
|
||||||
if (isAndroid) androidChannelInit();
|
if (isAndroid) androidChannelInit();
|
||||||
if (isAndroid) platformFFI.syncAndroidServiceAppDirConfigPath();
|
if (isAndroid) platformFFI.syncAndroidServiceAppDirConfigPath();
|
||||||
|
draggablePositions.load();
|
||||||
await Future.wait([gFFI.abModel.loadCache(), gFFI.groupModel.loadCache()]);
|
await Future.wait([gFFI.abModel.loadCache(), gFFI.groupModel.loadCache()]);
|
||||||
gFFI.userModel.refreshCurrentUser();
|
gFFI.userModel.refreshCurrentUser();
|
||||||
runApp(App());
|
runApp(App());
|
||||||
@ -176,6 +178,7 @@ void runMultiWindow(
|
|||||||
late Widget widget;
|
late Widget widget;
|
||||||
switch (appType) {
|
switch (appType) {
|
||||||
case kAppTypeDesktopRemote:
|
case kAppTypeDesktopRemote:
|
||||||
|
draggablePositions.load();
|
||||||
widget = DesktopRemoteScreen(
|
widget = DesktopRemoteScreen(
|
||||||
params: argument,
|
params: argument,
|
||||||
);
|
);
|
||||||
|
@ -82,13 +82,14 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
.changeCurrentKey(MessageKey(widget.id, ChatModel.clientModeID));
|
.changeCurrentKey(MessageKey(widget.id, ChatModel.clientModeID));
|
||||||
gFFI.chatModel.voiceCallStatus.value = VoiceCallStatus.notStarted;
|
gFFI.chatModel.voiceCallStatus.value = VoiceCallStatus.notStarted;
|
||||||
_blockableOverlayState.applyFfi(gFFI);
|
_blockableOverlayState.applyFfi(gFFI);
|
||||||
|
gFFI.dialogManager.loadMobileActionsOverlayVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
// https://github.com/flutter/flutter/issues/64935
|
// https://github.com/flutter/flutter/issues/64935
|
||||||
super.dispose();
|
super.dispose();
|
||||||
gFFI.dialogManager.hideMobileActionsOverlay();
|
gFFI.dialogManager.hideMobileActionsOverlay(store: false);
|
||||||
gFFI.inputModel.listenToMouse(false);
|
gFFI.inputModel.listenToMouse(false);
|
||||||
gFFI.imageModel.disposeImage();
|
gFFI.imageModel.disposeImage();
|
||||||
gFFI.cursorModel.disposeImages();
|
gFFI.cursorModel.disposeImages();
|
||||||
|
@ -917,10 +917,12 @@ class FfiModel with ChangeNotifier {
|
|||||||
if (parent.target?.connType == ConnType.defaultConn &&
|
if (parent.target?.connType == ConnType.defaultConn &&
|
||||||
parent.target != null &&
|
parent.target != null &&
|
||||||
parent.target!.ffiModel.permissions['keyboard'] != false) {
|
parent.target!.ffiModel.permissions['keyboard'] != false) {
|
||||||
Timer(
|
Timer(Duration(milliseconds: delayMSecs), () {
|
||||||
Duration(milliseconds: delayMSecs),
|
if (parent.target!.dialogManager.mobileActionsOverlayVisible.isTrue) {
|
||||||
() => parent.target!.dialogManager
|
parent.target!.dialogManager
|
||||||
.showMobileActionsOverlay(ffi: parent.target!));
|
.showMobileActionsOverlay(ffi: parent.target!);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1587,10 +1589,13 @@ class CanvasModel with ChangeNotifier {
|
|||||||
// (focalPoint.dx - _x_1) / s1 + displayOriginX = (focalPoint.dx - _x_2) / s2 + displayOriginX
|
// (focalPoint.dx - _x_1) / s1 + displayOriginX = (focalPoint.dx - _x_2) / s2 + displayOriginX
|
||||||
// _x_2 = focalPoint.dx - (focalPoint.dx - _x_1) / s1 * s2
|
// _x_2 = focalPoint.dx - (focalPoint.dx - _x_1) / s1 * s2
|
||||||
_x = focalPoint.dx - (focalPoint.dx - _x) / s * _scale;
|
_x = focalPoint.dx - (focalPoint.dx - _x) / s * _scale;
|
||||||
final adjustForKeyboard = parent.target?.cursorModel.adjustForKeyboard() ?? 0.0;
|
final adjustForKeyboard =
|
||||||
|
parent.target?.cursorModel.adjustForKeyboard() ?? 0.0;
|
||||||
// (focalPoint.dy - _y_1 + adjust) / s1 + displayOriginY = (focalPoint.dy - _y_2 + adjust) / s2 + displayOriginY
|
// (focalPoint.dy - _y_1 + adjust) / s1 + displayOriginY = (focalPoint.dy - _y_2 + adjust) / s2 + displayOriginY
|
||||||
// _y_2 = focalPoint.dy + adjust - (focalPoint.dy - _y_1 + adjust) / s1 * s2
|
// _y_2 = focalPoint.dy + adjust - (focalPoint.dy - _y_1 + adjust) / s1 * s2
|
||||||
_y = focalPoint.dy + adjustForKeyboard - (focalPoint.dy - _y + adjustForKeyboard) / s * _scale;
|
_y = focalPoint.dy +
|
||||||
|
adjustForKeyboard -
|
||||||
|
(focalPoint.dy - _y + adjustForKeyboard) / s * _scale;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user