Merge pull request #3670 from NicKoehler/multi-display

Multi display in menu bar
This commit is contained in:
RustDesk 2023-03-16 01:47:53 +08:00 committed by GitHub
commit 1f6fc8b1a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 183 additions and 76 deletions

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="321.118 40.669 32 32" width="32pt" height="32pt"><g><path d=" M 321.118 40.669 L 353.118 40.669 L 353.118 72.669 L 321.118 72.669 L 321.118 40.669 Z " fill="none"/><path d=" M 344.588 47.817 L 329.648 47.817 C 327.572 47.817 325.887 49.504 325.887 51.581 L 325.887 61.757 C 325.887 63.834 327.572 65.521 329.648 65.521 L 344.588 65.521 C 346.664 65.521 348.35 63.834 348.35 61.757 L 348.35 51.581 C 348.35 49.504 346.664 47.817 344.588 47.817 L 344.588 47.817 L 344.588 47.817 Z " fill="rgb(0,0,0)"/></g></svg>

After

Width:  |  Height:  |  Size: 683 B

View File

@ -1318,6 +1318,7 @@ class _DisplayState extends State<_Display> {
Widget other(BuildContext context) {
return _Card(title: 'Other Default Options', children: [
otherRow('Show monitors in menu bar', 'show_monitors_menubar'),
otherRow('Show remote cursor', 'show_remote_cursor'),
otherRow('Zoom cursor', 'zoom-cursor'),
otherRow('Show quality monitor', 'show_quality_monitor'),

View File

@ -22,7 +22,7 @@ import '../../models/model.dart';
import '../../models/platform_model.dart';
import '../../common/shared_state.dart';
import '../../utils/image.dart';
import '../widgets/remote_menubar.dart';
import '../widgets/remote_toolbar.dart';
import '../widgets/kb_layout_type_chooser.dart';
bool _isCustomCursorInited = false;

View File

@ -9,7 +9,7 @@ import 'package:flutter_hbb/common/shared_state.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/desktop/pages/remote_page.dart';
import 'package:flutter_hbb/desktop/widgets/remote_menubar.dart';
import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart'
as mod_menu;

View File

@ -356,7 +356,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
return Align(
alignment: Alignment.topCenter,
child: Obx(() => show.value
? _buildMenubar(context)
? _buildToolbar(context)
: _buildDraggableShowHide(context)),
);
}
@ -384,30 +384,39 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
});
}
Widget _buildMenubar(BuildContext context) {
final List<Widget> menubarItems = [];
Widget _buildToolbar(BuildContext context) {
final List<Widget> toolbarItems = [];
if (!isWebDesktop) {
menubarItems.add(_PinMenu(state: widget.state));
menubarItems.add(
toolbarItems.add(_PinMenu(state: widget.state));
toolbarItems.add(
_FullscreenMenu(state: widget.state, setFullscreen: _setFullscreen));
menubarItems.add(_MobileActionMenu(ffi: widget.ffi));
toolbarItems.add(_MobileActionMenu(ffi: widget.ffi));
}
menubarItems.add(_MonitorMenu(id: widget.id, ffi: widget.ffi));
menubarItems
if (PrivacyModeState.find(widget.id).isFalse &&
stateGlobal.displaysCount.value > 1) {
toolbarItems.add(
bind.mainGetUserDefaultOption(key: 'show_monitors_menubar') == 'Y'
? _MultiMonitorMenu(id: widget.id, ffi: widget.ffi)
: _MonitorMenu(id: widget.id, ffi: widget.ffi),
);
}
toolbarItems
.add(_ControlMenu(id: widget.id, ffi: widget.ffi, state: widget.state));
menubarItems.add(_DisplayMenu(
toolbarItems.add(_DisplayMenu(
id: widget.id,
ffi: widget.ffi,
state: widget.state,
setFullscreen: _setFullscreen,
));
menubarItems.add(_KeyboardMenu(id: widget.id, ffi: widget.ffi));
toolbarItems.add(_KeyboardMenu(id: widget.id, ffi: widget.ffi));
if (!isWeb) {
menubarItems.add(_ChatMenu(id: widget.id, ffi: widget.ffi));
menubarItems.add(_VoiceCallMenu(id: widget.id, ffi: widget.ffi));
toolbarItems.add(_ChatMenu(id: widget.id, ffi: widget.ffi));
toolbarItems.add(_VoiceCallMenu(id: widget.id, ffi: widget.ffi));
}
menubarItems.add(_RecordMenu());
menubarItems.add(_CloseMenu(id: widget.id, ffi: widget.ffi));
toolbarItems.add(_RecordMenu());
toolbarItems.add(_CloseMenu(id: widget.id, ffi: widget.ffi));
return Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -427,7 +436,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
child: Row(
children: [
SizedBox(width: _MenubarTheme.buttonHMargin * 2),
...menubarItems,
...toolbarItems,
SizedBox(width: _MenubarTheme.buttonHMargin * 2)
],
),
@ -527,10 +536,6 @@ class _MonitorMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (PrivacyModeState.find(id).isTrue ||
stateGlobal.displaysCount.value < 2) {
return Offstage();
}
return _IconSubmenuButton(
tooltip: 'Select Monitor',
icon: icon(),
@ -549,19 +554,20 @@ class _MonitorMenu extends StatelessWidget {
alignment: Alignment.center,
children: [
SvgPicture.asset(
"assets/display.svg",
"assets/screen.svg",
color: Colors.white,
),
Padding(
padding: const EdgeInsets.only(bottom: 3.9),
child: Obx(() {
RxInt display = CurrentDisplayState.find(id);
return Text(
'${display.value + 1}/${pi.displays.length}',
style: const TextStyle(color: Colors.white, fontSize: 8),
);
}),
)
Obx(() {
RxInt display = CurrentDisplayState.find(id);
return Text(
'${display.value + 1}/${pi.displays.length}',
style: const TextStyle(
color: _MenubarTheme.blueColor,
fontSize: 8,
fontWeight: FontWeight.bold,
),
);
}),
],
);
}
@ -584,19 +590,17 @@ class _MonitorMenu extends StatelessWidget {
alignment: Alignment.center,
children: [
SvgPicture.asset(
"assets/display.svg",
"assets/screen.svg",
color: Colors.white,
),
Padding(
padding: const EdgeInsets.only(bottom: 3.5 /*2.5*/),
child: Text(
(i + 1).toString(),
style: TextStyle(
color: Colors.white,
fontSize: 12,
),
Text(
(i + 1).toString(),
style: TextStyle(
color: _MenubarTheme.blueColor,
fontSize: 12,
fontWeight: FontWeight.bold,
),
)
),
],
),
),
@ -2206,3 +2210,69 @@ Widget _buildPointerTrackWidget(Widget child, FFI ffi) {
),
);
}
class _MultiMonitorMenu extends StatelessWidget {
final String id;
final FFI ffi;
const _MultiMonitorMenu({
super.key,
required this.id,
required this.ffi,
});
@override
Widget build(BuildContext context) {
final List<Widget> rowChildren = [];
final pi = ffi.ffiModel.pi;
for (int i = 0; i < pi.displays.length; i++) {
rowChildren.add(
Obx(() {
RxInt display = CurrentDisplayState.find(id);
return _IconMenuButton(
topLevel: false,
color: i == display.value
? _MenubarTheme.blueColor
: Colors.grey[800]!,
hoverColor: i == display.value
? _MenubarTheme.hoverBlueColor
: Colors.grey[850]!,
icon: Container(
alignment: AlignmentDirectional.center,
constraints:
const BoxConstraints(minHeight: _MenubarTheme.height),
child: Stack(
alignment: Alignment.center,
children: [
SvgPicture.asset(
"assets/screen.svg",
color: Colors.white,
),
Obx(
() => Text(
(i + 1).toString(),
style: TextStyle(
color: i == display.value
? _MenubarTheme.blueColor
: Colors.grey[800]!,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
onPressed: () {
if (display.value != i) {
bind.sessionSwitchDisplay(id: id, value: i);
}
},
);
}),
);
}
return Row(children: rowChildren);
}
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "此文件与对方的一致")
("identical_file_tip", "此文件与对方的一致"),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", "Tom brugernavn"),
("Empty Password", "Tom adgangskode"),
("Me", "Mig"),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", "Leerer Benutzername"),
("Empty Password", "Leeres Passwort"),
("Me", "Ich"),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", "Κενό όνομα χρήστη"),
("Empty Password", "Κενός κωδικός πρόσβασης"),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -52,6 +52,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("empty_favorite_tip", "No favorite peers yet?\nLet's find someone to connect with and add it to your favorites!"),
("empty_lan_tip", "Oh no, it looks like we haven't discovered any peers yet."),
("empty_address_book_tip", "Oh dear, it appears that there are currently no peers listed in your address book."),
("identical_file_tip", "This file is identical with the peer's one.")
("identical_file_tip", "This file is identical with the peer's one."),
("show_monitors_tip", "Show monitors in toolbar")
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", "Nombre de usuario vacío"),
("Empty Password", "Contraseña vacía"),
("Me", "Yo"),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", "Nome Utente Vuoto"),
("Empty Password", "Password Vuota"),
("Me", "Io"),
("identical_file_tip", "")
("identical_file_tip", "Questo file è identico a quello del peer."),
("show_monitors_tip", "Mostra schermi nella barra degli strumenti"),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", "Gebruikersnaam Leeg"),
("Empty Password", "Wachtwoord Leeg"),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}

View File

@ -477,6 +477,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Username", ""),
("Empty Password", ""),
("Me", ""),
("identical_file_tip", "")
("identical_file_tip", ""),
("show_monitors_tip", ""),
].iter().cloned().collect();
}