flutter_desktop: handle privacy mode back notifications

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-08-08 22:00:01 +08:00
parent e553756ad8
commit b2ffe9dee4
8 changed files with 210 additions and 38 deletions

View File

@ -194,14 +194,20 @@ void msgBox(String type, String title, String text, {bool? hasCancel}) {
style: TextStyle(color: MyTheme.accent)))); style: TextStyle(color: MyTheme.accent))));
SmartDialog.dismiss(); SmartDialog.dismiss();
final buttons = [ List<Widget> buttons = [];
wrap(Translator.call('OK'), () { if (type != "connecting" && type != "success" && type.indexOf("nook") < 0) {
SmartDialog.dismiss(); buttons.insert(
backToHome(); 0,
}) wrap(Translator.call('OK'), () {
]; SmartDialog.dismiss();
backToHome();
}));
}
if (hasCancel == null) { if (hasCancel == null) {
hasCancel = type != 'error'; // hasCancel = type != 'error';
hasCancel = type.indexOf("error") < 0 &&
type.indexOf("nocancel") < 0 &&
type != "restarting";
} }
if (hasCancel) { if (hasCancel) {
buttons.insert( buttons.insert(
@ -210,6 +216,14 @@ void msgBox(String type, String title, String text, {bool? hasCancel}) {
SmartDialog.dismiss(); SmartDialog.dismiss();
})); }));
} }
// TODO: test this button
if (type.indexOf("hasclose") >= 0) {
buttons.insert(
0,
wrap(Translator.call('Close'), () {
SmartDialog.dismiss();
}));
}
DialogManager.show((setState, close) => CustomAlertDialog( DialogManager.show((setState, close) => CustomAlertDialog(
title: Text(translate(title), style: TextStyle(fontSize: 21)), title: Text(translate(title), style: TextStyle(fontSize: 21)),
content: Text(Translator.call(text), style: TextStyle(fontSize: 15)), content: Text(Translator.call(text), style: TextStyle(fontSize: 15)),

View File

@ -604,8 +604,12 @@ class _RemotePageState extends State<RemotePage>
await bind.getSessionToggleOption(id: id, arg: 'privacy-mode') != await bind.getSessionToggleOption(id: id, arg: 'privacy-mode') !=
true) { true) {
more.add(PopupMenuItem<String>( more.add(PopupMenuItem<String>(
child: Text(translate((_ffi.ffiModel.inputBlocked ? 'Unb' : 'B') + child: Consumer<FfiModel>(
'lock user input')), builder: (_context, ffiModel, _child) => () {
return Text(translate(
(ffiModel.inputBlocked ? 'Unb' : 'B') +
'lock user input'));
}()),
value: 'block-input')); value: 'block-input'));
} }
} }
@ -951,7 +955,11 @@ void showOptions(String id) async {
more.add(getToggle( more.add(getToggle(
id, setState, 'lock-after-session-end', 'Lock after session end')); id, setState, 'lock-after-session-end', 'Lock after session end'));
if (pi.platform == 'Windows') { if (pi.platform == 'Windows') {
more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode')); more.add(Consumer<FfiModel>(
builder: (_context, _ffiModel, _child) => () {
return getToggle(
id, setState, 'privacy-mode', 'Privacy mode');
}()));
} }
} }
var setQuality = (String? value) { var setQuality = (String? value) {

View File

@ -173,6 +173,10 @@ class FfiModel with ChangeNotifier {
parent.target?.serverModel.onClientRemove(evt); parent.target?.serverModel.onClientRemove(evt);
} else if (name == 'update_quality_status') { } else if (name == 'update_quality_status') {
parent.target?.qualityMonitorModel.updateQualityStatus(evt); parent.target?.qualityMonitorModel.updateQualityStatus(evt);
} else if (name == 'update_block_input_state') {
updateBlockInputState(evt);
} else if (name == 'update_privacy_mode') {
updatePrivacyMode(evt);
} }
}; };
} }
@ -228,6 +232,10 @@ class FfiModel with ChangeNotifier {
parent.target?.serverModel.onClientRemove(evt); parent.target?.serverModel.onClientRemove(evt);
} else if (name == 'update_quality_status') { } else if (name == 'update_quality_status') {
parent.target?.qualityMonitorModel.updateQualityStatus(evt); parent.target?.qualityMonitorModel.updateQualityStatus(evt);
} else if (name == 'update_block_input_state') {
updateBlockInputState(evt);
} else if (name == 'update_privacy_mode') {
updatePrivacyMode(evt);
} }
}; };
platformFFI.setEventCallback(cb); platformFFI.setEventCallback(cb);
@ -331,6 +339,15 @@ class FfiModel with ChangeNotifier {
} }
notifyListeners(); notifyListeners();
} }
updateBlockInputState(Map<String, dynamic> evt) {
_inputBlocked = evt['input_state'] == 'on';
notifyListeners();
}
updatePrivacyMode(Map<String, dynamic> evt) {
notifyListeners();
}
} }
class ImageModel with ChangeNotifier { class ImageModel with ChangeNotifier {

View File

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:ui';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';

View File

@ -1004,6 +1004,13 @@ impl LoginConfigHandler {
Some(msg_out) Some(msg_out)
} }
/// Get [`PeerConfig`] of the current [`LoginConfigHandler`].
///
/// # Arguments
pub fn get_config(&mut self) -> &mut PeerConfig {
&mut self.config
}
/// Get [`OptionMessage`] of the current [`LoginConfigHandler`]. /// Get [`OptionMessage`] of the current [`LoginConfigHandler`].
/// Return `None` if there's no option, for example, when the session is only for file transfer. /// Return `None` if there's no option, for example, when the session is only for file transfer.
/// ///

View File

@ -104,6 +104,19 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc<Mutex<String>>>)
} }
} }
pub async fn send_opts_after_login(
config: &crate::client::LoginConfigHandler,
peer: &mut hbb_common::tcp::FramedStream,
) {
if let Some(opts) = config.get_option_message_after_login() {
let mut misc = Misc::new();
misc.set_option(opts);
let mut msg_out = Message::new();
msg_out.set_misc(misc);
allow_err!(peer.send(&msg_out).await);
}
}
#[cfg(feature = "use_rubato")] #[cfg(feature = "use_rubato")]
pub fn resample_channels( pub fn resample_channels(
data: &[f32], data: &[f32],

View File

@ -76,7 +76,7 @@ impl Session {
// TODO close // TODO close
// Self::close(); // Self::close();
let events2ui = Arc::new(RwLock::new(events2ui)); let events2ui = Arc::new(RwLock::new(events2ui));
let mut session = Session { let session = Session {
id: session_id.clone(), id: session_id.clone(),
sender: Default::default(), sender: Default::default(),
lc: Default::default(), lc: Default::default(),
@ -663,6 +663,8 @@ struct Connection {
} }
impl Connection { impl Connection {
// TODO: Similar to remote::start_clipboard
// merge the code
fn start_clipboard( fn start_clipboard(
tx_protobuf: mpsc::UnboundedSender<Data>, tx_protobuf: mpsc::UnboundedSender<Data>,
lc: Arc<RwLock<LoginConfigHandler>>, lc: Arc<RwLock<LoginConfigHandler>>,
@ -842,6 +844,7 @@ impl Connection {
Some(message::Union::VideoFrame(vf)) => { Some(message::Union::VideoFrame(vf)) => {
if !self.first_frame { if !self.first_frame {
self.first_frame = true; self.first_frame = true;
common::send_opts_after_login(&self.session.lc.read().unwrap(), peer).await;
} }
let incomming_format = CodecFormat::from(&vf); let incomming_format = CodecFormat::from(&vf);
if self.video_format != incomming_format { if self.video_format != incomming_format {
@ -1083,6 +1086,11 @@ impl Connection {
self.session.msgbox("error", "Connection Error", &c); self.session.msgbox("error", "Connection Error", &c);
return false; return false;
} }
Some(misc::Union::BackNotification(notification)) => {
if !self.handle_back_notification(notification).await {
return false;
}
}
_ => {} _ => {}
}, },
Some(message::Union::TestDelay(t)) => { Some(message::Union::TestDelay(t)) => {
@ -1107,6 +1115,130 @@ impl Connection {
true true
} }
async fn handle_back_notification(&mut self, notification: BackNotification) -> bool {
match notification.union {
Some(back_notification::Union::BlockInputState(state)) => {
self.handle_back_msg_block_input(
state.enum_value_or(back_notification::BlockInputState::BlkStateUnknown),
)
.await;
}
Some(back_notification::Union::PrivacyModeState(state)) => {
if !self
.handle_back_msg_privacy_mode(
state.enum_value_or(back_notification::PrivacyModeState::PrvStateUnknown),
)
.await
{
return false;
}
}
_ => {}
}
true
}
#[inline(always)]
fn update_block_input_state(&mut self, on: bool) {
self.session.push_event(
"update_block_input_state",
[("input_state", if on { "on" } else { "off" })].into(),
);
}
async fn handle_back_msg_block_input(&mut self, state: back_notification::BlockInputState) {
match state {
back_notification::BlockInputState::BlkOnSucceeded => {
self.update_block_input_state(true);
}
back_notification::BlockInputState::BlkOnFailed => {
self.session
.msgbox("custom-error", "Block user input", "Failed");
self.update_block_input_state(false);
}
back_notification::BlockInputState::BlkOffSucceeded => {
self.update_block_input_state(false);
}
back_notification::BlockInputState::BlkOffFailed => {
self.session
.msgbox("custom-error", "Unblock user input", "Failed");
}
_ => {}
}
}
#[inline(always)]
fn update_privacy_mode(&mut self, on: bool) {
let mut config = self.session.load_config();
config.privacy_mode = on;
self.session.save_config(&config);
self.session.lc.write().unwrap().get_config().privacy_mode = on;
self.session.push_event("update_privacy_mode", [].into());
}
async fn handle_back_msg_privacy_mode(
&mut self,
state: back_notification::PrivacyModeState,
) -> bool {
match state {
back_notification::PrivacyModeState::PrvOnByOther => {
self.session.msgbox(
"error",
"Connecting...",
"Someone turns on privacy mode, exit",
);
return false;
}
back_notification::PrivacyModeState::PrvNotSupported => {
self.session
.msgbox("custom-error", "Privacy mode", "Unsupported");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::PrvOnSucceeded => {
self.session
.msgbox("custom-nocancel", "Privacy mode", "In privacy mode");
self.update_privacy_mode(true);
}
back_notification::PrivacyModeState::PrvOnFailedDenied => {
self.session
.msgbox("custom-error", "Privacy mode", "Peer denied");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::PrvOnFailedPlugin => {
self.session
.msgbox("custom-error", "Privacy mode", "Please install plugins");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::PrvOnFailed => {
self.session
.msgbox("custom-error", "Privacy mode", "Failed");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::PrvOffSucceeded => {
self.session
.msgbox("custom-nocancel", "Privacy mode", "Out privacy mode");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::PrvOffByPeer => {
self.session
.msgbox("custom-error", "Privacy mode", "Peer exit");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::PrvOffFailed => {
self.session
.msgbox("custom-error", "Privacy mode", "Failed to turn off");
}
back_notification::PrivacyModeState::PrvOffUnknown => {
self.session
.msgbox("custom-error", "Privacy mode", "Turned off");
// log::error!("Privacy mode is turned off with unknown reason");
self.update_privacy_mode(false);
}
_ => {}
}
true
}
async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool { async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool {
match data { match data {
Data::Close => { Data::Close => {

View File

@ -25,8 +25,12 @@ use clipboard::{
use enigo::{self, Enigo, KeyboardControllable}; use enigo::{self, Enigo, KeyboardControllable};
use hbb_common::{ use hbb_common::{
allow_err, allow_err,
config::{Config, LocalConfig, PeerConfig}, config::{Config, LocalConfig, PeerConfig, TransferSerde},
fs, log, fs::{
self, can_enable_overwrite_detection, get_job, get_string, new_send_confirm,
DigestCheckResult, RemoveJobMeta, TransferJobMeta,
},
get_version_number, log,
message_proto::{permission_info::Permission, *}, message_proto::{permission_info::Permission, *},
protobuf::Message as _, protobuf::Message as _,
rendezvous_proto::ConnType, rendezvous_proto::ConnType,
@ -38,14 +42,6 @@ use hbb_common::{
}, },
Stream, Stream,
}; };
use hbb_common::{config::TransferSerde, fs::TransferJobMeta};
use hbb_common::{
fs::{
can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult,
RemoveJobMeta,
},
get_version_number,
};
#[cfg(windows)] #[cfg(windows)]
use crate::clipboard_file::*; use crate::clipboard_file::*;
@ -2071,22 +2067,6 @@ impl Remote {
true true
} }
async fn send_opts_after_login(&self, peer: &mut Stream) {
if let Some(opts) = self
.handler
.lc
.read()
.unwrap()
.get_option_message_after_login()
{
let mut misc = Misc::new();
misc.set_option(opts);
let mut msg_out = Message::new();
msg_out.set_misc(misc);
allow_err!(peer.send(&msg_out).await);
}
}
async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool { async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool {
if let Ok(msg_in) = Message::parse_from_bytes(&data) { if let Ok(msg_in) = Message::parse_from_bytes(&data) {
match msg_in.union { match msg_in.union {
@ -2095,7 +2075,7 @@ impl Remote {
self.first_frame = true; self.first_frame = true;
self.handler.call2("closeSuccess", &make_args!()); self.handler.call2("closeSuccess", &make_args!());
self.handler.call("adaptSize", &make_args!()); self.handler.call("adaptSize", &make_args!());
self.send_opts_after_login(peer).await; common::send_opts_after_login(&self.handler.lc.read().unwrap(), peer).await;
} }
let incomming_format = CodecFormat::from(&vf); let incomming_format = CodecFormat::from(&vf);
if self.video_format != incomming_format { if self.video_format != incomming_format {