refact, tab to window, flutter data, init commit
Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
parent
5112398ad3
commit
e205577145
@ -5,6 +5,7 @@ import 'package:flutter_hbb/common.dart';
|
|||||||
import 'package:flutter_hbb/models/state_model.dart';
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
|
|
||||||
const double kDesktopRemoteTabBarHeight = 28.0;
|
const double kDesktopRemoteTabBarHeight = 28.0;
|
||||||
|
const int kInvalidWindowId = -1;
|
||||||
const int kMainWindowId = 0;
|
const int kMainWindowId = 0;
|
||||||
|
|
||||||
const String kPeerPlatformWindows = "Windows";
|
const String kPeerPlatformWindows = "Windows";
|
||||||
@ -39,6 +40,7 @@ const String kWindowEventGetSessionIdList = "get_session_id_list";
|
|||||||
|
|
||||||
const String kWindowEventMoveTabToNewWindow = "move_tab_to_new_window";
|
const String kWindowEventMoveTabToNewWindow = "move_tab_to_new_window";
|
||||||
const String kWindowEventCloseForSeparateWindow = "close_for_separate_window";
|
const String kWindowEventCloseForSeparateWindow = "close_for_separate_window";
|
||||||
|
const String kWindowEventSendNewWindowData = "send_new_window_data";
|
||||||
|
|
||||||
const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs";
|
const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs";
|
||||||
const String kOptionOpenInTabs = "allow-open-in-tabs";
|
const String kOptionOpenInTabs = "allow-open-in-tabs";
|
||||||
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
import 'package:flutter_hbb/common/shared_state.dart';
|
import 'package:flutter_hbb/common/shared_state.dart';
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
|
import 'package:flutter_hbb/models/model.dart';
|
||||||
import 'package:flutter_hbb/models/state_model.dart';
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/remote_page.dart';
|
import 'package:flutter_hbb/desktop/pages/remote_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart';
|
import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart';
|
||||||
@ -148,9 +149,40 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
.toList()
|
.toList()
|
||||||
.join(';');
|
.join(';');
|
||||||
} else if (call.method == kWindowEventCloseForSeparateWindow) {
|
} else if (call.method == kWindowEventCloseForSeparateWindow) {
|
||||||
final peerId = call.arguments;
|
debugPrint('REMOVE ME ============================= ${call.arguments}');
|
||||||
|
final peerId = call.arguments['peerId'];
|
||||||
|
final newWindowId = call.arguments['newWindowId'];
|
||||||
|
late RemotePage page;
|
||||||
|
try {
|
||||||
|
page = tabController.state.value.tabs.firstWhere((tab) {
|
||||||
|
return tab.key == peerId;
|
||||||
|
}).page as RemotePage;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Failed to find tab for peerId $peerId');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final sendRes = await rustDeskWinManager.call(
|
||||||
|
newWindowId,
|
||||||
|
kWindowEventSendNewWindowData,
|
||||||
|
page.ffi.ffiModel.cachedPeerData) as bool;
|
||||||
|
if (!sendRes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Pass the required data to new window.
|
||||||
closeSessionOnDispose[peerId] = false;
|
closeSessionOnDispose[peerId] = false;
|
||||||
tabController.closeBy(peerId);
|
tabController.closeBy(peerId);
|
||||||
|
return true;
|
||||||
|
} else if (call.method == kWindowEventSendNewWindowData) {
|
||||||
|
if (peerId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tabController.state.value.tabs.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final page = tabController.state.value.tabs[0].page as RemotePage;
|
||||||
|
page.ffi.ffiModel
|
||||||
|
.handleCachedPeerData(call.arguments as CachedPeerData, peerId!);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
_update_remote_count();
|
_update_remote_count();
|
||||||
});
|
});
|
||||||
|
@ -41,7 +41,19 @@ final _waitForImageDialogShow = <UuidValue, bool>{};
|
|||||||
final _waitForFirstImage = <UuidValue, bool>{};
|
final _waitForFirstImage = <UuidValue, bool>{};
|
||||||
final _constSessionId = Uuid().v4obj();
|
final _constSessionId = Uuid().v4obj();
|
||||||
|
|
||||||
|
class CachedPeerData {
|
||||||
|
Map<String, dynamic> updatePrivacyMode = {};
|
||||||
|
Map<String, dynamic> peerInfo = {};
|
||||||
|
List<Map<String, dynamic>> cursorDataList = [];
|
||||||
|
Map<String, dynamic> lastCursorId = {};
|
||||||
|
bool secure = false;
|
||||||
|
bool direct = false;
|
||||||
|
|
||||||
|
CachedPeerData();
|
||||||
|
}
|
||||||
|
|
||||||
class FfiModel with ChangeNotifier {
|
class FfiModel with ChangeNotifier {
|
||||||
|
CachedPeerData cachedPeerData = CachedPeerData();
|
||||||
PeerInfo _pi = PeerInfo();
|
PeerInfo _pi = PeerInfo();
|
||||||
Display _display = Display();
|
Display _display = Display();
|
||||||
|
|
||||||
@ -117,6 +129,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setConnectionType(String peerId, bool secure, bool direct) {
|
setConnectionType(String peerId, bool secure, bool direct) {
|
||||||
|
cachedPeerData.secure = secure;
|
||||||
|
cachedPeerData.direct = direct;
|
||||||
_secure = secure;
|
_secure = secure;
|
||||||
_direct = direct;
|
_direct = direct;
|
||||||
try {
|
try {
|
||||||
@ -143,6 +157,22 @@ class FfiModel with ChangeNotifier {
|
|||||||
_permissions.clear();
|
_permissions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleCachedPeerData(CachedPeerData data, String peerId) async {
|
||||||
|
handleMsgBox({
|
||||||
|
'type': 'success',
|
||||||
|
'title': 'Successful',
|
||||||
|
'text': 'Connected, waiting for image...',
|
||||||
|
'link': '',
|
||||||
|
}, sessionId, peerId);
|
||||||
|
updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId);
|
||||||
|
setConnectionType(peerId, data.secure, data.direct);
|
||||||
|
handlePeerInfo(data.peerInfo, peerId);
|
||||||
|
for (var element in data.cursorDataList) {
|
||||||
|
handleCursorData(element);
|
||||||
|
}
|
||||||
|
handleCursorId(data.lastCursorId);
|
||||||
|
}
|
||||||
|
|
||||||
// todo: why called by two position
|
// todo: why called by two position
|
||||||
StreamEventHandler startEventListener(SessionID sessionId, String peerId) {
|
StreamEventHandler startEventListener(SessionID sessionId, String peerId) {
|
||||||
return (evt) async {
|
return (evt) async {
|
||||||
@ -159,9 +189,9 @@ class FfiModel with ChangeNotifier {
|
|||||||
} else if (name == 'switch_display') {
|
} else if (name == 'switch_display') {
|
||||||
handleSwitchDisplay(evt, sessionId, peerId);
|
handleSwitchDisplay(evt, sessionId, peerId);
|
||||||
} else if (name == 'cursor_data') {
|
} else if (name == 'cursor_data') {
|
||||||
await parent.target?.cursorModel.updateCursorData(evt);
|
await handleCursorData(evt);
|
||||||
} else if (name == 'cursor_id') {
|
} else if (name == 'cursor_id') {
|
||||||
await parent.target?.cursorModel.updateCursorId(evt);
|
await handleCursorId(evt);
|
||||||
} else if (name == 'cursor_position') {
|
} else if (name == 'cursor_position') {
|
||||||
await parent.target?.cursorModel.updateCursorPosition(evt, peerId);
|
await parent.target?.cursorModel.updateCursorPosition(evt, peerId);
|
||||||
} else if (name == 'clipboard') {
|
} else if (name == 'clipboard') {
|
||||||
@ -453,6 +483,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
|
|
||||||
/// Handle the peer info event based on [evt].
|
/// Handle the peer info event based on [evt].
|
||||||
handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
|
handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
|
||||||
|
cachedPeerData.peerInfo = evt;
|
||||||
|
|
||||||
// recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs)
|
// recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs)
|
||||||
bind.mainLoadRecentPeers();
|
bind.mainLoadRecentPeers();
|
||||||
|
|
||||||
@ -568,9 +600,20 @@ class FfiModel with ChangeNotifier {
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleCursorId(Map<String, dynamic> evt) async {
|
||||||
|
cachedPeerData.lastCursorId = evt;
|
||||||
|
await parent.target?.cursorModel.updateCursorId(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCursorData(Map<String, dynamic> evt) async {
|
||||||
|
cachedPeerData.cursorDataList.add(evt);
|
||||||
|
await parent.target?.cursorModel.updateCursorData(evt);
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle the peer info synchronization event based on [evt].
|
/// Handle the peer info synchronization event based on [evt].
|
||||||
handleSyncPeerInfo(Map<String, dynamic> evt, SessionID sessionId) async {
|
handleSyncPeerInfo(Map<String, dynamic> evt, SessionID sessionId) async {
|
||||||
if (evt['displays'] != null) {
|
if (evt['displays'] != null) {
|
||||||
|
cachedPeerData.peerInfo['displays'] = evt['displays'];
|
||||||
List<dynamic> displays = json.decode(evt['displays']);
|
List<dynamic> displays = json.decode(evt['displays']);
|
||||||
List<Display> newDisplays = [];
|
List<Display> newDisplays = [];
|
||||||
for (int i = 0; i < displays.length; ++i) {
|
for (int i = 0; i < displays.length; ++i) {
|
||||||
@ -1667,7 +1710,8 @@ class FFI {
|
|||||||
stream.listen((message) {
|
stream.listen((message) {
|
||||||
if (closed) return;
|
if (closed) return;
|
||||||
if (isSessionAdded && !isToNewWindowNotified.value) {
|
if (isSessionAdded && !isToNewWindowNotified.value) {
|
||||||
bind.sessionReadyToNewWindow(sessionId: sessionId);
|
// bind.sessionReadyToNewWindow(sessionId: sessionId);
|
||||||
|
bind.sessionRefresh(sessionId: sessionId);
|
||||||
isToNewWindowNotified.value = true;
|
isToNewWindowNotified.value = true;
|
||||||
}
|
}
|
||||||
() async {
|
() async {
|
||||||
|
@ -28,6 +28,13 @@ extension Index on int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MultiWindowCallResult {
|
||||||
|
int windowId;
|
||||||
|
dynamic result;
|
||||||
|
|
||||||
|
MultiWindowCallResult(this.windowId, this.result);
|
||||||
|
}
|
||||||
|
|
||||||
/// Window Manager
|
/// Window Manager
|
||||||
/// mainly use it in `Main Window`
|
/// mainly use it in `Main Window`
|
||||||
/// use it in sub window is not recommended
|
/// use it in sub window is not recommended
|
||||||
@ -49,7 +56,10 @@ class RustDeskMultiWindowManager {
|
|||||||
'id': peerId,
|
'id': peerId,
|
||||||
'session_id': sessionId,
|
'session_id': sessionId,
|
||||||
};
|
};
|
||||||
await _newSession(
|
// It's better to use the window id that returned by _newSession.
|
||||||
|
// Do not pass original window id to _newSession,
|
||||||
|
// as this function cann't promise the necessary data is passed to new window.
|
||||||
|
final multiWindowRes = await _newSession(
|
||||||
false,
|
false,
|
||||||
WindowType.RemoteDesktop,
|
WindowType.RemoteDesktop,
|
||||||
kWindowEventNewRemoteDesktop,
|
kWindowEventNewRemoteDesktop,
|
||||||
@ -57,17 +67,21 @@ class RustDeskMultiWindowManager {
|
|||||||
_remoteDesktopWindows,
|
_remoteDesktopWindows,
|
||||||
jsonEncode(params),
|
jsonEncode(params),
|
||||||
);
|
);
|
||||||
|
// kWindowEventCloseForSeparateWindow will not only close the tab, but also pass the required data to new window.
|
||||||
await DesktopMultiWindow.invokeMethod(
|
await DesktopMultiWindow.invokeMethod(
|
||||||
windowId, kWindowEventCloseForSeparateWindow, peerId);
|
windowId, kWindowEventCloseForSeparateWindow, {
|
||||||
|
'peerId': peerId,
|
||||||
|
'newWindowId': multiWindowRes.windowId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
newSessionWindow(
|
Future<int> newSessionWindow(
|
||||||
WindowType type, String remoteId, String msg, List<int> windows) async {
|
WindowType type, String remoteId, String msg, List<int> windows) async {
|
||||||
final windowController = await DesktopMultiWindow.createWindow(msg);
|
final windowController = await DesktopMultiWindow.createWindow(msg);
|
||||||
|
final windowId = windowController.windowId;
|
||||||
windowController
|
windowController
|
||||||
..setFrame(const Offset(0, 0) &
|
..setFrame(
|
||||||
Size(1280 + windowController.windowId * 20,
|
const Offset(0, 0) & Size(1280 + windowId * 20, 720 + windowId * 20))
|
||||||
720 + windowController.windowId * 20))
|
|
||||||
..center()
|
..center()
|
||||||
..setTitle(getWindowNameWithId(
|
..setTitle(getWindowNameWithId(
|
||||||
remoteId,
|
remoteId,
|
||||||
@ -76,11 +90,12 @@ class RustDeskMultiWindowManager {
|
|||||||
if (Platform.isMacOS) {
|
if (Platform.isMacOS) {
|
||||||
Future.microtask(() => windowController.show());
|
Future.microtask(() => windowController.show());
|
||||||
}
|
}
|
||||||
registerActiveWindow(windowController.windowId);
|
registerActiveWindow(windowId);
|
||||||
windows.add(windowController.windowId);
|
windows.add(windowId);
|
||||||
|
return windowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
_newSession(
|
Future<MultiWindowCallResult> _newSession(
|
||||||
bool openInTabs,
|
bool openInTabs,
|
||||||
WindowType type,
|
WindowType type,
|
||||||
String methodName,
|
String methodName,
|
||||||
@ -90,9 +105,10 @@ class RustDeskMultiWindowManager {
|
|||||||
) async {
|
) async {
|
||||||
if (openInTabs) {
|
if (openInTabs) {
|
||||||
if (windows.isEmpty) {
|
if (windows.isEmpty) {
|
||||||
await newSessionWindow(type, remoteId, msg, windows);
|
final windowId = await newSessionWindow(type, remoteId, msg, windows);
|
||||||
|
return MultiWindowCallResult(windowId, null);
|
||||||
} else {
|
} else {
|
||||||
call(type, methodName, msg);
|
return call(type, methodName, msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_inactiveWindows.isNotEmpty) {
|
if (_inactiveWindows.isNotEmpty) {
|
||||||
@ -103,15 +119,16 @@ class RustDeskMultiWindowManager {
|
|||||||
await DesktopMultiWindow.invokeMethod(windowId, methodName, msg);
|
await DesktopMultiWindow.invokeMethod(windowId, methodName, msg);
|
||||||
WindowController.fromWindowId(windowId).show();
|
WindowController.fromWindowId(windowId).show();
|
||||||
registerActiveWindow(windowId);
|
registerActiveWindow(windowId);
|
||||||
return;
|
return MultiWindowCallResult(windowId, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await newSessionWindow(type, remoteId, msg, windows);
|
final windowId = await newSessionWindow(type, remoteId, msg, windows);
|
||||||
|
return MultiWindowCallResult(windowId, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> newSession(
|
Future<MultiWindowCallResult> newSession(
|
||||||
WindowType type,
|
WindowType type,
|
||||||
String methodName,
|
String methodName,
|
||||||
String remoteId,
|
String remoteId,
|
||||||
@ -143,15 +160,15 @@ class RustDeskMultiWindowManager {
|
|||||||
for (final windowId in windows) {
|
for (final windowId in windows) {
|
||||||
if (await DesktopMultiWindow.invokeMethod(
|
if (await DesktopMultiWindow.invokeMethod(
|
||||||
windowId, kWindowEventActiveSession, remoteId)) {
|
windowId, kWindowEventActiveSession, remoteId)) {
|
||||||
return;
|
return MultiWindowCallResult(windowId, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await _newSession(openInTabs, type, methodName, remoteId, windows, msg);
|
return _newSession(openInTabs, type, methodName, remoteId, windows, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> newRemoteDesktop(
|
Future<MultiWindowCallResult> newRemoteDesktop(
|
||||||
String remoteId, {
|
String remoteId, {
|
||||||
String? password,
|
String? password,
|
||||||
String? switchUuid,
|
String? switchUuid,
|
||||||
@ -168,7 +185,7 @@ class RustDeskMultiWindowManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> newFileTransfer(String remoteId,
|
Future<MultiWindowCallResult> newFileTransfer(String remoteId,
|
||||||
{String? password, bool? forceRelay}) async {
|
{String? password, bool? forceRelay}) async {
|
||||||
return await newSession(
|
return await newSession(
|
||||||
WindowType.FileTransfer,
|
WindowType.FileTransfer,
|
||||||
@ -180,7 +197,7 @@ class RustDeskMultiWindowManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> newPortForward(String remoteId, bool isRDP,
|
Future<MultiWindowCallResult> newPortForward(String remoteId, bool isRDP,
|
||||||
{String? password, bool? forceRelay}) async {
|
{String? password, bool? forceRelay}) async {
|
||||||
return await newSession(
|
return await newSession(
|
||||||
WindowType.PortForward,
|
WindowType.PortForward,
|
||||||
@ -193,18 +210,22 @@ class RustDeskMultiWindowManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> call(WindowType type, String methodName, dynamic args) async {
|
Future<MultiWindowCallResult> call(
|
||||||
|
WindowType type, String methodName, dynamic args) async {
|
||||||
final wnds = _findWindowsByType(type);
|
final wnds = _findWindowsByType(type);
|
||||||
if (wnds.isEmpty) {
|
if (wnds.isEmpty) {
|
||||||
return;
|
return MultiWindowCallResult(kInvalidWindowId, null);
|
||||||
}
|
}
|
||||||
for (final windowId in wnds) {
|
for (final windowId in wnds) {
|
||||||
if (_activeWindows.contains(windowId)) {
|
if (_activeWindows.contains(windowId)) {
|
||||||
return await DesktopMultiWindow.invokeMethod(
|
final res =
|
||||||
windowId, methodName, args);
|
await DesktopMultiWindow.invokeMethod(windowId, methodName, args);
|
||||||
|
return MultiWindowCallResult(windowId, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await DesktopMultiWindow.invokeMethod(wnds[0], methodName, args);
|
final res =
|
||||||
|
await DesktopMultiWindow.invokeMethod(wnds[0], methodName, args);
|
||||||
|
return MultiWindowCallResult(wnds[0], res);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<int> _findWindowsByType(WindowType type) {
|
List<int> _findWindowsByType(WindowType type) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user