Merge pull request #3353 from 21pages/elevate

peercard and request elevation menu
This commit is contained in:
RustDesk 2023-02-24 17:46:37 +08:00 committed by GitHub
commit 1b82dc86ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 127 additions and 57 deletions

View File

@ -534,7 +534,7 @@ abstract class BasePeerCard extends StatelessWidget {
proc: () { proc: () {
() async { () async {
if (isLan) { if (isLan) {
// TODO bind.mainRemoveDiscovered(id: id);
} else { } else {
final favs = (await bind.mainGetFav()).toList(); final favs = (await bind.mainGetFav()).toList();
if (favs.remove(id)) { if (favs.remove(id)) {
@ -745,12 +745,9 @@ class RecentPeerCard extends BasePeerCard {
} }
if (gFFI.userModel.userName.isNotEmpty) { if (gFFI.userModel.userName.isNotEmpty) {
// if (!gFFI.abModel.idContainBy(peer.id)) { if (!gFFI.abModel.idContainBy(peer.id)) {
// menuItems.add(_addToAb(peer)); menuItems.add(_addToAb(peer));
// } else { }
// menuItems.add(_removeFromAb(peer));
// }
menuItems.add(_addToAb(peer));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
@ -797,12 +794,9 @@ class FavoritePeerCard extends BasePeerCard {
})); }));
if (gFFI.userModel.userName.isNotEmpty) { if (gFFI.userModel.userName.isNotEmpty) {
// if (!gFFI.abModel.idContainBy(peer.id)) { if (!gFFI.abModel.idContainBy(peer.id)) {
// menuItems.add(_addToAb(peer)); menuItems.add(_addToAb(peer));
// } else { }
// menuItems.add(_removeFromAb(peer));
// }
menuItems.add(_addToAb(peer));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
@ -843,23 +837,27 @@ class DiscoveredPeerCard extends BasePeerCard {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
if (!favs.contains(peer.id)) { final inRecent = await bind.mainIsInRecentPeers(id: peer.id);
menuItems.add(_addFavAction(peer.id)); if (inRecent) {
} else { if (!favs.contains(peer.id)) {
menuItems.add(_rmFavAction(peer.id, () async {})); menuItems.add(_addFavAction(peer.id));
} else {
menuItems.add(_rmFavAction(peer.id, () async {}));
}
} }
if (gFFI.userModel.userName.isNotEmpty) { if (gFFI.userModel.userName.isNotEmpty) {
// if (!gFFI.abModel.idContainBy(peer.id)) { if (!gFFI.abModel.idContainBy(peer.id)) {
// menuItems.add(_addToAb(peer)); menuItems.add(_addToAb(peer));
// } else { }
// menuItems.add(_removeFromAb(peer));
// }
menuItems.add(_addToAb(peer));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
menuItems.add(_removeAction(peer.id, () async {})); menuItems.add(
_removeAction(peer.id, () async {
await bind.mainLoadLanPeers();
}, isLan: true),
);
return menuItems; return menuItems;
} }

View File

@ -598,6 +598,7 @@ class _ControlMenu extends StatelessWidget {
hoverColor: _MenubarTheme.hoverBlueColor, hoverColor: _MenubarTheme.hoverBlueColor,
ffi: ffi, ffi: ffi,
menuChildren: [ menuChildren: [
requestElevation(),
osPassword(), osPassword(),
transferFile(context), transferFile(context),
tcpTunneling(context), tcpTunneling(context),
@ -611,6 +612,15 @@ class _ControlMenu extends StatelessWidget {
]); ]);
} }
requestElevation() {
final visible = ffi.elevationModel.showRequestMenu;
if (!visible) return Offstage();
return _MenuItemButton(
child: Text(translate('Request Elevation')),
ffi: ffi,
onPressed: () => showRequestElevationDialog(id, ffi.dialogManager));
}
osPassword() { osPassword() {
return _MenuItemButton( return _MenuItemButton(
child: Text(translate('OS Password')), child: Text(translate('OS Password')),
@ -1091,7 +1101,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
await bind.sessionSetImageQuality(id: widget.id, value: value); await bind.sessionSetImageQuality(id: widget.id, value: value);
} }
return SubmenuButton( return _SubmenuButton(
ffi: widget.ffi,
child: Text(translate('Image Quality')), child: Text(translate('Image Quality')),
menuChildren: [ menuChildren: [
_RadioMenuButton<String>( _RadioMenuButton<String>(
@ -1125,7 +1136,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
}, },
ffi: widget.ffi, ffi: widget.ffi,
), ),
].map((e) => _buildPointerTrackWidget(e, widget.ffi)).toList(), ],
); );
}); });
} }
@ -1300,7 +1311,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
bind.sessionChangePreferCodec(id: widget.id); bind.sessionChangePreferCodec(id: widget.id);
} }
return SubmenuButton( return _SubmenuButton(
ffi: widget.ffi,
child: Text(translate('Codec')), child: Text(translate('Codec')),
menuChildren: [ menuChildren: [
_RadioMenuButton<String>( _RadioMenuButton<String>(
@ -1331,7 +1343,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
onChanged: onChanged, onChanged: onChanged,
ffi: widget.ffi, ffi: widget.ffi,
), ),
].map((e) => _buildPointerTrackWidget(e, widget.ffi)).toList()); ]);
}); });
} }
@ -1363,7 +1375,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
} }
} }
return SubmenuButton( return _SubmenuButton(
ffi: widget.ffi,
menuChildren: resolutions menuChildren: resolutions
.map((e) => _RadioMenuButton( .map((e) => _RadioMenuButton(
value: '${e.width}x${e.height}', value: '${e.width}x${e.height}',
@ -1371,8 +1384,6 @@ class _DisplayMenuState extends State<_DisplayMenu> {
onChanged: onChanged, onChanged: onChanged,
ffi: widget.ffi, ffi: widget.ffi,
child: Text('${e.width}x${e.height}'))) child: Text('${e.width}x${e.height}')))
.toList()
.map((e) => _buildPointerTrackWidget(e, widget.ffi))
.toList(), .toList(),
child: Text(translate("Resolution"))); child: Text(translate("Resolution")));
} }
@ -1859,6 +1870,28 @@ class _IconSubmenuButtonState extends State<_IconSubmenuButton> {
} }
} }
class _SubmenuButton extends StatelessWidget {
final List<Widget> menuChildren;
final Widget? child;
final FFI ffi;
const _SubmenuButton({
Key? key,
required this.menuChildren,
required this.child,
required this.ffi,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SubmenuButton(
key: key,
child: child,
menuChildren:
menuChildren.map((e) => _buildPointerTrackWidget(e, ffi)).toList(),
);
}
}
class _MenuItemButton extends StatelessWidget { class _MenuItemButton extends StatelessWidget {
final VoidCallback? onPressed; final VoidCallback? onPressed;
final Widget? trailingIcon; final Widget? trailingIcon;

View File

@ -374,8 +374,7 @@ void showWaitUacDialog(
)); ));
} }
void _showRequestElevationDialog( void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
String id, OverlayDialogManager dialogManager) {
RxString groupValue = ''.obs; RxString groupValue = ''.obs;
RxString errUser = ''.obs; RxString errUser = ''.obs;
RxString errPwd = ''.obs; RxString errPwd = ''.obs;
@ -531,7 +530,7 @@ void showOnBlockDialog(
dialogManager.show(tag: '$id-$type', (setState, close) { dialogManager.show(tag: '$id-$type', (setState, close) {
void submit() { void submit() {
close(); close();
_showRequestElevationDialog(id, dialogManager); showRequestElevationDialog(id, dialogManager);
} }
return CustomAlertDialog( return CustomAlertDialog(
@ -553,7 +552,7 @@ void showElevationError(String id, String type, String title, String text,
dialogManager.show(tag: '$id-$type', (setState, close) { dialogManager.show(tag: '$id-$type', (setState, close) {
void submit() { void submit() {
close(); close();
_showRequestElevationDialog(id, dialogManager); showRequestElevationDialog(id, dialogManager);
} }
return CustomAlertDialog( return CustomAlertDialog(

View File

@ -203,6 +203,8 @@ class FfiModel with ChangeNotifier {
final peer_id = evt['peer_id'].toString(); final peer_id = evt['peer_id'].toString();
await bind.sessionSwitchSides(id: peer_id); await bind.sessionSwitchSides(id: peer_id);
closeConnection(id: peer_id); closeConnection(id: peer_id);
} else if (name == 'portable_service_running') {
parent.target?.elevationModel.onPortableServiceRunning(evt);
} else if (name == "on_url_scheme_received") { } else if (name == "on_url_scheme_received") {
final url = evt['url'].toString(); final url = evt['url'].toString();
parseRustdeskUri(url); parseRustdeskUri(url);
@ -439,6 +441,7 @@ class FfiModel with ChangeNotifier {
Map<String, dynamic> features = json.decode(evt['features']); Map<String, dynamic> features = json.decode(evt['features']);
_pi.features.privacyMode = features['privacy_mode'] == 1; _pi.features.privacyMode = features['privacy_mode'] == 1;
handleResolutions(peerId, evt["resolutions"]); handleResolutions(peerId, evt["resolutions"]);
parent.target?.elevationModel.onPeerInfo(_pi);
} }
notifyListeners(); notifyListeners();
} }
@ -1395,6 +1398,21 @@ class RecordingModel with ChangeNotifier {
} }
} }
class ElevationModel with ChangeNotifier {
WeakReference<FFI> parent;
ElevationModel(this.parent);
bool _running = false;
bool _canElevate = false;
bool get showRequestMenu => _canElevate && !_running;
onPeerInfo(PeerInfo pi) {
_canElevate = pi.platform == kPeerPlatformWindows && pi.sasEnabled == false;
}
onPortableServiceRunning(Map<String, dynamic> evt) {
_running = evt['running'] == 'true';
}
}
enum ConnType { defaultConn, fileTransfer, portForward, rdp } enum ConnType { defaultConn, fileTransfer, portForward, rdp }
/// Flutter state manager and data communication with the Rust core. /// Flutter state manager and data communication with the Rust core.
@ -1420,6 +1438,7 @@ class FFI {
late final QualityMonitorModel qualityMonitorModel; // session late final QualityMonitorModel qualityMonitorModel; // session
late final RecordingModel recordingModel; // session late final RecordingModel recordingModel; // session
late final InputModel inputModel; // session late final InputModel inputModel; // session
late final ElevationModel elevationModel; // session
FFI() { FFI() {
imageModel = ImageModel(WeakReference(this)); imageModel = ImageModel(WeakReference(this));
@ -1436,6 +1455,7 @@ class FFI {
qualityMonitorModel = QualityMonitorModel(WeakReference(this)); qualityMonitorModel = QualityMonitorModel(WeakReference(this));
recordingModel = RecordingModel(WeakReference(this)); recordingModel = RecordingModel(WeakReference(this));
inputModel = InputModel(WeakReference(this)); inputModel = InputModel(WeakReference(this));
elevationModel = ElevationModel(WeakReference(this));
} }
/// Start with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward]. /// Start with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].

View File

@ -56,6 +56,7 @@ pub struct Remote<T: InvokeUiSession> {
data_count: Arc<AtomicUsize>, data_count: Arc<AtomicUsize>,
frame_count: Arc<AtomicUsize>, frame_count: Arc<AtomicUsize>,
video_format: CodecFormat, video_format: CodecFormat,
elevation_requested: bool,
} }
impl<T: InvokeUiSession> Remote<T> { impl<T: InvokeUiSession> Remote<T> {
@ -87,6 +88,7 @@ impl<T: InvokeUiSession> Remote<T> {
video_format: CodecFormat::Unknown, video_format: CodecFormat::Unknown,
stop_voice_call_sender: None, stop_voice_call_sender: None,
voice_call_request_timestamp: None, voice_call_request_timestamp: None,
elevation_requested: false,
} }
} }
@ -686,6 +688,7 @@ impl<T: InvokeUiSession> Remote<T> {
let mut msg = Message::new(); let mut msg = Message::new();
msg.set_misc(misc); msg.set_misc(misc);
allow_err!(peer.send(&msg).await); allow_err!(peer.send(&msg).await);
self.elevation_requested = true;
} }
Data::ElevateWithLogon(username, password) => { Data::ElevateWithLogon(username, password) => {
let mut request = ElevationRequest::new(); let mut request = ElevationRequest::new();
@ -699,6 +702,7 @@ impl<T: InvokeUiSession> Remote<T> {
let mut msg = Message::new(); let mut msg = Message::new();
msg.set_misc(misc); msg.set_misc(misc);
allow_err!(peer.send(&msg).await); allow_err!(peer.send(&msg).await);
self.elevation_requested = true;
} }
Data::NewVoiceCall => { Data::NewVoiceCall => {
let msg = new_voice_call_request(true); let msg = new_voice_call_request(true);
@ -1181,7 +1185,8 @@ impl<T: InvokeUiSession> Remote<T> {
} }
} }
Some(misc::Union::PortableServiceRunning(b)) => { Some(misc::Union::PortableServiceRunning(b)) => {
if b { self.handler.portable_service_running(b);
if self.elevation_requested && b {
self.handler.msgbox( self.handler.msgbox(
"custom-nocancel-success", "custom-nocancel-success",
"Successful", "Successful",
@ -1253,14 +1258,12 @@ impl<T: InvokeUiSession> Remote<T> {
} }
} }
} }
Some(message::Union::PeerInfo(pi)) => { Some(message::Union::PeerInfo(pi)) => match pi.conn_id {
match pi.conn_id { crate::SYNC_PEER_INFO_DISPLAYS => {
crate::SYNC_PEER_INFO_DISPLAYS => { self.handler.set_displays(&pi.displays);
self.handler.set_displays(&pi.displays);
}
_ => {}
} }
} _ => {}
},
_ => {} _ => {}
} }
} }

View File

@ -572,6 +572,13 @@ impl InvokeUiSession for FlutterHandler {
self.push_event("switch_back", [("peer_id", peer_id)].into()); self.push_event("switch_back", [("peer_id", peer_id)].into());
} }
fn portable_service_running(&self, running: bool) {
self.push_event(
"portable_service_running",
[("running", running.to_string().as_str())].into(),
);
}
fn on_voice_call_started(&self) { fn on_voice_call_started(&self) {
self.push_event("on_voice_call_started", [].into()); self.push_event("on_voice_call_started", [].into());
} }

View File

@ -726,6 +726,10 @@ pub fn main_peer_has_password(id: String) -> bool {
peer_has_password(id) peer_has_password(id)
} }
pub fn main_is_in_recent_peers(id: String) -> bool {
PeerConfig::peers().iter().any(|e| e.0 == id)
}
pub fn main_load_recent_peers() { pub fn main_load_recent_peers() {
if !config::APP_DIR.read().unwrap().is_empty() { if !config::APP_DIR.read().unwrap().is_empty() {
let peers: Vec<HashMap<&str, String>> = PeerConfig::peers() let peers: Vec<HashMap<&str, String>> = PeerConfig::peers()
@ -796,6 +800,10 @@ pub fn main_load_lan_peers() {
}; };
} }
pub fn main_remove_discovered(id: String) {
remove_discovered(id);
}
fn main_broadcast_message(data: &HashMap<&str, &str>) { fn main_broadcast_message(data: &HashMap<&str, &str>) {
let apps = vec![ let apps = vec![
flutter::APP_TYPE_DESKTOP_REMOTE, flutter::APP_TYPE_DESKTOP_REMOTE,

View File

@ -1552,7 +1552,6 @@ impl Connection {
.err() .err()
.map_or("".to_string(), |e| e.to_string()); .map_or("".to_string(), |e| e.to_string());
} }
self.portable.elevation_requested = err.is_empty();
let mut misc = Misc::new(); let mut misc = Misc::new();
misc.set_elevation_response(err); misc.set_elevation_response(err);
let mut msg = Message::new(); let mut msg = Message::new();
@ -1571,7 +1570,6 @@ impl Connection {
.err() .err()
.map_or("".to_string(), |e| e.to_string()); .map_or("".to_string(), |e| e.to_string());
} }
self.portable.elevation_requested = err.is_empty();
let mut misc = Misc::new(); let mut misc = Misc::new();
misc.set_elevation_response(err); misc.set_elevation_response(err);
let mut msg = Message::new(); let mut msg = Message::new();
@ -1936,13 +1934,11 @@ impl Connection {
let p = &mut self.portable; let p = &mut self.portable;
if running != p.last_running { if running != p.last_running {
p.last_running = running; p.last_running = running;
if running && p.elevation_requested { let mut misc = Misc::new();
let mut misc = Misc::new(); misc.set_portable_service_running(running);
misc.set_portable_service_running(running); let mut msg = Message::new();
let mut msg = Message::new(); msg.set_misc(misc);
msg.set_misc(misc); self.inner.send(msg.into());
self.inner.send(msg.into());
}
} }
let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone(); let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone();
if p.last_uac != uac { if p.last_uac != uac {
@ -2166,7 +2162,6 @@ pub struct PortableState {
pub last_foreground_window_elevated: bool, pub last_foreground_window_elevated: bool,
pub last_running: bool, pub last_running: bool,
pub is_installed: bool, pub is_installed: bool,
pub elevation_requested: bool,
} }
#[cfg(windows)] #[cfg(windows)]
@ -2177,7 +2172,6 @@ impl Default for PortableState {
last_uac: Default::default(), last_uac: Default::default(),
last_foreground_window_elevated: Default::default(), last_foreground_window_elevated: Default::default(),
last_running: Default::default(), last_running: Default::default(),
elevation_requested: Default::default(),
} }
} }
} }

View File

@ -413,9 +413,7 @@ impl UI {
} }
fn remove_discovered(&mut self, id: String) { fn remove_discovered(&mut self, id: String) {
let mut peers = config::LanPeers::load().peers; remove_discovered(id);
peers.retain(|x| x.id != id);
config::LanPeers::store(&peers);
} }
fn send_wol(&mut self, id: String) { fn send_wol(&mut self, id: String) {

View File

@ -277,6 +277,8 @@ impl InvokeUiSession for SciterHandler {
fn switch_back(&self, _id: &str) {} fn switch_back(&self, _id: &str) {}
fn portable_service_running(&self, _running: bool) {}
fn on_voice_call_started(&self) { fn on_voice_call_started(&self) {
self.call("onVoiceCallStart", &make_args!()); self.call("onVoiceCallStart", &make_args!());
} }

View File

@ -596,6 +596,13 @@ pub fn get_lan_peers() -> Vec<HashMap<&'static str, String>> {
.collect() .collect()
} }
#[inline]
pub fn remove_discovered(id: String) {
let mut peers = config::LanPeers::load().peers;
peers.retain(|x| x.id != id);
config::LanPeers::store(&peers);
}
#[inline] #[inline]
pub fn get_uuid() -> String { pub fn get_uuid() -> String {
base64::encode(hbb_common::get_uuid()) base64::encode(hbb_common::get_uuid())

View File

@ -805,6 +805,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn clipboard(&self, content: String); fn clipboard(&self, content: String);
fn cancel_msgbox(&self, tag: &str); fn cancel_msgbox(&self, tag: &str);
fn switch_back(&self, id: &str); fn switch_back(&self, id: &str);
fn portable_service_running(&self, running: bool);
fn on_voice_call_started(&self); fn on_voice_call_started(&self);
fn on_voice_call_closed(&self, reason: &str); fn on_voice_call_closed(&self, reason: &str);
fn on_voice_call_waiting(&self); fn on_voice_call_waiting(&self);