Merge pull request #5654 from 21pages/tray

translate placeholder && tray tooltip and pull up
This commit is contained in:
RustDesk 2023-09-13 13:10:37 +08:00 committed by GitHub
commit 9e3f0304de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 203 additions and 20 deletions

View File

@ -404,7 +404,7 @@ pub fn core_main() -> Option<Vec<String>> {
crate::ui_interface::start_option_status_sync();
} else if args[0] == "--cm-no-ui" {
#[cfg(feature = "flutter")]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
#[cfg(not(any(target_os = "android", target_os = "ios", target_os = "windows")))]
crate::flutter::connection_manager::start_cm_no_ui();
return None;
} else {

View File

@ -157,6 +157,7 @@ fn handle_config_options(config_options: HashMap<String, String>) {
Config::set_options(options);
}
#[allow(unused)]
#[cfg(not(any(target_os = "ios")))]
pub fn is_pro() -> bool {
PRO.lock().unwrap().clone()

View File

@ -234,6 +234,8 @@ pub enum Data {
#[cfg(windows)]
SyncWinCpuUsage(Option<f64>),
FileTransferLog(String),
#[cfg(any(windows, target_os = "macos"))]
ControlledSessionCount(usize),
}
#[tokio::main(flavor = "current_thread")]
@ -482,6 +484,16 @@ async fn handle(data: Data, stream: &mut Connection) {
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
Data::Plugin(plugin) => crate::plugin::ipc::handle_plugin(plugin, stream).await,
#[cfg(any(windows, target_os = "macos"))]
Data::ControlledSessionCount(_) => {
allow_err!(
stream
.send(&Data::ControlledSessionCount(
crate::Connection::alive_conns().len()
))
.await
);
}
_ => {}
}
}

View File

@ -1,5 +1,7 @@
use hbb_common::regex::Regex;
use std::ops::Deref;
mod ar;
mod ca;
mod cn;
mod cs;
@ -17,6 +19,7 @@ mod it;
mod ja;
mod ko;
mod kz;
mod lt;
mod nl;
mod pl;
mod ptbr;
@ -32,8 +35,6 @@ mod tr;
mod tw;
mod ua;
mod vn;
mod lt;
mod ar;
pub const LANGS: &[(&str, &str)] = &[
("en", "English"),
@ -137,16 +138,67 @@ pub fn translate_locale(name: String, locale: &str) -> String {
"ar" => ar::T.deref(),
_ => en::T.deref(),
};
let (name, placeholder_value) = extract_placeholder(&name);
let replace = |s: &&str| {
let mut s = s.to_string();
if let Some(value) = placeholder_value.as_ref() {
s = s.replace("{}", &value);
}
s
};
if let Some(v) = m.get(&name as &str) {
if v.is_empty() {
if lang != "en" {
if let Some(v) = en::T.get(&name as &str) {
return v.to_string();
return replace(v);
}
}
} else {
return v.to_string();
return replace(v);
}
}
name
replace(&name.as_str())
}
// Matching pattern is {}
// Write {value} in the UI and {} in the translation file
//
// Example:
// Write in the UI: translate("There are {24} hours in a day")
// Write in the translation file: ("There are {} hours in a day", "{} hours make up a day")
fn extract_placeholder(input: &str) -> (String, Option<String>) {
if let Ok(re) = Regex::new(r#"\{(.*?)\}"#) {
if let Some(captures) = re.captures(input) {
if let Some(inner_match) = captures.get(1) {
let name = re.replace(input, "{}").to_string();
let value = inner_match.as_str().to_string();
return (name, Some(value));
}
}
}
(input.to_string(), None)
}
mod test {
#[test]
fn test_extract_placeholders() {
use super::extract_placeholder as f;
assert_eq!(f(""), ("".to_string(), None));
assert_eq!(
f("{3} sessions"),
("{} sessions".to_string(), Some("3".to_string()))
);
assert_eq!(f(" } { "), (" } { ".to_string(), None));
// Allow empty value
assert_eq!(
f("{} sessions"),
("{} sessions".to_string(), Some("".to_string()))
);
// Match only the first one
assert_eq!(
f("{2} times {4} makes {8}"),
("{} times {4} makes {8}".to_string(), Some("2".to_string()))
);
}
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "安装成功!"),
("Installation failed!", "安装失败!"),
("Reverse mouse wheel", "鼠标滚轮反向"),
("{} sessions", "{}个会话"),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "Installation erfolgreich!"),
("Installation failed!", "Installation fehlgeschlagen!"),
("Reverse mouse wheel", "Mausrad rückwärts drehen"),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "Instalación exitosa"),
("Installation failed!", "La instalación ha fallado"),
("Reverse mouse wheel", "Invertir rueda del ratón"),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "Instalasi berhasil!"),
("Installation failed!", "Instalasi gagal!"),
("Reverse mouse wheel", "Balikkan arah scroll mouse!"),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "Installazione completata"),
("Installation failed!", "Installazione fallita"),
("Reverse mouse wheel", "Rotella mouse inversa"),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "Instalacja zakończona!"),
("Installation failed!", "Instalacja nie powiodła się"),
("Reverse mouse wheel", "Odwróć rolkę myszki"),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", "Установка выполнена успешно!"),
("Installation failed!", "Установка не выполнена!"),
("Reverse mouse wheel", "Реверсировать колесо мыши"),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -544,5 +544,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Installation Successful!", ""),
("Installation failed!", ""),
("Reverse mouse wheel", ""),
("{} sessions", ""),
].iter().cloned().collect();
}

