mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge remote-tracking branch 'rd/master' into feat/x11/clipboard-file/init
Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
@@ -32,7 +32,7 @@ import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||
for (var peer in peerData) {
|
||||
if (peer is Map && peer.containsKey("id")) {
|
||||
String id = peer["id"];
|
||||
if (id != null && !combinedPeers.containsKey(id)) {
|
||||
if (!combinedPeers.containsKey(id)) {
|
||||
combinedPeers[id] = peer;
|
||||
}
|
||||
}
|
||||
@@ -55,12 +55,12 @@ import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||
}
|
||||
|
||||
class AutocompletePeerTile extends StatefulWidget {
|
||||
final IDTextEditingController idController;
|
||||
final VoidCallback onSelect;
|
||||
final Peer peer;
|
||||
|
||||
const AutocompletePeerTile({
|
||||
Key? key,
|
||||
required this.idController,
|
||||
required this.onSelect,
|
||||
required this.peer,
|
||||
}) : super(key: key);
|
||||
|
||||
@@ -85,12 +85,7 @@ class _AutocompletePeerTileState extends State<AutocompletePeerTile>{
|
||||
fontSize: 11,
|
||||
color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6));
|
||||
final child = GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
widget.idController.id = widget.peer.id;
|
||||
FocusScope.of(context).unfocus();
|
||||
});
|
||||
},
|
||||
onTap: () => widget.onSelect(),
|
||||
child:
|
||||
Container(
|
||||
height: 42,
|
||||
|
||||
@@ -190,14 +190,20 @@ class _PeersViewState extends State<_PeersView> with WindowListener {
|
||||
child: widget.peerCardBuilder(peer),
|
||||
);
|
||||
final windowWidth = MediaQuery.of(context).size.width;
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
// `Provider.of<PeerTabModel>(context)` will causes infinete loop.
|
||||
// Because `gFFI.peerTabModel.setCurrentTabCachedPeers(peers)` will trigger `notifyListeners()`.
|
||||
//
|
||||
// No need to listen the currentTab change event.
|
||||
// Because the currentTab change event will trigger the peers change event,
|
||||
// and the peers change event will trigger _buildPeersView().
|
||||
final currentTab = Provider.of<PeerTabModel>(context, listen: false).currentTab;
|
||||
final hideAbTagsPanel = bind.mainGetLocalOption(key: "hideAbTagsPanel").isNotEmpty;
|
||||
return isDesktop
|
||||
? Obx(
|
||||
() => SizedBox(
|
||||
width: peerCardUiType.value != PeerUiType.list
|
||||
? 220
|
||||
: model.currentTab == PeerTabIndex.group.index || (model.currentTab == PeerTabIndex.ab.index && !hideAbTagsPanel)
|
||||
: currentTab == PeerTabIndex.group.index || (currentTab == PeerTabIndex.ab.index && !hideAbTagsPanel)
|
||||
? windowWidth - 390 :
|
||||
windowWidth - 227,
|
||||
height:
|
||||
|
||||
@@ -5,6 +5,9 @@ import 'package:flutter_hbb/common.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
const int kMaxVirtualDisplayCount = 4;
|
||||
const int kAllVirtualDisplay = -1;
|
||||
|
||||
const double kDesktopRemoteTabBarHeight = 28.0;
|
||||
const int kInvalidWindowId = -1;
|
||||
const int kMainWindowId = 0;
|
||||
@@ -15,6 +18,11 @@ const kKeyLegacyMode = 'legacy';
|
||||
const kKeyMapMode = 'map';
|
||||
const kKeyTranslateMode = 'translate';
|
||||
|
||||
const String kPlatformAdditionsIsWayland = "is_wayland";
|
||||
const String kPlatformAdditionsHeadless = "headless";
|
||||
const String kPlatformAdditionsIsInstalled = "is_installed";
|
||||
const String kPlatformAdditionsVirtualDisplays = "virtual_displays";
|
||||
|
||||
const String kPeerPlatformWindows = "Windows";
|
||||
const String kPeerPlatformLinux = "Linux";
|
||||
const String kPeerPlatformMacOS = "Mac OS";
|
||||
|
||||
@@ -277,6 +277,12 @@ class _ConnectionPageState extends State<ConnectionPage>
|
||||
},
|
||||
));
|
||||
},
|
||||
onSelected: (option) {
|
||||
setState(() {
|
||||
_idController.id = option.id;
|
||||
FocusScope.of(context).unfocus();
|
||||
});
|
||||
},
|
||||
optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<Peer> onSelected, Iterable<Peer> options) {
|
||||
double maxHeight = options.length * 50;
|
||||
maxHeight = maxHeight > 200 ? 200 : maxHeight;
|
||||
@@ -304,7 +310,7 @@ class _ConnectionPageState extends State<ConnectionPage>
|
||||
: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: ListView(
|
||||
children: options.map((peer) => AutocompletePeerTile(idController: _idController, peer: peer)).toList(),
|
||||
children: options.map((peer) => AutocompletePeerTile(onSelect: () => onSelected(peer), peer: peer)).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -978,6 +978,10 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
ffi: widget.ffi,
|
||||
screenAdjustor: _screenAdjustor,
|
||||
),
|
||||
_VirtualDisplayMenu(
|
||||
id: widget.id,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
Divider(),
|
||||
toggles(),
|
||||
widget.pluginItem,
|
||||
@@ -1387,6 +1391,70 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
|
||||
}
|
||||
}
|
||||
|
||||
class _VirtualDisplayMenu extends StatefulWidget {
|
||||
final String id;
|
||||
final FFI ffi;
|
||||
|
||||
_VirtualDisplayMenu({
|
||||
Key? key,
|
||||
required this.id,
|
||||
required this.ffi,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<_VirtualDisplayMenu> createState() => _VirtualDisplayMenuState();
|
||||
}
|
||||
|
||||
class _VirtualDisplayMenuState extends State<_VirtualDisplayMenu> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.ffi.ffiModel.pi.platform != kPeerPlatformWindows) {
|
||||
return Offstage();
|
||||
}
|
||||
if (!widget.ffi.ffiModel.pi.isInstalled) {
|
||||
return Offstage();
|
||||
}
|
||||
|
||||
final virtualDisplays = widget.ffi.ffiModel.pi.virtualDisplays;
|
||||
|
||||
final children = <Widget>[];
|
||||
for (var i = 0; i < kMaxVirtualDisplayCount; i++) {
|
||||
children.add(CkbMenuButton(
|
||||
value: virtualDisplays.contains(i + 1),
|
||||
onChanged: (bool? value) async {
|
||||
if (value != null) {
|
||||
bind.sessionToggleVirtualDisplay(
|
||||
sessionId: widget.ffi.sessionId, index: i + 1, on: value);
|
||||
}
|
||||
},
|
||||
child: Text('${translate('Virtual display')} ${i + 1}'),
|
||||
ffi: widget.ffi,
|
||||
));
|
||||
}
|
||||
children.add(Divider());
|
||||
children.add(MenuButton(
|
||||
onPressed: () {
|
||||
bind.sessionToggleVirtualDisplay(
|
||||
sessionId: widget.ffi.sessionId,
|
||||
index: kAllVirtualDisplay,
|
||||
on: false);
|
||||
},
|
||||
ffi: widget.ffi,
|
||||
child: Text(translate('Plug out all')),
|
||||
));
|
||||
return _SubmenuButton(
|
||||
ffi: widget.ffi,
|
||||
menuChildren: children,
|
||||
child: Text(translate("Virtual display")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _KeyboardMenu extends StatelessWidget {
|
||||
final String id;
|
||||
final FFI ffi;
|
||||
|
||||
@@ -245,6 +245,12 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
inputFormatters: [IDTextInputFormatter()],
|
||||
);
|
||||
},
|
||||
onSelected: (option) {
|
||||
setState(() {
|
||||
_idController.id = option.id;
|
||||
FocusScope.of(context).unfocus();
|
||||
});
|
||||
},
|
||||
optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<Peer> onSelected, Iterable<Peer> options) {
|
||||
double maxHeight = options.length * 50;
|
||||
maxHeight = maxHeight > 200 ? 200 : maxHeight;
|
||||
@@ -268,7 +274,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
)))
|
||||
: ListView(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
children: options.map((peer) => AutocompletePeerTile(idController: _idController, peer: peer)).toList(),
|
||||
children: options.map((peer) => AutocompletePeerTile(onSelect: () => onSelected(peer), peer: peer)).toList(),
|
||||
))))
|
||||
);
|
||||
},
|
||||
|
||||
@@ -248,6 +248,8 @@ class FfiModel with ChangeNotifier {
|
||||
handlePeerInfo(evt, peerId, false);
|
||||
} else if (name == 'sync_peer_info') {
|
||||
handleSyncPeerInfo(evt, sessionId, peerId);
|
||||
} else if (name == 'sync_platform_additions') {
|
||||
handlePlatformAdditions(evt, sessionId, peerId);
|
||||
} else if (name == 'connection_ready') {
|
||||
setConnectionType(
|
||||
peerId, evt['secure'] == 'true', evt['direct'] == 'true');
|
||||
@@ -895,6 +897,33 @@ class FfiModel with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
handlePlatformAdditions(
|
||||
Map<String, dynamic> evt, SessionID sessionId, String peerId) async {
|
||||
final updateData = evt['platform_additions'] as String?;
|
||||
if (updateData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (updateData.isEmpty) {
|
||||
_pi.platformAdditions.remove(kPlatformAdditionsVirtualDisplays);
|
||||
} else {
|
||||
try {
|
||||
final updateJson = json.decode(updateData);
|
||||
for (final key in updateJson.keys) {
|
||||
_pi.platformAdditions[key] = updateJson[key];
|
||||
}
|
||||
if (!updateJson.contains(kPlatformAdditionsVirtualDisplays)) {
|
||||
_pi.platformAdditions.remove(kPlatformAdditionsVirtualDisplays);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Failed to decode platformAdditions $e');
|
||||
}
|
||||
}
|
||||
|
||||
cachedPeerData.peerInfo['platform_additions'] =
|
||||
json.encode(_pi.platformAdditions);
|
||||
}
|
||||
|
||||
// Directly switch to the new display without waiting for the response.
|
||||
switchToNewDisplay(int display, SessionID sessionId, String peerId) {
|
||||
// VideoHandler creation is upon when video frames are received, so either caching commands(don't know next width/height) or stopping recording when switching displays.
|
||||
@@ -2300,8 +2329,13 @@ class PeerInfo with ChangeNotifier {
|
||||
RxInt displaysCount = 0.obs;
|
||||
RxBool isSet = false.obs;
|
||||
|
||||
bool get isWayland => platformAdditions['is_wayland'] == true;
|
||||
bool get isHeadless => platformAdditions['headless'] == true;
|
||||
bool get isWayland => platformAdditions[kPlatformAdditionsIsWayland] == true;
|
||||
bool get isHeadless => platformAdditions[kPlatformAdditionsHeadless] == true;
|
||||
bool get isInstalled =>
|
||||
platform != kPeerPlatformWindows ||
|
||||
platformAdditions[kPlatformAdditionsIsInstalled] == true;
|
||||
List<int> get virtualDisplays => List<int>.from(
|
||||
platformAdditions[kPlatformAdditionsVirtualDisplays] ?? []);
|
||||
|
||||
bool get isSupportMultiDisplay => isDesktop && isSupportMultiUiSession;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user