msgbox & translations

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-10-14 11:19:49 +08:00
parent 5ddb10366e
commit 77de0d05f9
42 changed files with 271 additions and 64 deletions

View File

@ -18,6 +18,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:window_size/window_size.dart' as window_size; import 'package:window_size/window_size.dart' as window_size;
import 'package:url_launcher/url_launcher.dart';
import 'common/widgets/overlay.dart'; import 'common/widgets/overlay.dart';
import 'mobile/pages/file_manager_page.dart'; import 'mobile/pages/file_manager_page.dart';
@ -618,8 +619,8 @@ class CustomAlertDialog extends StatelessWidget {
} }
} }
void msgBox( void msgBox(String type, String title, String text, String link,
String type, String title, String text, OverlayDialogManager dialogManager, OverlayDialogManager dialogManager,
{bool? hasCancel}) { {bool? hasCancel}) {
dialogManager.dismissAll(); dialogManager.dismissAll();
List<Widget> buttons = []; List<Widget> buttons = [];
@ -636,6 +637,12 @@ void msgBox(
dialogManager.dismissAll(); dialogManager.dismissAll();
} }
jumplink() {
if (link.startsWith('http')) {
launchUrl(Uri.parse(link));
}
}
if (type != "connecting" && type != "success" && !type.contains("nook")) { if (type != "connecting" && type != "success" && !type.contains("nook")) {
hasOk = true; hasOk = true;
buttons.insert(0, msgBoxButton(translate('OK'), submit)); buttons.insert(0, msgBoxButton(translate('OK'), submit));
@ -654,6 +661,9 @@ void msgBox(
dialogManager.dismissAll(); dialogManager.dismissAll();
})); }));
} }
if (link.isNotEmpty) {
buttons.insert(0, msgBoxButton(translate('JumpLink'), jumplink));
}
dialogManager.show((setState, close) => CustomAlertDialog( dialogManager.show((setState, close) => CustomAlertDialog(
title: _msgBoxTitle(title), title: _msgBoxTitle(title),
content: SelectableText(translate(text), content: SelectableText(translate(text),

View File

@ -414,7 +414,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
final root = await bind.mainIsRoot(); final root = await bind.mainIsRoot();
final release = await bind.mainIsRelease(); final release = await bind.mainIsRelease();
if (Platform.isWindows && release && !installed && !root) { if (Platform.isWindows && release && !installed && !root) {
msgBox('custom-elevation-nocancel', 'Prompt', 'elevation_prompt', msgBox('custom-elevation-nocancel', 'Prompt', 'elevation_prompt', '',
gFFI.dialogManager); gFFI.dialogManager);
} }
}); });

View File

@ -6,7 +6,7 @@ import '../../models/model.dart';
import '../../models/platform_model.dart'; import '../../models/platform_model.dart';
void clientClose(OverlayDialogManager dialogManager) { void clientClose(OverlayDialogManager dialogManager) {
msgBox('', 'Close', 'Are you sure to close the connection?', dialogManager); msgBox('', 'Close', 'Are you sure to close the connection?', '', dialogManager);
} }
void showSuccess() { void showSuccess() {

View File

@ -222,26 +222,27 @@ class FfiModel with ChangeNotifier {
handleMsgBox(Map<String, dynamic> evt, String id) { handleMsgBox(Map<String, dynamic> evt, String id) {
if (parent.target == null) return; if (parent.target == null) return;
final dialogManager = parent.target!.dialogManager; final dialogManager = parent.target!.dialogManager;
var type = evt['type']; final type = evt['type'];
var title = evt['title']; final title = evt['title'];
var text = evt['text']; final text = evt['text'];
final link = evt['link'];
if (type == 're-input-password') { if (type == 're-input-password') {
wrongPasswordDialog(id, dialogManager); wrongPasswordDialog(id, dialogManager);
} else if (type == 'input-password') { } else if (type == 'input-password') {
enterPasswordDialog(id, dialogManager); enterPasswordDialog(id, dialogManager);
} else if (type == 'restarting') { } else if (type == 'restarting') {
showMsgBox(id, type, title, text, false, dialogManager, hasCancel: false); showMsgBox(id, type, title, text, link, false, dialogManager, hasCancel: false);
} else { } else {
var hasRetry = evt['hasRetry'] == 'true'; var hasRetry = evt['hasRetry'] == 'true';
showMsgBox(id, type, title, text, hasRetry, dialogManager); showMsgBox(id, type, title, text, link, hasRetry, dialogManager);
} }
} }
/// Show a message box with [type], [title] and [text]. /// Show a message box with [type], [title] and [text].
showMsgBox(String id, String type, String title, String text, bool hasRetry, showMsgBox(String id, String type, String title, String text, String link,
OverlayDialogManager dialogManager, bool hasRetry, OverlayDialogManager dialogManager,
{bool? hasCancel}) { {bool? hasCancel}) {
msgBox(type, title, text, dialogManager, hasCancel: hasCancel); msgBox(type, title, text, link, dialogManager, hasCancel: hasCancel);
_timer?.cancel(); _timer?.cancel();
if (hasRetry) { if (hasRetry) {
_timer = Timer(Duration(seconds: _reconnects), () { _timer = Timer(Duration(seconds: _reconnects), () {

View File

@ -506,6 +506,19 @@ message AudioFrame {
int64 timestamp = 2; int64 timestamp = 2;
} }
// Notify peer to show message box.
message MessageBox {
// Message type. Refer to flutter/lib/commom.dart/msgBox().
string msgtype = 1;
string title = 2;
// English
string text = 3;
// If not empty, msgbox provides a button to following the link.
// The link here can't be directly http url.
// It must be the key of http url configed in peer side or "rustdesk://*" (jump in app).
string link = 4;
}
message BackNotification { message BackNotification {
// no need to consider block input by someone else // no need to consider block input by someone else
enum BlockInputState { enum BlockInputState {
@ -581,5 +594,6 @@ message Message {
FileResponse file_response = 18; FileResponse file_response = 18;
Misc misc = 19; Misc misc = 19;
Cliprdr cliprdr = 20; Cliprdr cliprdr = 20;
MessageBox message_box = 21;
} }
} }

View File

@ -53,11 +53,19 @@ lazy_static::lazy_static! {
static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load())); static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load()));
} }
// #[cfg(any(target_os = "android", target_os = "ios"))]
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref APP_DIR: Arc<RwLock<String>> = Default::default(); pub static ref APP_DIR: Arc<RwLock<String>> = Default::default();
pub static ref APP_HOME_DIR: Arc<RwLock<String>> = Default::default(); pub static ref APP_HOME_DIR: Arc<RwLock<String>> = Default::default();
} }
// #[cfg(any(target_os = "android", target_os = "ios"))]
lazy_static::lazy_static! {
pub static ref HELPER_URL: HashMap<&'static str, &'static str> = HashMap::from([
("rustdesk docs home", "https://rustdesk.com/docs/en/"),
("rustdesk docs x11-required", "https://rustdesk.com/docs/en/manual/linux/#x11-required"),
]);
}
const CHARS: &'static [char] = &[ const CHARS: &'static [char] = &[
'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',

View File

@ -48,7 +48,10 @@ pub use super::lang::*;
pub mod file_trait; pub mod file_trait;
pub mod helper; pub mod helper;
pub mod io_loop; pub mod io_loop;
use crate::ui_session_interface::global_save_keyboard_mode; use crate::{
server::video_service::{SCRAP_X11_REF_URL, SCRAP_X11_REQUIRED},
ui_session_interface::global_save_keyboard_mode,
};
pub static SERVER_KEYBOARD_ENABLED: AtomicBool = AtomicBool::new(true); pub static SERVER_KEYBOARD_ENABLED: AtomicBool = AtomicBool::new(true);
pub static SERVER_FILE_TRANSFER_ENABLED: AtomicBool = AtomicBool::new(true); pub static SERVER_FILE_TRANSFER_ENABLED: AtomicBool = AtomicBool::new(true);
pub static SERVER_CLIPBOARD_ENABLED: AtomicBool = AtomicBool::new(true); pub static SERVER_CLIPBOARD_ENABLED: AtomicBool = AtomicBool::new(true);
@ -1263,10 +1266,14 @@ impl LoginConfigHandler {
pub fn handle_login_error(&mut self, err: &str, interface: &impl Interface) -> bool { pub fn handle_login_error(&mut self, err: &str, interface: &impl Interface) -> bool {
if err == "Wrong Password" { if err == "Wrong Password" {
self.password = Default::default(); self.password = Default::default();
interface.msgbox("re-input-password", err, "Do you want to enter again?"); interface.msgbox("re-input-password", err, "Do you want to enter again?", "");
true true
} else { } else {
interface.msgbox("error", "Login Error", err); if err.contains(SCRAP_X11_REQUIRED) {
interface.msgbox("error", "Login Error", err, SCRAP_X11_REF_URL);
} else {
interface.msgbox("error", "Login Error", err, "");
}
false false
} }
} }
@ -1636,7 +1643,7 @@ pub async fn handle_hash(
if password.is_empty() { if password.is_empty() {
// login without password, the remote side can click accept // login without password, the remote side can click accept
send_login(lc.clone(), Vec::new(), peer).await; send_login(lc.clone(), Vec::new(), peer).await;
interface.msgbox("input-password", "Password Required", ""); interface.msgbox("input-password", "Password Required", "", "");
} else { } else {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(&password); hasher.update(&password);
@ -1689,7 +1696,7 @@ pub async fn handle_login_from_ui(
pub trait Interface: Send + Clone + 'static + Sized { pub trait Interface: Send + Clone + 'static + Sized {
/// Send message data to remote peer. /// Send message data to remote peer.
fn send(&self, data: Data); fn send(&self, data: Data);
fn msgbox(&self, msgtype: &str, title: &str, text: &str); fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str);
fn handle_login_error(&mut self, err: &str) -> bool; fn handle_login_error(&mut self, err: &str) -> bool;
fn handle_peer_info(&mut self, pi: PeerInfo); fn handle_peer_info(&mut self, pi: PeerInfo);
fn set_force_relay(&mut self, direct: bool, received: bool); fn set_force_relay(&mut self, direct: bool, received: bool);
@ -1697,7 +1704,7 @@ pub trait Interface: Send + Clone + 'static + Sized {
fn is_port_forward(&self) -> bool; fn is_port_forward(&self) -> bool;
fn is_rdp(&self) -> bool; fn is_rdp(&self) -> bool;
fn on_error(&self, err: &str) { fn on_error(&self, err: &str) {
self.msgbox("error", "Error", err); self.msgbox("error", "Error", err, "");
} }
fn is_force_relay(&self) -> bool; fn is_force_relay(&self) -> bool;
async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream); async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream);

View File

@ -119,7 +119,7 @@ impl<T: InvokeUiSession> Remote<T> {
Err(err) => { Err(err) => {
log::error!("Connection closed: {}", err); log::error!("Connection closed: {}", err);
self.handler.set_force_relay(direct, received); self.handler.set_force_relay(direct, received);
self.handler.msgbox("error", "Connection Error", &err.to_string()); self.handler.msgbox("error", "Connection Error", &err.to_string(), "");
break; break;
} }
Ok(ref bytes) => { Ok(ref bytes) => {
@ -134,10 +134,10 @@ impl<T: InvokeUiSession> Remote<T> {
} else { } else {
if self.handler.is_restarting_remote_device() { if self.handler.is_restarting_remote_device() {
log::info!("Restart remote device"); log::info!("Restart remote device");
self.handler.msgbox("restarting", "Restarting Remote Device", "remote_restarting_tip"); self.handler.msgbox("restarting", "Restarting Remote Device", "remote_restarting_tip", "");
} else { } else {
log::info!("Reset by the peer"); log::info!("Reset by the peer");
self.handler.msgbox("error", "Connection Error", "Reset by the peer"); self.handler.msgbox("error", "Connection Error", "Reset by the peer", "");
} }
break; break;
} }
@ -162,12 +162,12 @@ impl<T: InvokeUiSession> Remote<T> {
} }
_ = self.timer.tick() => { _ = self.timer.tick() => {
if last_recv_time.elapsed() >= SEC30 { if last_recv_time.elapsed() >= SEC30 {
self.handler.msgbox("error", "Connection Error", "Timeout"); self.handler.msgbox("error", "Connection Error", "Timeout", "");
break; break;
} }
if !self.read_jobs.is_empty() { if !self.read_jobs.is_empty() {
if let Err(err) = fs::handle_read_jobs(&mut self.read_jobs, &mut peer).await { if let Err(err) = fs::handle_read_jobs(&mut self.read_jobs, &mut peer).await {
self.handler.msgbox("error", "Connection Error", &err.to_string()); self.handler.msgbox("error", "Connection Error", &err.to_string(), "");
break; break;
} }
self.update_jobs_status(); self.update_jobs_status();
@ -191,7 +191,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
Err(err) => { Err(err) => {
self.handler self.handler
.msgbox("error", "Connection Error", &err.to_string()); .msgbox("error", "Connection Error", &err.to_string(), "");
} }
} }
if let Some(stop) = stop_clipboard { if let Some(stop) = stop_clipboard {
@ -971,7 +971,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
} }
Some(misc::Union::CloseReason(c)) => { Some(misc::Union::CloseReason(c)) => {
self.handler.msgbox("error", "Connection Error", &c); self.handler.msgbox("error", "Connection Error", &c, "");
return false; return false;
} }
Some(misc::Union::BackNotification(notification)) => { Some(misc::Union::BackNotification(notification)) => {
@ -981,8 +981,12 @@ impl<T: InvokeUiSession> Remote<T> {
} }
Some(misc::Union::Uac(uac)) => { Some(misc::Union::Uac(uac)) => {
if uac { if uac {
self.handler self.handler.msgbox(
.msgbox("custom-uac-nocancel", "Warning", "uac_warning"); "custom-uac-nocancel",
"Warning",
"uac_warning",
"",
);
} }
} }
Some(misc::Union::ForegroundWindowElevated(elevated)) => { Some(misc::Union::ForegroundWindowElevated(elevated)) => {
@ -991,6 +995,7 @@ impl<T: InvokeUiSession> Remote<T> {
"custom-elevated-foreground-nocancel", "custom-elevated-foreground-nocancel",
"Warning", "Warning",
"elevated_foreground_window_warning", "elevated_foreground_window_warning",
"",
); );
} }
} }
@ -1012,6 +1017,19 @@ impl<T: InvokeUiSession> Remote<T> {
} }
_ => {} _ => {}
}, },
Some(message::Union::MessageBox(msgbox)) => {
let mut link = msgbox.link;
if !link.starts_with("rustdesk://") {
if let Some(v) = hbb_common::config::HELPER_URL.get(&link as &str) {
link = v.to_string();
} else {
log::warn!("Message box ignore link {} for security", &link);
link = "".to_string();
}
}
self.handler
.msgbox(&msgbox.msgtype, &msgbox.title, &msgbox.text, &link);
}
_ => {} _ => {}
} }
} }
@ -1053,7 +1071,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
back_notification::BlockInputState::BlkOnFailed => { back_notification::BlockInputState::BlkOnFailed => {
self.handler self.handler
.msgbox("custom-error", "Block user input", "Failed"); .msgbox("custom-error", "Block user input", "Failed", "");
self.update_block_input_state(false); self.update_block_input_state(false);
} }
back_notification::BlockInputState::BlkOffSucceeded => { back_notification::BlockInputState::BlkOffSucceeded => {
@ -1061,7 +1079,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
back_notification::BlockInputState::BlkOffFailed => { back_notification::BlockInputState::BlkOffFailed => {
self.handler self.handler
.msgbox("custom-error", "Unblock user input", "Failed"); .msgbox("custom-error", "Unblock user input", "Failed", "");
} }
_ => {} _ => {}
} }
@ -1086,51 +1104,52 @@ impl<T: InvokeUiSession> Remote<T> {
"error", "error",
"Connecting...", "Connecting...",
"Someone turns on privacy mode, exit", "Someone turns on privacy mode, exit",
"",
); );
return false; return false;
} }
back_notification::PrivacyModeState::PrvNotSupported => { back_notification::PrivacyModeState::PrvNotSupported => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Unsupported"); .msgbox("custom-error", "Privacy mode", "Unsupported", "");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }
back_notification::PrivacyModeState::PrvOnSucceeded => { back_notification::PrivacyModeState::PrvOnSucceeded => {
self.handler self.handler
.msgbox("custom-nocancel", "Privacy mode", "In privacy mode"); .msgbox("custom-nocancel", "Privacy mode", "In privacy mode", "");
self.update_privacy_mode(true); self.update_privacy_mode(true);
} }
back_notification::PrivacyModeState::PrvOnFailedDenied => { back_notification::PrivacyModeState::PrvOnFailedDenied => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Peer denied"); .msgbox("custom-error", "Privacy mode", "Peer denied", "");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }
back_notification::PrivacyModeState::PrvOnFailedPlugin => { back_notification::PrivacyModeState::PrvOnFailedPlugin => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Please install plugins"); .msgbox("custom-error", "Privacy mode", "Please install plugins", "");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }
back_notification::PrivacyModeState::PrvOnFailed => { back_notification::PrivacyModeState::PrvOnFailed => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Failed"); .msgbox("custom-error", "Privacy mode", "Failed", "");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }
back_notification::PrivacyModeState::PrvOffSucceeded => { back_notification::PrivacyModeState::PrvOffSucceeded => {
self.handler self.handler
.msgbox("custom-nocancel", "Privacy mode", "Out privacy mode"); .msgbox("custom-nocancel", "Privacy mode", "Out privacy mode", "");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }
back_notification::PrivacyModeState::PrvOffByPeer => { back_notification::PrivacyModeState::PrvOffByPeer => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Peer exit"); .msgbox("custom-error", "Privacy mode", "Peer exit", "");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }
back_notification::PrivacyModeState::PrvOffFailed => { back_notification::PrivacyModeState::PrvOffFailed => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Failed to turn off"); .msgbox("custom-error", "Privacy mode", "Failed to turn off", "");
} }
back_notification::PrivacyModeState::PrvOffUnknown => { back_notification::PrivacyModeState::PrvOffUnknown => {
self.handler self.handler
.msgbox("custom-error", "Privacy mode", "Turned off"); .msgbox("custom-error", "Privacy mode", "Turned off", "");
// log::error!("Privacy mode is turned off with unknown reason"); // log::error!("Privacy mode is turned off with unknown reason");
self.update_privacy_mode(false); self.update_privacy_mode(false);
} }

View File

@ -1,5 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
future::Future,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -21,6 +22,8 @@ use hbb_common::{
// #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] // #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))]
use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all}; use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all};
pub type NotifyMessageBox = fn(String, String, String, String) -> dyn Future<Output = ()>;
pub const CLIPBOARD_NAME: &'static str = "clipboard"; pub const CLIPBOARD_NAME: &'static str = "clipboard";
pub const CLIPBOARD_INTERVAL: u64 = 333; pub const CLIPBOARD_INTERVAL: u64 = 333;
@ -44,8 +47,7 @@ pub fn global_init() -> bool {
true true
} }
pub fn global_clean() { pub fn global_clean() {}
}
#[inline] #[inline]
pub fn valid_for_numlock(evt: &KeyEvent) -> bool { pub fn valid_for_numlock(evt: &KeyEvent) -> bool {

View File

@ -310,7 +310,7 @@ impl InvokeUiSession for FlutterHandler {
); );
} }
fn msgbox(&self, msgtype: &str, title: &str, text: &str, retry: bool) { fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) {
let has_retry = if retry { "true" } else { "" }; let has_retry = if retry { "true" } else { "" };
self.push_event( self.push_event(
"msgbox", "msgbox",
@ -318,6 +318,7 @@ impl InvokeUiSession for FlutterHandler {
("type", msgtype), ("type", msgtype),
("title", title), ("title", title),
("text", text), ("text", text),
("link", link),
("hasRetry", has_retry), ("hasRetry", has_retry),
], ],
); );

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", "自定义"), ("Custom", "自定义"),
("Full Access", "完全访问"), ("Full Access", "完全访问"),
("Screen Share", "仅共享屏幕"), ("Screen Share", "仅共享屏幕"),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland 需要 Ubuntu 21.04 或更高版本。"),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 发行版。 请尝试 X11 桌面或更改您的操作系统。"),
("JumpLink", "查看"),
("Please Select the screen to be shared(Operate on the peer side).", "请选择要分享的画面(对端操作)。"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vyžaduje Ubuntu 21.04 nebo vyšší verzi."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vyžaduje vyšší verzi linuxové distribuce. Zkuste prosím X11 desktop nebo změňte OS."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Vyberte prosím obrazovku, kterou chcete sdílet (Ovládejte na straně protějšku)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland kræver Ubuntu 21.04 eller nyere version."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland kræver en højere version af linux distro. Prøv venligst X11 desktop eller skift dit OS."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Vælg venligst den skærm, der skal deles (Betjen på peer-siden)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland erfordert Ubuntu 21.04 oder eine höhere Version."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland erfordert eine höhere Version der Linux-Distribution. Bitte versuchen Sie den X11-Desktop oder ändern Sie Ihr Betriebssystem."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Bitte wählen Sie den Bildschirm aus, der freigegeben werden soll (auf der Peer-Seite arbeiten)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -33,5 +33,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", "Running software without privilege elevation may cause problems when remote users operate certain windows."), ("elevation_prompt", "Running software without privilege elevation may cause problems when remote users operate certain windows."),
("uac_warning", "Temporarily denied access due to elevation request, please wait for the remote user to accept the UAC dialog. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."), ("uac_warning", "Temporarily denied access due to elevation request, please wait for the remote user to accept the UAC dialog. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."),
("elevated_foreground_window_warning", "Temporarily unable to use the mouse and keyboard, because the current window of the remote desktop requires higher privilege to operate, you can request the remote user to minimize the current window. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."), ("elevated_foreground_window_warning", "Temporarily unable to use the mouse and keyboard, because the current window of the remote desktop requires higher privilege to operate, you can request the remote user to minimize the current window. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."),
("JumpLink", "View"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland postulas Ubuntu 21.04 aŭ pli altan version."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland postulas pli altan version de linuksa distro. Bonvolu provi X11-labortablon aŭ ŝanĝi vian OS."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Bonvolu Elekti la ekranon por esti dividita (Funkciu ĉe la sama flanko)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requiere Ubuntu 21.04 o una versión superior."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requiere una versión superior de la distribución de Linux. Pruebe el escritorio X11 o cambie su sistema operativo."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Seleccione la pantalla que se compartirá (Operar en el lado del compañero)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland nécessite Ubuntu 21.04 ou une version supérieure."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland nécessite une version supérieure de la distribution Linux. Veuillez essayer le bureau X11 ou changer votre système d'exploitation."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Veuillez sélectionner l'écran à partager (opérer du côté pair)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "A Waylandhoz Ubuntu 21.04 vagy újabb verzió szükséges."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "A Wayland a Linux disztró magasabb verzióját igényli. Próbálja ki az X11 desktopot, vagy változtassa meg az operációs rendszert."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Kérjük, válassza ki a megosztani kívánt képernyőt (a társoldalon működjön)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland membutuhkan Ubuntu 21.04 atau versi yang lebih tinggi."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland membutuhkan versi distro linux yang lebih tinggi. Silakan coba desktop X11 atau ubah OS Anda."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Silakan Pilih layar yang akan dibagikan (Operasi di sisi rekan)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland richiede Ubuntu 21.04 o versione successiva."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland richiede una versione superiore della distribuzione Linux. Prova X11 desktop o cambia il tuo sistema operativo."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Seleziona lo schermo da condividere (opera sul lato peer)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland には、Ubuntu 21.04 以降のバージョンが必要です。"),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland には、より高いバージョンの Linux ディストリビューションが必要です。 X11 デスクトップを試すか、OS を変更してください。"),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "共有する画面を選択してください(ピア側で操作)。"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland는 Ubuntu 21.04 이상 버전이 필요합니다."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland에는 더 높은 버전의 Linux 배포판이 필요합니다. X11 데스크탑을 시도하거나 OS를 변경하십시오."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "공유할 화면을 선택하십시오(피어 측에서 작동)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland Ubuntu 21.04 немесе одан жоғары нұсқасын қажет етеді."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland linux дистрибутивінің жоғарырақ нұсқасын қажет етеді. X11 жұмыс үстелін қолданып көріңіз немесе операциялық жүйеңізді өзгертіңіз."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Бөлісетін экранды таңдаңыз (бірдей жағынан жұмыс жасаңыз)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland wymaga Ubuntu 21.04 lub nowszego."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland wymaga wyższej wersji dystrybucji Linuksa. Wypróbuj pulpit X11 lub zmień system operacyjny."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Wybierz ekran do udostępnienia (działaj po stronie równorzędnej)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requer Ubuntu 21.04 ou versão superior."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Por favor, selecione a tela a ser compartilhada (operar no lado do peer)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", ""),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", ""),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland требует Ubuntu 21.04 или более позднюю версию."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Для Wayland требуется более поздняя версия дистрибутива Linux. Пожалуйста, попробуйте рабочий стол X11 или смените ОС."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Пожалуйста, выберите экран для совместного использования (работайте на одноранговой стороне)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vyžaduje Ubuntu 21.04 alebo vyššiu verziu."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vyžaduje vyššiu verziu linuxovej distribúcie. Skúste X11 desktop alebo zmeňte OS."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Vyberte obrazovku, ktorú chcete zdieľať (Ovládajte na strane partnera)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", ""),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", ""),
("JumpLink", ""),
("Please Select the screen to be shared(Operate on the peer side).", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland, Ubuntu 21.04 veya daha yüksek bir sürüm gerektirir."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland, linux dağıtımının daha yüksek bir sürümünü gerektirir. Lütfen X11 masaüstünü deneyin veya işletim sisteminizi değiştirin."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Lütfen paylaşılacak ekranı seçiniz (Ekran tarafında çalıştırın)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", "自定義"), ("Custom", "自定義"),
("Full Access", "完全訪問"), ("Full Access", "完全訪問"),
("Screen Share", "僅共享屏幕"), ("Screen Share", "僅共享屏幕"),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland 需要 Ubuntu 21.04 或更高版本。"),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 發行版。 請嘗試 X11 桌面或更改您的操作系統。"),
("JumpLink", "查看"),
("Please Select the screen to be shared(Operate on the peer side).", "請選擇要分享的畫面(在對端操作)。"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland потребує Ubuntu 21.04 або новішої версії."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Для Wayland потрібна новіша версія дистрибутива Linux. Будь ласка, спробуйте робочий стіл X11 або змініть свою ОС."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Будь ласка, виберіть екран, до якого потрібно надати доступ (працюйте на стороні однорангового пристрою)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", ""), ("Custom", ""),
("Full Access", ""), ("Full Access", ""),
("Screen Share", ""), ("Screen Share", ""),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland yêu cầu phiên bản Ubuntu 21.04 trở lên."),
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland yêu cầu phiên bản distro linux cao hơn. Vui lòng thử máy tính để bàn X11 hoặc thay đổi hệ điều hành của bạn."),
("JumpLink", "View"),
("Please Select the screen to be shared(Operate on the peer side).", "Vui lòng Chọn màn hình để chia sẻ (Hoạt động ở phía ngang hàng)."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -75,13 +75,13 @@ pub async fn listen(
let interface = interface.clone(); let interface = interface.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Err(err) = run_forward(forward, stream).await { if let Err(err) = run_forward(forward, stream).await {
interface.msgbox("error", "Error", &err.to_string()); interface.msgbox("error", "Error", &err.to_string(), "");
} }
log::info!("connection from {:?} closed", addr); log::info!("connection from {:?} closed", addr);
}); });
} }
Err(err) => { Err(err) => {
interface.msgbox("error", "Error", &err.to_string()); interface.msgbox("error", "Error", &err.to_string(), "");
} }
_ => {} _ => {}
} }

