refact, peer card menu, open in tabs or windows

Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
dignow 2023-08-08 12:12:35 +08:00
parent 6b375cb0a3
commit ac88f55f25
41 changed files with 187 additions and 100 deletions

View File

@ -1240,7 +1240,7 @@ bool option2bool(String option, String value) {
option == "stop-service" || option == "stop-service" ||
option == "direct-server" || option == "direct-server" ||
option == "stop-rendezvous-service" || option == "stop-rendezvous-service" ||
option == "force-always-relay") { option == kOptionForceAlwaysRelay) {
res = value == "Y"; res = value == "Y";
} else { } else {
assert(false); assert(false);
@ -1257,7 +1257,7 @@ String bool2option(String option, bool b) {
option == "stop-service" || option == "stop-service" ||
option == "direct-server" || option == "direct-server" ||
option == "stop-rendezvous-service" || option == "stop-rendezvous-service" ||
option == "force-always-relay") { option == kOptionForceAlwaysRelay) {
res = b ? 'Y' : ''; res = b ? 'Y' : '';
} else { } else {
assert(false); assert(false);
@ -1288,6 +1288,14 @@ bool mainGetLocalBoolOptionSync(String key) {
return option2bool(key, bind.mainGetLocalOption(key: key)); return option2bool(key, bind.mainGetLocalOption(key: key));
} }
bool mainGetPeerBoolOptionSync(String id, String key) {
return option2bool(key, bind.mainGetPeerOptionSync(id: id, key: key));
}
mainSetPeerBoolOptionSync(String id, String key, bool v) {
bind.mainSetPeerOptionSync(id: id, key: key, value: bool2option(key, v));
}
Future<bool> matchPeer(String searchText, Peer peer) async { Future<bool> matchPeer(String searchText, Peer peer) async {
if (searchText.isEmpty) { if (searchText.isEmpty) {
return true; return true;
@ -1545,7 +1553,9 @@ Future<bool> restoreWindowPosition(WindowType type,
debugPrint("no window position saved, ignoring position restoration"); debugPrint("no window position saved, ignoring position restoration");
return false; return false;
} }
if (type == WindowType.RemoteDesktop && !isRemotePeerPos && windowId != null) { if (type == WindowType.RemoteDesktop &&
!isRemotePeerPos &&
windowId != null) {
if (lpos.offsetWidth != null) { if (lpos.offsetWidth != null) {
lpos.offsetWidth = lpos.offsetWidth! + windowId * 20; lpos.offsetWidth = lpos.offsetWidth! + windowId * 20;
} }
@ -1801,14 +1811,13 @@ connectMainDesktop(
required bool isTcpTunneling, required bool isTcpTunneling,
required bool isRDP, required bool isRDP,
bool? forceRelay, bool? forceRelay,
bool forceSeparateWindow = false,
}) async { }) async {
if (isFileTransfer) { if (isFileTransfer) {
await rustDeskWinManager.newFileTransfer(id, forceRelay: forceRelay); await rustDeskWinManager.newFileTransfer(id, forceRelay: forceRelay);
} else if (isTcpTunneling || isRDP) { } else if (isTcpTunneling || isRDP) {
await rustDeskWinManager.newPortForward(id, isRDP, forceRelay: forceRelay); await rustDeskWinManager.newPortForward(id, isRDP, forceRelay: forceRelay);
} else { } else {
await rustDeskWinManager.newRemoteDesktop(id, forceRelay: forceRelay, forceSeparateWindow: forceSeparateWindow); await rustDeskWinManager.newRemoteDesktop(id, forceRelay: forceRelay);
} }
} }
@ -1822,7 +1831,6 @@ connect(
bool isFileTransfer = false, bool isFileTransfer = false,
bool isTcpTunneling = false, bool isTcpTunneling = false,
bool isRDP = false, bool isRDP = false,
bool forceSeparateWindow = false,
}) async { }) async {
if (id == '') return; if (id == '') return;
id = id.replaceAll(' ', ''); id = id.replaceAll(' ', '');
@ -1840,7 +1848,6 @@ connect(
isTcpTunneling: isTcpTunneling, isTcpTunneling: isTcpTunneling,
isRDP: isRDP, isRDP: isRDP,
forceRelay: forceRelay, forceRelay: forceRelay,
forceSeparateWindow: forceSeparateWindow,
); );
} else { } else {
await rustDeskWinManager.call(WindowType.Main, kWindowConnect, { await rustDeskWinManager.call(WindowType.Main, kWindowConnect, {
@ -1849,7 +1856,6 @@ connect(
'isTcpTunneling': isTcpTunneling, 'isTcpTunneling': isTcpTunneling,
'isRDP': isRDP, 'isRDP': isRDP,
'forceRelay': forceRelay, 'forceRelay': forceRelay,
'forceSeparateWindow': forceSeparateWindow,
}); });
} }
} else { } else {

View File

@ -404,7 +404,6 @@ abstract class BasePeerCard extends StatelessWidget {
bool isFileTransfer = false, bool isFileTransfer = false,
bool isTcpTunneling = false, bool isTcpTunneling = false,
bool isRDP = false, bool isRDP = false,
bool forceSeparateWindow = false,
}) { }) {
return MenuEntryButton<String>( return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text( childBuilder: (TextStyle? style) => Text(
@ -418,7 +417,6 @@ abstract class BasePeerCard extends StatelessWidget {
isFileTransfer: isFileTransfer, isFileTransfer: isFileTransfer,
isTcpTunneling: isTcpTunneling, isTcpTunneling: isTcpTunneling,
isRDP: isRDP, isRDP: isRDP,
forceSeparateWindow: forceSeparateWindow,
); );
}, },
padding: menuPadding, padding: menuPadding,
@ -427,25 +425,13 @@ abstract class BasePeerCard extends StatelessWidget {
} }
@protected @protected
List<MenuEntryBase<String>> _connectActions(BuildContext context, Peer peer) { MenuEntryBase<String> _connectAction(BuildContext context, Peer peer) {
final actions = [_connectAction(context, peer, false)];
if (!mainGetLocalBoolOptionSync(kOptionSeparateRemoteWindow)) {
actions.add(_connectAction(context, peer, true));
}
return actions;
}
@protected
MenuEntryBase<String> _connectAction(
BuildContext context, Peer peer, bool forceSeparateWindow) {
return _connectCommonAction( return _connectCommonAction(
context, context,
peer.id, peer.id,
(peer.alias.isEmpty (peer.alias.isEmpty
? translate('Connect') ? translate('Connect')
: '${translate('Connect')} ${peer.id}') + : '${translate('Connect')} ${peer.id}'),
(forceSeparateWindow ? ' (${translate('separate window')})' : ''),
forceSeparateWindow: forceSeparateWindow,
); );
} }
@ -538,15 +524,40 @@ abstract class BasePeerCard extends StatelessWidget {
); );
} }
Future<MenuEntryBase<String>> _openNewConnInAction(
String id, String label, String key) async {
return MenuEntrySwitch<String>(
switchType: SwitchType.scheckbox,
text: translate(label),
getter: () async => mainGetPeerBoolOptionSync(id, key),
setter: (bool v) async {
await bind.mainSetPeerOption(
id: id, key: key, value: bool2option(key, v));
},
padding: menuPadding,
dismissOnClicked: true,
);
}
_openInTabsAction(String id) async =>
await _openNewConnInAction(id, 'Open in Tabs', kOptionOpenInTabs);
_openInWindowsAction(String id) async =>
await _openNewConnInAction(id, 'Open in windows', kOptionOpenInWindows);
_openNewConnInOptAction(String id) async =>
mainGetLocalBoolOptionSync(kOptionOpenNewConnInTabs)
? await _openInWindowsAction(id)
: await _openInTabsAction(id);
@protected @protected
Future<bool> _isForceAlwaysRelay(String id) async { Future<bool> _isForceAlwaysRelay(String id) async {
return (await bind.mainGetPeerOption(id: id, key: 'force-always-relay')) return (await bind.mainGetPeerOption(id: id, key: kOptionForceAlwaysRelay))
.isNotEmpty; .isNotEmpty;
} }
@protected @protected
Future<MenuEntryBase<String>> _forceAlwaysRelayAction(String id) async { Future<MenuEntryBase<String>> _forceAlwaysRelayAction(String id) async {
const option = 'force-always-relay';
return MenuEntrySwitch<String>( return MenuEntrySwitch<String>(
switchType: SwitchType.scheckbox, switchType: SwitchType.scheckbox,
text: translate('Always connect via relay'), text: translate('Always connect via relay'),
@ -555,7 +566,9 @@ abstract class BasePeerCard extends StatelessWidget {
}, },
setter: (bool v) async { setter: (bool v) async {
await bind.mainSetPeerOption( await bind.mainSetPeerOption(
id: id, key: option, value: bool2option(option, v)); id: id,
key: kOptionForceAlwaysRelay,
value: bool2option(kOptionForceAlwaysRelay, v));
}, },
padding: menuPadding, padding: menuPadding,
dismissOnClicked: true, dismissOnClicked: true,
@ -813,7 +826,7 @@ class RecentPeerCard extends BasePeerCard {
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
BuildContext context) async { BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [ final List<MenuEntryBase<String>> menuItems = [
..._connectActions(context, peer), _connectAction(context, peer),
_transferFileAction(context, peer.id), _transferFileAction(context, peer.id),
]; ];
@ -822,6 +835,7 @@ class RecentPeerCard extends BasePeerCard {
if (isDesktop && peer.platform != 'Android') { if (isDesktop && peer.platform != 'Android') {
menuItems.add(_tcpTunnelingAction(context, peer.id)); menuItems.add(_tcpTunnelingAction(context, peer.id));
} }
menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (peer.platform == 'Windows') { if (peer.platform == 'Windows') {
menuItems.add(_rdpAction(context, peer.id)); menuItems.add(_rdpAction(context, peer.id));
@ -869,12 +883,13 @@ class FavoritePeerCard extends BasePeerCard {
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
BuildContext context) async { BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [ final List<MenuEntryBase<String>> menuItems = [
..._connectActions(context, peer), _connectAction(context, peer),
_transferFileAction(context, peer.id), _transferFileAction(context, peer.id),
]; ];
if (isDesktop && peer.platform != 'Android') { if (isDesktop && peer.platform != 'Android') {
menuItems.add(_tcpTunnelingAction(context, peer.id)); menuItems.add(_tcpTunnelingAction(context, peer.id));
} }
menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (peer.platform == 'Windows') { if (peer.platform == 'Windows') {
menuItems.add(_rdpAction(context, peer.id)); menuItems.add(_rdpAction(context, peer.id));
@ -919,7 +934,7 @@ class DiscoveredPeerCard extends BasePeerCard {
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
BuildContext context) async { BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [ final List<MenuEntryBase<String>> menuItems = [
..._connectActions(context, peer), _connectAction(context, peer),
_transferFileAction(context, peer.id), _transferFileAction(context, peer.id),
]; ];
@ -928,6 +943,7 @@ class DiscoveredPeerCard extends BasePeerCard {
if (isDesktop && peer.platform != 'Android') { if (isDesktop && peer.platform != 'Android') {
menuItems.add(_tcpTunnelingAction(context, peer.id)); menuItems.add(_tcpTunnelingAction(context, peer.id));
} }
menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (peer.platform == 'Windows') { if (peer.platform == 'Windows') {
menuItems.add(_rdpAction(context, peer.id)); menuItems.add(_rdpAction(context, peer.id));
@ -971,12 +987,13 @@ class AddressBookPeerCard extends BasePeerCard {
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
BuildContext context) async { BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [ final List<MenuEntryBase<String>> menuItems = [
..._connectActions(context, peer), _connectAction(context, peer),
_transferFileAction(context, peer.id), _transferFileAction(context, peer.id),
]; ];
if (isDesktop && peer.platform != 'Android') { if (isDesktop && peer.platform != 'Android') {
menuItems.add(_tcpTunnelingAction(context, peer.id)); menuItems.add(_tcpTunnelingAction(context, peer.id));
} }
menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (peer.platform == 'Windows') { if (peer.platform == 'Windows') {
menuItems.add(_rdpAction(context, peer.id)); menuItems.add(_rdpAction(context, peer.id));
@ -1033,12 +1050,13 @@ class MyGroupPeerCard extends BasePeerCard {
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
BuildContext context) async { BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [ final List<MenuEntryBase<String>> menuItems = [
..._connectActions(context, peer), _connectAction(context, peer),
_transferFileAction(context, peer.id), _transferFileAction(context, peer.id),
]; ];
if (isDesktop && peer.platform != 'Android') { if (isDesktop && peer.platform != 'Android') {
menuItems.add(_tcpTunnelingAction(context, peer.id)); menuItems.add(_tcpTunnelingAction(context, peer.id));
} }
menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (peer.platform == 'Windows') { if (peer.platform == 'Windows') {
menuItems.add(_rdpAction(context, peer.id)); menuItems.add(_rdpAction(context, peer.id));

View File

@ -22,8 +22,6 @@ const String kAppTypeDesktopRemote = "remote";
const String kAppTypeDesktopFileTransfer = "file transfer"; const String kAppTypeDesktopFileTransfer = "file transfer";
const String kAppTypeDesktopPortForward = "port forward"; const String kAppTypeDesktopPortForward = "port forward";
const bool kCloseMultiWindowByHide = true;
const String kWindowMainWindowOnTop = "main_window_on_top"; const String kWindowMainWindowOnTop = "main_window_on_top";
const String kWindowGetWindowInfo = "get_window_info"; const String kWindowGetWindowInfo = "get_window_info";
const String kWindowDisableGrabKeyboard = "disable_grab_keyboard"; const String kWindowDisableGrabKeyboard = "disable_grab_keyboard";
@ -42,7 +40,10 @@ 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 kOptionSeparateRemoteWindow = "allow-separate-remote-window"; const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs";
const String kOptionOpenInTabs = "allow-open-in-tabs";
const String kOptionOpenInWindows = "allow-open-in-windows";
const String kOptionForceAlwaysRelay = "force-always-relay";
const String kUniLinksPrefix = "rustdesk://"; const String kUniLinksPrefix = "rustdesk://";
const String kUrlActionClose = "close"; const String kUrlActionClose = "close";

View File

@ -554,13 +554,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
} else if (call.method == kWindowEventShow) { } else if (call.method == kWindowEventShow) {
await rustDeskWinManager.registerActiveWindow(call.arguments["id"]); await rustDeskWinManager.registerActiveWindow(call.arguments["id"]);
} else if (call.method == kWindowEventHide) { } else if (call.method == kWindowEventHide) {
final wId = call.arguments['id']; await rustDeskWinManager.unregisterActiveWindow(call.arguments['id']);
final isSeparateWindowEnabled =
mainGetLocalBoolOptionSync(kOptionSeparateRemoteWindow);
if (isSeparateWindowEnabled && !kCloseMultiWindowByHide) {
await rustDeskWinManager.destroyWindow(wId);
}
await rustDeskWinManager.unregisterActiveWindow(wId);
} else if (call.method == kWindowConnect) { } else if (call.method == kWindowConnect) {
await connectMainDesktop( await connectMainDesktop(
call.arguments['id'], call.arguments['id'],
@ -568,7 +562,6 @@ class _DesktopHomePageState extends State<DesktopHomePage>
isTcpTunneling: call.arguments['isTcpTunneling'], isTcpTunneling: call.arguments['isTcpTunneling'],
isRDP: call.arguments['isRDP'], isRDP: call.arguments['isRDP'],
forceRelay: call.arguments['forceRelay'], forceRelay: call.arguments['forceRelay'],
forceSeparateWindow: call.arguments['forceSeparateWindow'],
); );
} else if (call.method == kWindowEventMoveTabToNewWindow) { } else if (call.method == kWindowEventMoveTabToNewWindow) {
final args = call.arguments.split(','); final args = call.arguments.split(',');

View File

@ -319,8 +319,8 @@ class _GeneralState extends State<_General> {
_OptionCheckBox(context, 'Adaptive bitrate', 'enable-abr'), _OptionCheckBox(context, 'Adaptive bitrate', 'enable-abr'),
_OptionCheckBox( _OptionCheckBox(
context, context,
'Separate remote windows', 'Open new connections in tabs',
kOptionSeparateRemoteWindow, kOptionOpenNewConnInTabs,
isServer: false, isServer: false,
), ),
]; ];

View File

@ -116,7 +116,7 @@ class _RemotePageState extends State<RemotePage>
Wakelock.enable(); Wakelock.enable();
} }
// Register texture. // Register texture.
if (mainGetLocalBoolOptionSync(kOptionSeparateRemoteWindow)) { if (mainGetLocalBoolOptionSync(kOptionOpenNewConnInTabs)) {
_renderTexture = renderTexture; _renderTexture = renderTexture;
} else { } else {
_renderTexture = RenderTexture(); _renderTexture = RenderTexture();

View File

@ -81,19 +81,24 @@ class RustDeskMultiWindowManager {
} }
_newSession( _newSession(
bool separateWindow, bool openInTabs,
WindowType type, WindowType type,
String methodName, String methodName,
String remoteId, String remoteId,
List<int> windows, List<int> windows,
String msg, String msg,
) async { ) async {
if (separateWindow) { if (openInTabs) {
if (kCloseMultiWindowByHide && _inactiveWindows.isNotEmpty) { if (windows.isEmpty) {
await newSessionWindow(type, remoteId, msg, windows);
} else {
call(type, methodName, msg);
}
} else {
if (_inactiveWindows.isNotEmpty) {
for (final windowId in windows) { for (final windowId in windows) {
if (_inactiveWindows.contains(windowId)) { if (_inactiveWindows.contains(windowId)) {
await DesktopMultiWindow.invokeMethod( await DesktopMultiWindow.invokeMethod(windowId, methodName, msg);
windowId, methodName, msg);
WindowController.fromWindowId(windowId).show(); WindowController.fromWindowId(windowId).show();
registerActiveWindow(windowId); registerActiveWindow(windowId);
return; return;
@ -101,12 +106,6 @@ class RustDeskMultiWindowManager {
} }
} }
await newSessionWindow(type, remoteId, msg, windows); await newSessionWindow(type, remoteId, msg, windows);
} else {
if (windows.isEmpty) {
await newSessionWindow(type, remoteId, msg, windows);
} else {
call(type, methodName, msg);
}
} }
} }
@ -119,7 +118,6 @@ class RustDeskMultiWindowManager {
bool? forceRelay, bool? forceRelay,
String? switchUuid, String? switchUuid,
bool? isRDP, bool? isRDP,
bool forceSeparateWindow = false,
}) async { }) async {
var params = { var params = {
"type": type.index, "type": type.index,
@ -136,11 +134,16 @@ class RustDeskMultiWindowManager {
final msg = jsonEncode(params); final msg = jsonEncode(params);
// separate window for file transfer is not supported // separate window for file transfer is not supported
bool separateWindow = forceSeparateWindow || bool openInTabs = false;
(type != WindowType.FileTransfer && if (type == WindowType.RemoteDesktop) {
mainGetLocalBoolOptionSync(kOptionSeparateRemoteWindow)); if (mainGetLocalBoolOptionSync(kOptionOpenNewConnInTabs)) {
openInTabs = !mainGetPeerBoolOptionSync(remoteId, kOptionOpenInWindows);
} else {
openInTabs = mainGetPeerBoolOptionSync(remoteId, kOptionOpenInTabs);
}
}
if (windows.length > 1 || separateWindow) { if (windows.length > 1 || !openInTabs) {
for (final windowId in windows) { for (final windowId in windows) {
if (await DesktopMultiWindow.invokeMethod( if (await DesktopMultiWindow.invokeMethod(
windowId, kWindowEventActiveSession, remoteId)) { windowId, kWindowEventActiveSession, remoteId)) {
@ -149,7 +152,7 @@ class RustDeskMultiWindowManager {
} }
} }
await _newSession(separateWindow, type, methodName, remoteId, windows, msg); await _newSession(openInTabs, type, methodName, remoteId, windows, msg);
} }
Future<dynamic> newRemoteDesktop( Future<dynamic> newRemoteDesktop(
@ -157,7 +160,6 @@ class RustDeskMultiWindowManager {
String? password, String? password,
String? switchUuid, String? switchUuid,
bool? forceRelay, bool? forceRelay,
bool forceSeparateWindow = false,
}) async { }) async {
return await newSession( return await newSession(
WindowType.RemoteDesktop, WindowType.RemoteDesktop,
@ -167,7 +169,6 @@ class RustDeskMultiWindowManager {
password: password, password: password,
forceRelay: forceRelay, forceRelay: forceRelay,
switchUuid: switchUuid, switchUuid: switchUuid,
forceSeparateWindow: forceSeparateWindow,
); );
} }

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "管理的设备数已达到最大值"), ("exceed_max_devices", "管理的设备数已达到最大值"),
("Sync with recent sessions", "同步最近会话"), ("Sync with recent sessions", "同步最近会话"),
("Sort tags", "对标签进行排序"), ("Sort tags", "对标签进行排序"),
("Separate remote windows", "使用独立远程窗口"), ("Open new connections in tabs", "在选项卡中打开新连接"),
("Open in tabs", "在选项卡中打开"),
("Open in windows", "在新窗口中打开"),
("separate window", "独立窗口"), ("separate window", "独立窗口"),
("Move tab to new window", "将标签页移至新窗口"), ("Move tab to new window", "将标签页移至新窗口"),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "Sie haben die maximale Anzahl der verwalteten Geräte erreicht."), ("exceed_max_devices", "Sie haben die maximale Anzahl der verwalteten Geräte erreicht."),
("Sync with recent sessions", "Synchronisierung mit den letzten Sitzungen"), ("Sync with recent sessions", "Synchronisierung mit den letzten Sitzungen"),
("Sort tags", "Tags sortieren"), ("Sort tags", "Tags sortieren"),
("Separate remote windows", "Separate entfernte Fenster"), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", "Separates Fenster"), ("separate window", "Separates Fenster"),
("Move tab to new window", "Tab in neues Fenster verschieben"), ("Move tab to new window", "Tab in neues Fenster verschieben"),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "Has alcanzado el máximo número de dispositivos administrados."), ("exceed_max_devices", "Has alcanzado el máximo número de dispositivos administrados."),
("Sync with recent sessions", "Sincronizar con sesiones recientes"), ("Sync with recent sessions", "Sincronizar con sesiones recientes"),
("Sort tags", "Ordenar etiquetas"), ("Sort tags", "Ordenar etiquetas"),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "Hai raggiunto il numero massimo di dispositivi gestibili."), ("exceed_max_devices", "Hai raggiunto il numero massimo di dispositivi gestibili."),
("Sync with recent sessions", "Sincronizza con le sessioni recenti"), ("Sync with recent sessions", "Sincronizza con le sessioni recenti"),
("Sort tags", "Ordina etichette"), ("Sort tags", "Ordina etichette"),
("Separate remote windows", "Separa finestre remote"), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", "Separa finestra"), ("separate window", "Separa finestra"),
("Move tab to new window", "Sposta scheda nella finestra successiva"), ("Move tab to new window", "Sposta scheda nella finestra successiva"),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "Het maximum aantal gecontroleerde apparaten is bereikt."), ("exceed_max_devices", "Het maximum aantal gecontroleerde apparaten is bereikt."),
("Sync with recent sessions", "Recente sessies synchroniseren"), ("Sync with recent sessions", "Recente sessies synchroniseren"),
("Sort tags", "Labels sorteren"), ("Sort tags", "Labels sorteren"),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "Przekroczona maks. liczba urządzeń"), ("exceed_max_devices", "Przekroczona maks. liczba urządzeń"),
("Sync with recent sessions", "Synchronizacja z ostatnimi sesjami"), ("Sync with recent sessions", "Synchronizacja z ostatnimi sesjami"),
("Sort tags", "Znaczniki sortowania"), ("Sort tags", "Znaczniki sortowania"),
("Separate remote windows", "Oddzielne zdalne okna"), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", "oddzielne okno"), ("separate window", "oddzielne okno"),
("Move tab to new window", "Przenieś zakładkę do nowego okna"), ("Move tab to new window", "Przenieś zakładkę do nowego okna"),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", "Достигнуто максимальне количество управляемых устройств."), ("exceed_max_devices", "Достигнуто максимальне количество управляемых устройств."),
("Sync with recent sessions", "Синхронизация последних сессий"), ("Sync with recent sessions", "Синхронизация последних сессий"),
("Sort tags", "Сортировка меток"), ("Sort tags", "Сортировка меток"),
("Separate remote windows", "Отдельные удалённые окна"), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", "отдельное окно"), ("separate window", "отдельное окно"),
("Move tab to new window", "Переместить вкладку в отдельное окно"), ("Move tab to new window", "Переместить вкладку в отдельное окно"),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();

View File

@ -524,7 +524,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("exceed_max_devices", ""), ("exceed_max_devices", ""),
("Sync with recent sessions", ""), ("Sync with recent sessions", ""),
("Sort tags", ""), ("Sort tags", ""),
("Separate remote windows", ""), ("Open new connections in tabs", ""),
("Open in tabs", ""),
("Open in windows", ""),
("separate window", ""), ("separate window", ""),
("Move tab to new window", ""), ("Move tab to new window", ""),
].iter().cloned().collect(); ].iter().cloned().collect();