View File

@ -1351,6 +1351,12 @@ impl Connection {
log::error!("ipc to connection manager exit: {}", err);
}
});
#[cfg(all(windows, feature = "flutter"))]
std::thread::spawn(|| {
if crate::is_server() && !crate::check_process("--tray", false) {
crate::platform::run_as_user(vec!["--tray"]).ok();
}
});
}
}
@ -2406,7 +2412,10 @@ async fn start_ipc(
if let Ok(s) = crate::ipc::connect(1000, "_cm").await {
stream = Some(s);
} else {
#[allow(unused_mut)]
#[allow(unused_assignments)]
let mut args = vec!["--cm"];
#[cfg(not(windows))]
if crate::hbbs_http::sync::is_pro() && password::hide_cm() {
args.push("--hide");
}

View File

@ -1,5 +1,11 @@
use crate::{client::translate, ipc::Data};
use hbb_common::{allow_err, log, tokio};
use std::{
sync::{Arc, Mutex},
time::Duration,
};
pub fn start_tray() {
use hbb_common::{allow_err, log};
allow_err!(make_tray());
}
@ -40,29 +46,42 @@ pub fn make_tray() -> hbb_common::ResultType<()> {
let event_loop = EventLoopBuilder::new().build();
let tray_menu = Menu::new();
let quit_i = MenuItem::new(crate::client::translate("Exit".to_owned()), true, None);
let open_i = MenuItem::new(crate::client::translate("Open".to_owned()), true, None);
let quit_i = MenuItem::new(translate("Exit".to_owned()), true, None);
let open_i = MenuItem::new(translate("Open".to_owned()), true, None);
tray_menu.append_items(&[&open_i, &quit_i]);
let _tray_icon = Some(
TrayIconBuilder::new()
.with_menu(Box::new(tray_menu))
.with_tooltip(format!(
let tooltip = |count: usize| {
if count == 0 {
format!(
"{} {}",
crate::get_app_name(),
crate::lang::translate("Service is running".to_owned())
))
translate("Service is running".to_owned()),
)
} else {
format!(
"{} - {}\n{}",
crate::get_app_name(),
translate("Ready".to_owned()),
translate("{".to_string() + &format!("{count}") + "} sessions"),
)
}
};
let tray_icon = Some(
TrayIconBuilder::new()
.with_menu(Box::new(tray_menu))
.with_tooltip(tooltip(0))
.with_icon(icon)
.build()?,
);
let tray_icon = Arc::new(Mutex::new(tray_icon));
let menu_channel = MenuEvent::receiver();
let tray_channel = TrayEvent::receiver();
#[cfg(not(target_os = "linux"))]
let (ipc_sender, ipc_receiver) = std::sync::mpsc::channel::<Data>();
let mut docker_hiden = false;
let open_func = move || {
if cfg!(not(feature = "flutter"))
{
if cfg!(not(feature = "flutter")) {
crate::run_me::<&str>(vec![]).ok();
return;
}
@ -89,6 +108,11 @@ pub fn make_tray() -> hbb_common::ResultType<()> {
}
};
// ubuntu 22.04 can't see tooltip
#[cfg(not(target_os = "linux"))]
std::thread::spawn(move || {
start_query_session_count(ipc_sender.clone());
});
event_loop.run(move |_event, _, control_flow| {
if !docker_hiden {
#[cfg(target_os = "macos")]
@ -121,5 +145,55 @@ pub fn make_tray() -> hbb_common::ResultType<()> {
open_func();
}
}
#[cfg(not(target_os = "linux"))]
if let Ok(data) = ipc_receiver.try_recv() {
match data {
Data::ControlledSessionCount(count) => {
tray_icon
.lock()
.unwrap()
.as_mut()
.map(|t| t.set_tooltip(Some(tooltip(count))));
}
_ => {}
}
}
});
}
#[cfg(not(target_os = "linux"))]
#[tokio::main(flavor = "current_thread")]
async fn start_query_session_count(sender: std::sync::mpsc::Sender<Data>) {
let mut last_count = 0;
loop {
if let Ok(mut c) = crate::ipc::connect(1000, "").await {
let mut timer = tokio::time::interval(Duration::from_secs(1));
loop {
tokio::select! {
res = c.next() => {
match res {
Err(err) => {
log::error!("ipc connection closed: {}", err);
break;
}
Ok(Some(Data::ControlledSessionCount(count))) => {
if count != last_count {
last_count = count;
sender.send(Data::ControlledSessionCount(count)).ok();
}
}
_ => {}
}
}
_ = timer.tick() => {
c.send(&Data::ControlledSessionCount(0)).await.ok();
}
}
}
}
hbb_common::sleep(1.).await;
}
}