View File

@ -742,6 +742,10 @@ impl Connection {
res.set_peer_info(pi); res.set_peer_info(pi);
} else { } else {
try_activate_screen(); try_activate_screen();
if let Some(msg_out) = super::video_service::is_inited_msg() {
self.send(msg_out).await;
}
match super::video_service::get_displays().await { match super::video_service::get_displays().await {
Err(err) => { Err(err) => {
res.set_error(format!("Error: {}", err)); res.set_error(format!("Error: {}", err));

View File

@ -39,6 +39,12 @@ use std::{
#[cfg(windows)] #[cfg(windows)]
use virtual_display; use virtual_display;
pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version.";
pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str =
"Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.";
pub const SCRAP_X11_REQUIRED: &str = "x11 expected";
pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
pub const NAME: &'static str = "video"; pub const NAME: &'static str = "video";
lazy_static::lazy_static! { lazy_static::lazy_static! {
@ -747,6 +753,14 @@ pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
(*lock, displays) (*lock, displays)
} }
pub fn is_inited_msg() -> Option<Message> {
#[cfg(target_os = "linux")]
if !scrap::is_x11() {
return super::wayland::is_inited();
}
None
}
pub async fn get_displays() -> ResultType<(usize, Vec<DisplayInfo>)> { pub async fn get_displays() -> ResultType<(usize, Vec<DisplayInfo>)> {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {

View File

@ -3,11 +3,9 @@ use hbb_common::{allow_err, platform::linux::DISTRO};
use scrap::{set_map_err, Capturer, Display, Frame, TraitCapturer}; use scrap::{set_map_err, Capturer, Display, Frame, TraitCapturer};
use std::io; use std::io;
pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; use super::video_service::{
pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = SCRAP_OTHER_VERSION_OR_X11_REQUIRED, SCRAP_UBUNTU_HIGHER_REQUIRED, SCRAP_X11_REQUIRED,
"Wayland requires higher version of linux distro. Please try X11 desktop or change your OS."; };
pub const SCRAP_X11_REQUIRED: &str = "X11 is required";
pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref CAP_DISPLAY_INFO: RwLock<u64> = RwLock::new(0); static ref CAP_DISPLAY_INFO: RwLock<u64> = RwLock::new(0);
@ -26,7 +24,10 @@ fn map_err_scrap(err: String) -> io::Error {
// std::process::exit(-1); // std::process::exit(-1);
// } // }
log::error!("REMOVE ME ===================================== wayland scrap error {}", &err); log::error!(
"REMOVE ME ===================================== wayland scrap error {}",
&err
);
if DISTRO.name.to_uppercase() == "Ubuntu".to_uppercase() { if DISTRO.name.to_uppercase() == "Ubuntu".to_uppercase() {
if DISTRO.version_id < "21".to_owned() { if DISTRO.version_id < "21".to_owned() {
@ -93,6 +94,27 @@ pub(super) async fn ensure_inited() -> ResultType<()> {
check_init().await check_init().await
} }
pub(super) fn is_inited() -> Option<Message> {
if scrap::is_x11() {
None
} else {
if *CAP_DISPLAY_INFO.read().unwrap() == 0 {
let mut msg_out = Message::new();
let res = MessageBox {
msgtype: "nook-nocancel-hasclose".to_owned(),
title: "Wayland".to_owned(),
text: "Please Select the screen to be shared(Operate on the peer side).".to_owned(),
link: "".to_owned(),
..Default::default()
};
msg_out.set_message_box(res);
Some(msg_out)
} else {
None
}
}
}
async fn check_init() -> ResultType<()> { async fn check_init() -> ResultType<()> {
if !scrap::is_x11() { if !scrap::is_x11() {
let mut minx = 0; let mut minx = 0;

View File

@ -232,7 +232,7 @@ class ChatBox: Reactor.Component {
/******************** start of msgbox ****************************************/ /******************** start of msgbox ****************************************/
var remember_password = false; var remember_password = false;
function msgbox(type, title, content, callback=null, height=180, width=500, hasRetry=false, contentStyle="") { function msgbox(type, title, content, link, callback=null, height=180, width=500, hasRetry=false, contentStyle="") {
$(body).scrollTo(0, 0); $(body).scrollTo(0, 0);
if (!type) { if (!type) {
closeMsgbox(); closeMsgbox();
@ -264,21 +264,21 @@ function msgbox(type, title, content, callback=null, height=180, width=500, hasR
} else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) { } else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) {
callback = function() { view.close(); } callback = function() { view.close(); }
} }
$(#msgbox).content(<MsgboxComponent width={width} height={height} auto_login={auto_login} type={type} title={title} content={content} remember={remember} callback={callback} contentStyle={contentStyle} hasRetry={hasRetry} />); $(#msgbox).content(<MsgboxComponent width={width} height={height} auto_login={auto_login} type={type} title={title} content={content} link={link} remember={remember} callback={callback} contentStyle={contentStyle} hasRetry={hasRetry} />);
} }
function connecting() { function connecting() {
handler.msgbox("connecting", "Connecting...", "Connection in progress. Please wait."); handler.msgbox("connecting", "Connecting...", "Connection in progress. Please wait.");
} }
handler.msgbox = function(type, title, text, hasRetry=false) { handler.msgbox = function(type, title, text, link = "", hasRetry=false) {
// crash somehow (when input wrong password), even with small time, for example, 1ms // crash somehow (when input wrong password), even with small time, for example, 1ms
self.timer(60ms, function() { msgbox(type, title, text, null, 180, 500, hasRetry); }); self.timer(60ms, function() { msgbox(type, title, text, link, null, 180, 500, hasRetry); });
} }
var reconnectTimeout = 1000; var reconnectTimeout = 1000;
handler.msgbox_retry = function(type, title, text, hasRetry) { handler.msgbox_retry = function(type, title, text, link, hasRetry) {
handler.msgbox(type, title, text, hasRetry); handler.msgbox(type, title, text, link, hasRetry);
if (hasRetry) { if (hasRetry) {
self.timer(0, retryConnect); self.timer(0, retryConnect);
self.timer(reconnectTimeout, retryConnect); self.timer(reconnectTimeout, retryConnect);

View File

@ -1,3 +1,5 @@
import * as env from "@env";
function translate_text(text) { function translate_text(text) {
if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) { if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) {
var fds = text.split(': '); var fds = text.split(': ');
@ -22,6 +24,7 @@ class MsgboxComponent: Reactor.Component {
this.type = params.type; this.type = params.type;
this.title = params.title; this.title = params.title;
this.content = params.content; this.content = params.content;
this.link = params.link;
this.remember = params.remember; this.remember = params.remember;
this.callback = params.callback; this.callback = params.callback;
this.hasRetry = params.hasRetry; this.hasRetry = params.hasRetry;
@ -93,6 +96,7 @@ class MsgboxComponent: Reactor.Component {
var content = this.getContent(); var content = this.getContent();
var hasCancel = this.type.indexOf("error") < 0 && this.type.indexOf("nocancel") < 0 && this.type != "restarting"; var hasCancel = this.type.indexOf("error") < 0 && this.type.indexOf("nocancel") < 0 && this.type != "restarting";
var hasOk = this.type != "connecting" && this.type != "success" && this.type.indexOf("nook") < 0; var hasOk = this.type != "connecting" && this.type != "success" && this.type.indexOf("nook") < 0;
var hasLink = this.link != "";
var hasClose = this.type.indexOf("hasclose") >= 0; var hasClose = this.type.indexOf("hasclose") >= 0;
var show_progress = this.type == "connecting"; var show_progress = this.type == "connecting";
var me = this; var me = this;
@ -121,6 +125,7 @@ class MsgboxComponent: Reactor.Component {
{hasCancel || this.hasRetry ? <button .button #cancel .outline>{translate(this.hasRetry ? "OK" : "Cancel")}</button> : ""} {hasCancel || this.hasRetry ? <button .button #cancel .outline>{translate(this.hasRetry ? "OK" : "Cancel")}</button> : ""}
{this.hasSkip() ? <button .button #skip .outline>{translate('Skip')}</button> : ""} {this.hasSkip() ? <button .button #skip .outline>{translate('Skip')}</button> : ""}
{hasOk || this.hasRetry ? <button .button #submit>{translate(this.hasRetry ? "Retry" : "OK")}</button> : ""} {hasOk || this.hasRetry ? <button .button #submit>{translate(this.hasRetry ? "Retry" : "OK")}</button> : ""}
{hasLink ? <button .button #jumplink .outline>{translate('JumpLink')}</button> : ""}
{hasClose ? <button .button #cancel .outline>{translate('Close')}</button> : ""} {hasClose ? <button .button #cancel .outline>{translate('Close')}</button> : ""}
</div> </div>
</div> </div>
@ -156,6 +161,13 @@ class MsgboxComponent: Reactor.Component {
if (this.close) this.close(); if (this.close) this.close();
} }
event click $(button#jumplink) {
stdout.println("REMOVE ME ================================= jump link" + this.link);
if (this.link.indexOf("http") == 0) {
env.launch(this.link);
}
}
event click $(button#submit) { event click $(button#submit) {
if (this.type == "error") { if (this.type == "error") {
if (this.hasRetry) { if (this.hasRetry) {

View File

@ -238,8 +238,8 @@ impl InvokeUiSession for SciterHandler {
self.call("updatePi", &make_args!(pi_sciter)); self.call("updatePi", &make_args!(pi_sciter));
} }
fn msgbox(&self, msgtype: &str, title: &str, text: &str, retry: bool) { fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) {
self.call2("msgbox_retry", &make_args!(msgtype, title, text, retry)); self.call2("msgbox_retry", &make_args!(msgtype, title, text, link, retry));
} }
fn new_message(&self, msg: String) { fn new_message(&self, msg: String) {

View File

@ -1088,7 +1088,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn job_progress(&self, id: i32, file_num: i32, speed: f64, finished_size: f64); fn job_progress(&self, id: i32, file_num: i32, speed: f64, finished_size: f64);
fn adapt_size(&self); fn adapt_size(&self);
fn on_rgba(&self, data: &[u8]); fn on_rgba(&self, data: &[u8]);
fn msgbox(&self, msgtype: &str, title: &str, text: &str, retry: bool); fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool);
#[cfg(any(target_os = "android", target_os = "ios"))] #[cfg(any(target_os = "android", target_os = "ios"))]
fn clipboard(&self, content: String); fn clipboard(&self, content: String);
} }
@ -1137,9 +1137,9 @@ impl<T: InvokeUiSession> Interface for Session<T> {
self.lc.read().unwrap().conn_type.eq(&ConnType::RDP) self.lc.read().unwrap().conn_type.eq(&ConnType::RDP)
} }
fn msgbox(&self, msgtype: &str, title: &str, text: &str) { fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str) {
let retry = check_if_retry(msgtype, title, text); let retry = check_if_retry(msgtype, title, text);
self.ui_handler.msgbox(msgtype, title, text, retry); self.ui_handler.msgbox(msgtype, title, text, link, retry);
} }
fn handle_login_error(&mut self, err: &str) -> bool { fn handle_login_error(&mut self, err: &str) -> bool {
@ -1164,7 +1164,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
if pi.displays.is_empty() { if pi.displays.is_empty() {
self.lc.write().unwrap().handle_peer_info(&pi); self.lc.write().unwrap().handle_peer_info(&pi);
self.update_privacy_mode(); self.update_privacy_mode();
self.msgbox("error", "Remote Error", "No Display"); self.msgbox("error", "Remote Error", "No Display", "");
return; return;
} }
let p = self.lc.read().unwrap().should_auto_login(); let p = self.lc.read().unwrap().should_auto_login();
@ -1181,7 +1181,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
if self.is_file_transfer() { if self.is_file_transfer() {
self.close_success(); self.close_success();
} else if !self.is_port_forward() { } else if !self.is_port_forward() {
self.msgbox("success", "Successful", "Connected, waiting for image..."); self.msgbox("success", "Successful", "Connected, waiting for image...", "");
} }
#[cfg(windows)] #[cfg(windows)]
{ {