From 86cc71f4d23fe76aa9e586442ffbcc4737e953ff Mon Sep 17 00:00:00 2001 From: csf Date: Sat, 30 Jul 2022 13:51:06 +0800 Subject: [PATCH 01/33] opt: mobile UI --- flutter/lib/models/file_model.dart | 1 + flutter/lib/pages/file_manager_page.dart | 1 + flutter/lib/pages/settings_page.dart | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index e4afc892f..4a96e6e73 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -199,6 +199,7 @@ class FileModel extends ChangeNotifier { onClose() { SmartDialog.dismiss(); + jobReset(); // save config Map msg = Map(); diff --git a/flutter/lib/pages/file_manager_page.dart b/flutter/lib/pages/file_manager_page.dart index 2cb980f44..7e9c39a4e 100644 --- a/flutter/lib/pages/file_manager_page.dart +++ b/flutter/lib/pages/file_manager_page.dart @@ -28,6 +28,7 @@ class _FileManagerPageState extends State { void initState() { super.initState(); FFI.connect(widget.id, isFileTransfer: true); + showLoading(translate('Connecting...')); FFI.ffiModel.updateEventListener(widget.id); Wakelock.enable(); } diff --git a/flutter/lib/pages/settings_page.dart b/flutter/lib/pages/settings_page.dart index 30eb88b7b..ea92a72ca 100644 --- a/flutter/lib/pages/settings_page.dart +++ b/flutter/lib/pages/settings_page.dart @@ -26,11 +26,11 @@ class SettingsPage extends StatefulWidget implements PageShape { _SettingsState createState() => _SettingsState(); } -class _SettingsState extends State with WidgetsBindingObserver { - static const url = 'https://rustdesk.com/'; - final _hasIgnoreBattery = androidVersion >= 26; - var _ignoreBatteryOpt = false; +const url = 'https://rustdesk.com/'; +final _hasIgnoreBattery = androidVersion >= 26; +var _ignoreBatteryOpt = false; +class _SettingsState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); From e53119a01a0a4be043e56f9970db834a3837d45b Mon Sep 17 00:00:00 2001 From: csf Date: Sat, 30 Jul 2022 21:12:08 +0800 Subject: [PATCH 02/33] add mobile quality monitor --- flutter/lib/models/model.dart | 41 +++++ flutter/lib/pages/remote_page.dart | 45 +++++ src/client/helper.rs | 14 +- src/mobile.rs | 279 ++++++++++++++++++----------- src/ui/remote.rs | 9 - 5 files changed, 272 insertions(+), 116 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 2f6007400..7255c6baa 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -162,6 +162,8 @@ class FfiModel with ChangeNotifier { FFI.serverModel.onClientAuthorized(evt); } else if (name == 'on_client_remove') { FFI.serverModel.onClientRemove(evt); + } else if (name == 'update_quality_status') { + FFI.qualityMonitorModel.updateQualityStatus(evt); } }; PlatformFFI.setEventCallback(cb); @@ -655,6 +657,44 @@ class CursorModel with ChangeNotifier { } } +class QualityMonitorData { + String? speed; + String? fps; + String? delay; + String? targetBitrate; + String? codecFormat; +} + +class QualityMonitorModel with ChangeNotifier { + var _show = FFI.getByName('toggle_option', 'show-quality-monitor') == 'true'; + final _data = QualityMonitorData(); + + bool get show => _show; + QualityMonitorData get data => _data; + + checkShowQualityMonitor() { + final show = + FFI.getByName('toggle_option', 'show-quality-monitor') == 'true'; + if (_show != show) { + _show = show; + notifyListeners(); + } + } + + updateQualityStatus(Map evt) { + try { + if ((evt["speed"] as String).isNotEmpty) _data.speed = evt["speed"]; + if ((evt["fps"] as String).isNotEmpty) _data.fps = evt["fps"]; + if ((evt["delay"] as String).isNotEmpty) _data.delay = evt["delay"]; + if ((evt["target_bitrate"] as String).isNotEmpty) + _data.targetBitrate = evt["target_bitrate"]; + if ((evt["codec_format"] as String).isNotEmpty) + _data.codecFormat = evt["codec_format"]; + notifyListeners(); + } catch (e) {} + } +} + enum MouseButtons { left, right, wheel } extension ToString on MouseButtons { @@ -684,6 +724,7 @@ class FFI { static final serverModel = ServerModel(); static final chatModel = ChatModel(); static final fileModel = FileModel(); + static final qualityMonitorModel = QualityMonitorModel(); static String getId() { return getByName('remote_id'); diff --git a/flutter/lib/pages/remote_page.dart b/flutter/lib/pages/remote_page.dart index 265222837..bb196f0cf 100644 --- a/flutter/lib/pages/remote_page.dart +++ b/flutter/lib/pages/remote_page.dart @@ -592,6 +592,7 @@ class _RemotePageState extends State { child: Stack(children: [ ImagePaint(), CursorPaint(), + QualityMonitor(), getHelpTools(), SizedBox( width: 0, @@ -948,6 +949,47 @@ class ImagePainter extends CustomPainter { } } +class QualityMonitor extends StatelessWidget { + @override + Widget build(BuildContext context) => ChangeNotifierProvider.value( + value: FFI.qualityMonitorModel, + child: Consumer( + builder: (context, qualityMonitorModel, child) => Positioned( + top: 10, + right: 10, + child: qualityMonitorModel.show + ? Container( + padding: EdgeInsets.all(8), + color: MyTheme.canvasColor.withAlpha(120), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Speed: ${qualityMonitorModel.data.speed}", + style: TextStyle(color: MyTheme.grayBg), + ), + Text( + "FPS: ${qualityMonitorModel.data.fps}", + style: TextStyle(color: MyTheme.grayBg), + ), + Text( + "Delay: ${qualityMonitorModel.data.delay} ms", + style: TextStyle(color: MyTheme.grayBg), + ), + Text( + "Target Bitrate: ${qualityMonitorModel.data.targetBitrate}kb", + style: TextStyle(color: MyTheme.grayBg), + ), + Text( + "Codec: ${qualityMonitorModel.data.codecFormat}", + style: TextStyle(color: MyTheme.grayBg), + ), + ], + ), + ) + : SizedBox.shrink()))); +} + CheckboxListTile getToggle( void Function(void Function()) setState, option, name) { return CheckboxListTile( @@ -956,6 +998,9 @@ CheckboxListTile getToggle( setState(() { FFI.setByName('toggle_option', option); }); + if (option == "show-quality-monitor") { + FFI.qualityMonitorModel.checkShowQualityMonitor(); + } }, dense: true, title: Text(translate(name))); diff --git a/src/client/helper.rs b/src/client/helper.rs index 26dc37ba4..5274a7c55 100644 --- a/src/client/helper.rs +++ b/src/client/helper.rs @@ -3,7 +3,10 @@ use std::{ time::Instant, }; -use hbb_common::{log, message_proto::{VideoFrame, video_frame}}; +use hbb_common::{ + log, + message_proto::{video_frame, VideoFrame}, +}; const MAX_LATENCY: i64 = 500; const MIN_LATENCY: i64 = 100; @@ -87,3 +90,12 @@ impl ToString for CodecFormat { } } } + +#[derive(Debug, Default)] +pub struct QualityStatus { + pub speed: Option, + pub fps: Option, + pub delay: Option, + pub target_bitrate: Option, + pub codec_format: Option, +} diff --git a/src/mobile.rs b/src/mobile.rs index b21618d46..a8777cf39 100644 --- a/src/mobile.rs +++ b/src/mobile.rs @@ -1,12 +1,16 @@ use crate::client::*; -use crate::common::{make_fd_to_json}; +use crate::common::make_fd_to_json; use flutter_rust_bridge::{StreamSink, ZeroCopyBuffer}; use hbb_common::{ allow_err, compress::decompress, config::{Config, LocalConfig}, - fs, log, - fs::{can_enable_overwrite_detection, new_send_confirm, DigestCheckResult, get_string, transform_windows_path}, + fs, + fs::{ + can_enable_overwrite_detection, get_string, new_send_confirm, transform_windows_path, + DigestCheckResult, + }, + log, message_proto::*, protobuf::Message as _, rendezvous_proto::ConnType, @@ -17,6 +21,7 @@ use hbb_common::{ }, Stream, }; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::{ collections::{HashMap, VecDeque}, sync::{Arc, Mutex, RwLock}, @@ -397,6 +402,26 @@ impl Session { log::debug!("{:?}", msg_out); self.send_msg(msg_out); } + + fn update_quality_status(&self, status: QualityStatus) { + const NULL: String = String::new(); + self.push_event( + "update_quality_status", + vec![ + ("speed", &status.speed.map_or(NULL, |it| it)), + ("fps", &status.fps.map_or(NULL, |it| it.to_string())), + ("delay", &status.delay.map_or(NULL, |it| it.to_string())), + ( + "target_bitrate", + &status.target_bitrate.map_or(NULL, |it| it.to_string()), + ), + ( + "codec_format", + &status.codec_format.map_or(NULL, |it| it.to_string()), + ), + ], + ); + } } impl FileManager for Session {} @@ -438,7 +463,11 @@ impl Interface for Session { if lc.is_file_transfer { if pi.username.is_empty() { - self.msgbox("error", "Error", "No active console user logged on, please connect and logon first."); + self.msgbox( + "error", + "Error", + "No active console user logged on, please connect and logon first.", + ); return; } } else { @@ -487,7 +516,14 @@ impl Interface for Session { } async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream) { - handle_test_delay(t, peer).await; + if !t.from_client { + self.update_quality_status(QualityStatus { + delay: Some(t.last_delay as _), + target_bitrate: Some(t.target_bitrate as _), + ..Default::default() + }); + handle_test_delay(t, peer).await; + } } } @@ -502,6 +538,9 @@ struct Connection { write_jobs: Vec, timer: Interval, last_update_jobs_status: (Instant, HashMap), + data_count: Arc, + frame_count: Arc, + video_format: CodecFormat, } impl Connection { @@ -528,6 +567,9 @@ impl Connection { write_jobs: Vec::new(), timer: time::interval(SEC30), last_update_jobs_status: (Instant::now(), Default::default()), + data_count: Arc::new(AtomicUsize::new(0)), + frame_count: Arc::new(AtomicUsize::new(0)), + video_format: CodecFormat::Unknown, }; let key = Config::get_option("key"); let token = Config::get_option("access_token"); @@ -541,6 +583,9 @@ impl Connection { ("direct", &direct.to_string()), ], ); + + let mut status_timer = time::interval(Duration::new(1, 0)); + loop { tokio::select! { res = peer.next() => { @@ -553,6 +598,7 @@ impl Connection { } Ok(ref bytes) => { last_recv_time = Instant::now(); + conn.data_count.fetch_add(bytes.len(), Ordering::Relaxed); if !conn.handle_msg_from_peer(bytes, &mut peer).await { break } @@ -586,6 +632,16 @@ impl Connection { conn.timer = time::interval_at(Instant::now() + SEC30, SEC30); } } + _ = status_timer.tick() => { + let speed = conn.data_count.swap(0, Ordering::Relaxed); + let speed = format!("{:.2}kB/s", speed as f32 / 1024 as f32); + let fps = conn.frame_count.swap(0, Ordering::Relaxed) as _; + conn.session.update_quality_status(QualityStatus { + speed:Some(speed), + fps:Some(fps), + ..Default::default() + }); + } } } log::debug!("Exit io_loop of id={}", session.id); @@ -603,10 +659,19 @@ impl Connection { if !self.first_frame { self.first_frame = true; } + let incomming_format = CodecFormat::from(&vf); + if self.video_format != incomming_format { + self.video_format = incomming_format.clone(); + self.session.update_quality_status(QualityStatus { + codec_format: Some(incomming_format), + ..Default::default() + }) + }; if let (Ok(true), Some(s)) = ( self.video_handler.handle_frame(vf), RGBA_STREAM.read().unwrap().as_ref(), ) { + self.frame_count.fetch_add(1, Ordering::Relaxed); s.add(ZeroCopyBuffer(self.video_handler.rgb.clone())); } } @@ -664,113 +729,114 @@ impl Connection { vec![("x", &cp.x.to_string()), ("y", &cp.y.to_string())], ); } - Some(message::Union::FileResponse(fr)) => match fr.union { - Some(file_response::Union::Dir(fd)) => { - let mut entries = fd.entries.to_vec(); - if self.session.peer_platform() == "Windows" { - fs::transform_windows_path(&mut entries); - } - let id = fd.id; - self.session.push_event( - "file_dir", - vec![("value", &make_fd_to_json(fd)), ("is_local", "false")], - ); - if let Some(job) = fs::get_job(id, &mut self.write_jobs) { - job.set_files(entries); - } - } - Some(file_response::Union::Block(block)) => { - if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) { - if let Err(_err) = job.write(block, None).await { - // to-do: add "skip" for writing job + Some(message::Union::FileResponse(fr)) => { + match fr.union { + Some(file_response::Union::Dir(fd)) => { + let mut entries = fd.entries.to_vec(); + if self.session.peer_platform() == "Windows" { + fs::transform_windows_path(&mut entries); + } + let id = fd.id; + self.session.push_event( + "file_dir", + vec![("value", &make_fd_to_json(fd)), ("is_local", "false")], + ); + if let Some(job) = fs::get_job(id, &mut self.write_jobs) { + job.set_files(entries); } - self.update_jobs_status(); } - } - Some(file_response::Union::Done(d)) => { - if let Some(job) = fs::get_job(d.id, &mut self.write_jobs) { - job.modify_time(); - fs::remove_job(d.id, &mut self.write_jobs); + Some(file_response::Union::Block(block)) => { + if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) { + if let Err(_err) = job.write(block, None).await { + // to-do: add "skip" for writing job + } + self.update_jobs_status(); + } } - self.handle_job_status(d.id, d.file_num, None); - } - Some(file_response::Union::Error(e)) => { - self.handle_job_status(e.id, e.file_num, Some(e.error)); - } - Some(file_response::Union::Digest(digest)) => { - if digest.is_upload { - if let Some(job) = fs::get_job(digest.id, &mut self.read_jobs) { - if let Some(file) = job.files().get(digest.file_num as usize) { - let read_path = get_string(&job.join(&file.name)); - let overwrite_strategy = job.default_overwrite_strategy(); - if let Some(overwrite) = overwrite_strategy { - let req = FileTransferSendConfirmRequest { - id: digest.id, - file_num: digest.file_num, - union: Some(if overwrite { - file_transfer_send_confirm_request::Union::OffsetBlk(0) - } else { - file_transfer_send_confirm_request::Union::Skip( - true, - ) - }), - ..Default::default() - }; - job.confirm(&req); - let msg = new_send_confirm(req); - allow_err!(peer.send(&msg).await); - } else { - self.handle_override_file_confirm( - digest.id, - digest.file_num, - read_path, - true, - ); + Some(file_response::Union::Done(d)) => { + if let Some(job) = fs::get_job(d.id, &mut self.write_jobs) { + job.modify_time(); + fs::remove_job(d.id, &mut self.write_jobs); + } + self.handle_job_status(d.id, d.file_num, None); + } + Some(file_response::Union::Error(e)) => { + self.handle_job_status(e.id, e.file_num, Some(e.error)); + } + Some(file_response::Union::Digest(digest)) => { + if digest.is_upload { + if let Some(job) = fs::get_job(digest.id, &mut self.read_jobs) { + if let Some(file) = job.files().get(digest.file_num as usize) { + let read_path = get_string(&job.join(&file.name)); + let overwrite_strategy = job.default_overwrite_strategy(); + if let Some(overwrite) = overwrite_strategy { + let req = FileTransferSendConfirmRequest { + id: digest.id, + file_num: digest.file_num, + union: Some(if overwrite { + file_transfer_send_confirm_request::Union::OffsetBlk(0) + } else { + file_transfer_send_confirm_request::Union::Skip( + true, + ) + }), + ..Default::default() + }; + job.confirm(&req); + let msg = new_send_confirm(req); + allow_err!(peer.send(&msg).await); + } else { + self.handle_override_file_confirm( + digest.id, + digest.file_num, + read_path, + true, + ); + } } } - } - } else { - if let Some(job) = fs::get_job(digest.id, &mut self.write_jobs) { - if let Some(file) = job.files().get(digest.file_num as usize) { - let write_path = get_string(&job.join(&file.name)); - let overwrite_strategy = job.default_overwrite_strategy(); - match fs::is_write_need_confirmation(&write_path, &digest) { - Ok(res) => match res { - DigestCheckResult::IsSame => { - let msg= new_send_confirm(FileTransferSendConfirmRequest { + } else { + if let Some(job) = fs::get_job(digest.id, &mut self.write_jobs) { + if let Some(file) = job.files().get(digest.file_num as usize) { + let write_path = get_string(&job.join(&file.name)); + let overwrite_strategy = job.default_overwrite_strategy(); + match fs::is_write_need_confirmation(&write_path, &digest) { + Ok(res) => match res { + DigestCheckResult::IsSame => { + let msg= new_send_confirm(FileTransferSendConfirmRequest { id: digest.id, file_num: digest.file_num, union: Some(file_transfer_send_confirm_request::Union::Skip(true)), ..Default::default() }); - self.session.send_msg(msg); - } - DigestCheckResult::NeedConfirm(digest) => { - if let Some(overwrite) = overwrite_strategy { - let msg = new_send_confirm( - FileTransferSendConfirmRequest { - id: digest.id, - file_num: digest.file_num, - union: Some(if overwrite { - file_transfer_send_confirm_request::Union::OffsetBlk(0) - } else { - file_transfer_send_confirm_request::Union::Skip(true) - }), - ..Default::default() - }, - ); self.session.send_msg(msg); - } else { - self.handle_override_file_confirm( - digest.id, - digest.file_num, - write_path.to_string(), - false, - ); } - } - DigestCheckResult::NoSuchFile => { - let msg = new_send_confirm( + DigestCheckResult::NeedConfirm(digest) => { + if let Some(overwrite) = overwrite_strategy { + let msg = new_send_confirm( + FileTransferSendConfirmRequest { + id: digest.id, + file_num: digest.file_num, + union: Some(if overwrite { + file_transfer_send_confirm_request::Union::OffsetBlk(0) + } else { + file_transfer_send_confirm_request::Union::Skip(true) + }), + ..Default::default() + }, + ); + self.session.send_msg(msg); + } else { + self.handle_override_file_confirm( + digest.id, + digest.file_num, + write_path.to_string(), + false, + ); + } + } + DigestCheckResult::NoSuchFile => { + let msg = new_send_confirm( FileTransferSendConfirmRequest { id: digest.id, file_num: digest.file_num, @@ -778,19 +844,20 @@ impl Connection { ..Default::default() }, ); - self.session.send_msg(msg); + self.session.send_msg(msg); + } + }, + Err(err) => { + println!("error recving digest: {}", err); } - }, - Err(err) => { - println!("error recving digest: {}", err); } } } } } + _ => {} } - _ => {} - }, + } Some(message::Union::Misc(misc)) => match misc.union { Some(misc::Union::AudioFormat(f)) => { self.audio_handler.handle_format(f); // diff --git a/src/ui/remote.rs b/src/ui/remote.rs index ad6b3cbd5..f1b2df46b 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -239,15 +239,6 @@ impl sciter::EventHandler for Handler { } } -#[derive(Debug, Default)] -struct QualityStatus { - speed: Option, - fps: Option, - delay: Option, - target_bitrate: Option, - codec_format: Option, -} - impl Handler { pub fn new(cmd: String, id: String, password: String, args: Vec) -> Self { let me = Self { From eec26e5c70f3b5115e4b606bab9d18ce7d77ea90 Mon Sep 17 00:00:00 2001 From: csf Date: Sat, 30 Jul 2022 22:13:38 +0800 Subject: [PATCH 03/33] add mobile restart remote device --- flutter/lib/models/model.dart | 9 ++++++--- flutter/lib/pages/remote_page.dart | 30 ++++++++++++++++++++++++++++++ src/mobile.rs | 19 +++++++++++++++++-- src/ui/remote.rs | 5 +++-- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 7255c6baa..4e1c76e4a 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -68,7 +68,7 @@ class FfiModel with ChangeNotifier { void updatePermission(Map evt) { evt.forEach((k, v) { - if (k == 'name') return; + if (k == 'name' || k.isEmpty) return; _permissions[k] = v == 'true'; }); print('$_permissions'); @@ -195,14 +195,17 @@ class FfiModel with ChangeNotifier { wrongPasswordDialog(id); } else if (type == 'input-password') { enterPasswordDialog(id); + } else if (type == 'restarting') { + showMsgBox(type, title, text, false, hasCancel: false); } else { var hasRetry = evt['hasRetry'] == 'true'; showMsgBox(type, title, text, hasRetry); } } - void showMsgBox(String type, String title, String text, bool hasRetry) { - msgBox(type, title, text); + void showMsgBox(String type, String title, String text, bool hasRetry, + {bool? hasCancel}) { + msgBox(type, title, text, hasCancel: hasCancel); _timer?.cancel(); if (hasRetry) { _timer = Timer(Duration(seconds: _reconnects), () { diff --git a/flutter/lib/pages/remote_page.dart b/flutter/lib/pages/remote_page.dart index bb196f0cf..81349ef3b 100644 --- a/flutter/lib/pages/remote_page.dart +++ b/flutter/lib/pages/remote_page.dart @@ -694,6 +694,13 @@ class _RemotePageState extends State { value: 'block-input')); } } + if (FFI.ffiModel.permissions["restart"] != false && + (pi.platform == "Linux" || + pi.platform == "Windows" || + pi.platform == "Mac OS")) { + more.add(PopupMenuItem( + child: Text(translate('Restart Remote Device')), value: 'restart')); + } () async { var value = await showMenu( context: context, @@ -727,6 +734,8 @@ class _RemotePageState extends State { } } else if (value == 'reset_canvas') { FFI.cursorModel.reset(); + } else if (value == 'restart') { + showRestartRemoteDevice(pi, widget.id); } }(); } @@ -1103,6 +1112,27 @@ void showOptions() { }, clickMaskDismiss: true, backDismiss: true); } +void showRestartRemoteDevice(PeerInfo pi, String id) async { + final res = + await DialogManager.show((setState, close) => CustomAlertDialog( + title: Row(children: [ + Icon(Icons.warning_amber_sharp, + color: Colors.redAccent, size: 28), + SizedBox(width: 10), + Text(translate("Restart Remote Device")), + ]), + content: Text( + "${translate('Are you sure you want to restart')} \n${pi.username}@${pi.hostname}($id) ?"), + actions: [ + TextButton( + onPressed: () => close(), child: Text(translate("Cancel"))), + ElevatedButton( + onPressed: () => close(true), child: Text(translate("OK"))), + ], + )); + if (res == true) FFI.setByName('restart_remote_device'); +} + void showSetOSPassword(bool login) { final controller = TextEditingController(); var password = FFI.getByName('peer_option', "os-password"); diff --git a/src/mobile.rs b/src/mobile.rs index a8777cf39..dec9d49c8 100644 --- a/src/mobile.rs +++ b/src/mobile.rs @@ -88,6 +88,15 @@ impl Session { } } + pub fn restart_remote_device() { + if let Some(session) = SESSION.write().unwrap().as_ref() { + let mut lc = session.lc.write().unwrap(); + lc.restarting_remote_device = true; + let msg = lc.restart_remote_device(); + session.send(Data::Message(msg)); + } + } + fn send(data: Data) { if let Some(session) = SESSION.read().unwrap().as_ref() { session.send(data); @@ -605,8 +614,13 @@ impl Connection { } } } else { - log::info!("Reset by the peer"); - session.msgbox("error", "Connection Error", "Reset by the peer"); + if session.lc.read().unwrap().restarting_remote_device { + log::info!("Restart remote device"); + session.msgbox("restarting", "Restarting Remote Device", "remote_restarting_tip"); + } else { + log::info!("Reset by the peer"); + session.msgbox("error", "Connection Error", "Reset by the peer"); + } break; } } @@ -876,6 +890,7 @@ impl Connection { Permission::Keyboard => "keyboard", Permission::Clipboard => "clipboard", Permission::Audio => "audio", + Permission::Restart => "restart", _ => "", }, &p.enabled.to_string(), diff --git a/src/ui/remote.rs b/src/ui/remote.rs index f1b2df46b..5a44b498e 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -629,8 +629,9 @@ impl Handler { } fn restart_remote_device(&mut self) { - self.lc.write().unwrap().restarting_remote_device = true; - let msg = self.lc.write().unwrap().restart_remote_device(); + let mut lc = self.lc.write().unwrap(); + lc.restarting_remote_device = true; + let msg = lc.restart_remote_device(); self.send(Data::Message(msg)); } From 859e292e1bd93d96aaa824b2c4820b23ecbf830c Mon Sep 17 00:00:00 2001 From: csf Date: Sun, 31 Jul 2022 15:45:29 +0800 Subject: [PATCH 04/33] add mobile_ffi.rs --- src/mobile_ffi.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mobile_ffi.rs b/src/mobile_ffi.rs index c3ed39764..ef2a986eb 100644 --- a/src/mobile_ffi.rs +++ b/src/mobile_ffi.rs @@ -314,6 +314,9 @@ unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) { "input_os_password" => { Session::input_os_password(value.to_owned(), true); } + "restart_remote_device" => { + Session::restart_remote_device(); + } // File Action "read_remote_dir" => { if let Ok(m) = serde_json::from_str::>(value) { From 93e79b5234935b2d1f8690c96c0238cd2690a36c Mon Sep 17 00:00:00 2001 From: csf Date: Sun, 31 Jul 2022 20:08:49 +0800 Subject: [PATCH 05/33] fix translate empty bug --- src/lang.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/lang.rs b/src/lang.rs index ec0f3c187..073f47694 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -8,17 +8,17 @@ mod de; mod en; mod eo; mod es; -mod hu; mod fr; +mod hu; mod id; mod it; +mod pl; mod ptbr; mod ru; mod sk; mod tr; mod tw; mod vn; -mod pl; lazy_static::lazy_static! { pub static ref LANGS: Value = @@ -90,13 +90,15 @@ pub fn translate_locale(name: String, locale: &str) -> String { _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { - v.to_string() - } else { - if lang != "en" { - if let Some(v) = en::T.get(&name as &str) { - return v.to_string(); + if v.is_empty() { + if lang != "en" { + if let Some(v) = en::T.get(&name as &str) { + return v.to_string(); + } } + } else { + return v.to_string(); } - name } + name } From 5658ce807e644d0c8d6715f191f53103dbaeca4f Mon Sep 17 00:00:00 2001 From: csf Date: Sun, 31 Jul 2022 20:42:56 +0800 Subject: [PATCH 06/33] add mobile switch language --- flutter/lib/main.dart | 2 +- flutter/lib/pages/chat_page.dart | 2 -- flutter/lib/pages/home_page.dart | 15 +++++++++- flutter/lib/pages/settings_page.dart | 42 ++++++++++++++++++++++++++++ flutter/lib/widgets/overlay.dart | 4 +-- src/mobile_ffi.rs | 17 +++++++++++ 6 files changed, 76 insertions(+), 6 deletions(-) diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index a81a047b4..9ca9039f0 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -39,7 +39,7 @@ class App extends StatelessWidget { primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), - home: !isAndroid ? WebHomePage() : HomePage(), + home: !isAndroid ? WebHomePage() : HomePage(key: homeKey), navigatorObservers: [ FirebaseAnalyticsObserver(analytics: analytics), FlutterSmartDialog.observer diff --git a/flutter/lib/pages/chat_page.dart b/flutter/lib/pages/chat_page.dart index af940a29e..527f2a8c6 100644 --- a/flutter/lib/pages/chat_page.dart +++ b/flutter/lib/pages/chat_page.dart @@ -6,8 +6,6 @@ import 'package:provider/provider.dart'; import '../models/model.dart'; import 'home_page.dart'; -ChatPage chatPage = ChatPage(); - class ChatPage extends StatelessWidget implements PageShape { @override final title = translate("Chat"); diff --git a/flutter/lib/pages/home_page.dart b/flutter/lib/pages/home_page.dart index 371aa3f64..fbf4fa0d2 100644 --- a/flutter/lib/pages/home_page.dart +++ b/flutter/lib/pages/home_page.dart @@ -12,6 +12,8 @@ abstract class PageShape extends Widget { final List appBarActions = []; } +final homeKey = GlobalKey<_HomePageState>(); + class HomePage extends StatefulWidget { HomePage({Key? key}) : super(key: key); @@ -23,12 +25,23 @@ class _HomePageState extends State { var _selectedIndex = 0; final List _pages = []; + void refreshPages() { + setState(() { + initPages(); + }); + } + @override void initState() { super.initState(); + initPages(); + } + + void initPages() { + _pages.clear(); _pages.add(ConnectionPage()); if (isAndroid) { - _pages.addAll([chatPage, ServerPage()]); + _pages.addAll([ChatPage(), ServerPage()]); } _pages.add(SettingsPage()); } diff --git a/flutter/lib/pages/settings_page.dart b/flutter/lib/pages/settings_page.dart index ea92a72ca..bb1238494 100644 --- a/flutter/lib/pages/settings_page.dart +++ b/flutter/lib/pages/settings_page.dart @@ -146,6 +146,12 @@ class _SettingsState extends State with WidgetsBindingObserver { leading: Icon(Icons.cloud), onPressed: (context) { showServerSettings(); + }), + SettingsTile.navigation( + title: Text(translate('Language')), + leading: Icon(Icons.translate), + onPressed: (context) { + showLanguageSettings(); }) ]), SettingsSection( @@ -185,6 +191,42 @@ void showServerSettings() { showServerSettingsWithValue(id, relay, key, api); } +void showLanguageSettings() { + try { + final langs = json.decode(FFI.getByName('langs')) as List; + var lang = FFI.getByName('local_option', 'lang'); + DialogManager.show((setState, close) { + final setLang = (v) { + if (lang != v) { + setState(() { + lang = v; + }); + final msg = Map() + ..['name'] = 'lang' + ..['value'] = v; + FFI.setByName('local_option', json.encode(msg)); + homeKey.currentState?.refreshPages(); + Future.delayed(Duration(milliseconds: 200), close); + } + }; + return CustomAlertDialog( + title: SizedBox.shrink(), + content: Column( + children: [ + getRadio('Default', '', lang, setLang), + Divider(color: MyTheme.border), + ] + + langs.map((e) { + final key = e[0] as String; + final name = e[1] as String; + return getRadio(name, key, lang, setLang); + }).toList(), + ), + actions: []); + }, backDismiss: true, clickMaskDismiss: true); + } catch (_e) {} +} + void showAbout() { DialogManager.show((setState, close) { return CustomAlertDialog( diff --git a/flutter/lib/widgets/overlay.dart b/flutter/lib/widgets/overlay.dart index 276c175f9..b2ee54410 100644 --- a/flutter/lib/widgets/overlay.dart +++ b/flutter/lib/widgets/overlay.dart @@ -27,7 +27,7 @@ class DraggableChatWindow extends StatelessWidget { height: height, builder: (_, onPanUpdate) { return isIOS - ? chatPage + ? ChatPage() : Scaffold( resizeToAvoidBottomInset: false, appBar: CustomAppBar( @@ -68,7 +68,7 @@ class DraggableChatWindow extends StatelessWidget { ), ), ), - body: chatPage, + body: ChatPage(), ); }); } diff --git a/src/mobile_ffi.rs b/src/mobile_ffi.rs index ef2a986eb..b9ef571bb 100644 --- a/src/mobile_ffi.rs +++ b/src/mobile_ffi.rs @@ -113,6 +113,14 @@ unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *co res = Session::get_option(arg); } } + "local_option" => { + if let Ok(arg) = arg.to_str() { + res = LocalConfig::get_option(arg); + } + } + "langs" => { + res = crate::lang::LANGS.to_string(); + } // File Action "get_home_dir" => { res = fs::get_home_as_string(); @@ -311,6 +319,15 @@ unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) { } } } + "local_option" => { + if let Ok(m) = serde_json::from_str::>(value) { + if let Some(name) = m.get("name") { + if let Some(value) = m.get("value") { + LocalConfig::set_option(name.to_owned(), value.to_owned()); + } + } + } + } "input_os_password" => { Session::input_os_password(value.to_owned(), true); } From 3458c164fbaa19e6be6a4ef0d1df878c8bbdf146 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 1 Aug 2022 09:50:23 +0800 Subject: [PATCH 07/33] fix: add version key to detect specific send/recv logic --- libs/hbb_common/protos/message.proto | 1 + libs/hbb_common/src/fs.rs | 8 ++++---- src/client.rs | 1 + src/ipc.rs | 1 + src/mobile.rs | 5 ++--- src/server/connection.rs | 11 +++++++++-- src/ui/cm.rs | 4 ++-- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 5069fa2b0..dec00f21e 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -64,6 +64,7 @@ message LoginRequest { } bool video_ack_required = 9; uint64 session_id = 10; + string version = 11; } message ChatMessage { string text = 1; } diff --git a/libs/hbb_common/src/fs.rs b/libs/hbb_common/src/fs.rs index 4880b4622..6cc795a0d 100644 --- a/libs/hbb_common/src/fs.rs +++ b/libs/hbb_common/src/fs.rs @@ -276,7 +276,7 @@ impl TransferJob { show_hidden: bool, is_remote: bool, files: Vec, - enable_override_detection: bool, + enable_overwrite_detection: bool, ) -> Self { log::info!("new write {}", path); let total_size = files.iter().map(|x| x.size as u64).sum(); @@ -289,7 +289,7 @@ impl TransferJob { is_remote, files, total_size, - enable_overwrite_detection: enable_override_detection, + enable_overwrite_detection, ..Default::default() } } @@ -301,7 +301,7 @@ impl TransferJob { file_num: i32, show_hidden: bool, is_remote: bool, - enable_override_detection: bool, + enable_overwrite_detection: bool, ) -> ResultType { log::info!("new read {}", path); let files = get_recursive_files(&path, show_hidden)?; @@ -315,7 +315,7 @@ impl TransferJob { is_remote, files, total_size, - enable_overwrite_detection: enable_override_detection, + enable_overwrite_detection, ..Default::default() }) } diff --git a/src/client.rs b/src/client.rs index 172fb6d3d..2d8e6be36 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1151,6 +1151,7 @@ impl LoginConfigHandler { my_name: crate::username(), option: self.get_option_message(true).into(), session_id: self.session_id, + version: crate::VERSION.to_string(), ..Default::default() }; if self.is_file_transfer { diff --git a/src/ipc.rs b/src/ipc.rs index 7ed6f4fd5..13ad67283 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -57,6 +57,7 @@ pub enum FS { id: i32, file_num: i32, files: Vec<(String, u64)>, + overwrite_detection: bool, }, CancelWrite { id: i32, diff --git a/src/mobile.rs b/src/mobile.rs index b21618d46..d19e7afb9 100644 --- a/src/mobile.rs +++ b/src/mobile.rs @@ -1377,9 +1377,8 @@ pub mod connection_manager { id, file_num, mut files, + overwrite_detection } => { - // in mobile, can_enable_override_detection is always true - let od = true; WRITE_JOBS.lock().unwrap().push(fs::TransferJob::new_write( id, "".to_string(), @@ -1395,7 +1394,7 @@ pub mod connection_manager { ..Default::default() }) .collect(), - true, + overwrite_detection )); } ipc::FS::CancelWrite { id } => { diff --git a/src/server/connection.rs b/src/server/connection.rs index 2fae6296d..2062ba31d 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1099,8 +1099,9 @@ impl Connection { } Some(file_action::Union::Send(s)) => { let id = s.id; - let od = - can_enable_overwrite_detection(get_version_number(VERSION)); + let od = can_enable_overwrite_detection(get_version_number( + &self.lr.version, + )); let path = s.path.clone(); match fs::TransferJob::new_read( id, @@ -1123,6 +1124,11 @@ impl Connection { } } Some(file_action::Union::Receive(r)) => { + // note: 1.1.10 introduced identical file detection, which breaks original logic of send/recv files + // whenever got send/recv request, check peer version to ensure old version of rustdesk + let od = can_enable_overwrite_detection(get_version_number( + &self.lr.version, + )); self.send_fs(ipc::FS::NewWrite { path: r.path, id: r.id, @@ -1133,6 +1139,7 @@ impl Connection { .drain(..) .map(|f| (f.name, f.modified_time)) .collect(), + overwrite_detection: od, }); } Some(file_action::Union::RemoveDir(d)) => { diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 45038d753..38bfc9359 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -160,8 +160,8 @@ impl ConnectionManager { id, file_num, mut files, + overwrite_detection } => { - let od = can_enable_overwrite_detection(get_version_number(VERSION)); // cm has no show_hidden context // dummy remote, show_hidden, is_remote write_jobs.push(fs::TransferJob::new_write( @@ -179,7 +179,7 @@ impl ConnectionManager { ..Default::default() }) .collect(), - od, + overwrite_detection, )); } ipc::FS::CancelWrite { id } => { From 2b07c97c08f6f902b79b86dd46440b115f1efcae Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 1 Aug 2022 12:17:38 +0800 Subject: [PATCH 08/33] fix mobile readableFileSize --- flutter/lib/common.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index ddce41a22..dbd15d436 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -199,7 +199,7 @@ const G = M * K; String readableFileSize(double size) { if (size < K) { - return size.toString() + " B"; + return size.toStringAsFixed(2) + " B"; } else if (size < M) { return (size / K).toStringAsFixed(2) + " KB"; } else if (size < G) { From 2d90946a4d64532ec0c4a536d25f13bd05289432 Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 1 Aug 2022 12:44:13 +0800 Subject: [PATCH 09/33] fix mobile UI overflowed --- flutter/lib/pages/remote_page.dart | 2 +- flutter/lib/pages/server_page.dart | 46 +++++++++++++++++------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/flutter/lib/pages/remote_page.dart b/flutter/lib/pages/remote_page.dart index 81349ef3b..a308496ea 100644 --- a/flutter/lib/pages/remote_page.dart +++ b/flutter/lib/pages/remote_page.dart @@ -659,7 +659,7 @@ class _RemotePageState extends State { more.add(PopupMenuItem( child: Row( children: ([ - Container(width: 100.0, child: Text(translate('OS Password'))), + Text(translate('OS Password')), TextButton( style: flatButtonStyle, onPressed: () { diff --git a/flutter/lib/pages/server_page.dart b/flutter/lib/pages/server_page.dart index bb80b8d51..8e79466d6 100644 --- a/flutter/lib/pages/server_page.dart +++ b/flutter/lib/pages/server_page.dart @@ -200,7 +200,8 @@ class ServerInfo extends StatelessWidget { Icon(Icons.warning_amber_sharp, color: Colors.redAccent, size: 24), SizedBox(width: 10), - Text( + Expanded( + child: Text( translate("Service is not running"), style: TextStyle( fontFamily: 'WorkSans', @@ -208,7 +209,7 @@ class ServerInfo extends StatelessWidget { fontSize: 18, color: MyTheme.accent80, ), - ) + )) ], )), SizedBox(height: 5), @@ -316,30 +317,35 @@ class PermissionRow extends StatelessWidget { @override Widget build(BuildContext context) { return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( - children: [ - SizedBox( - width: 140, + Expanded( + flex: 5, + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, child: Text(name, - style: TextStyle(fontSize: 16.0, color: MyTheme.accent50))), - SizedBox( - width: 50, + style: + TextStyle(fontSize: 16.0, color: MyTheme.accent50)))), + Expanded( + flex: 2, + child: FittedBox( + fit: BoxFit.scaleDown, child: Text(isOk ? translate("ON") : translate("OFF"), style: TextStyle( fontSize: 16.0, - color: isOk ? Colors.green : Colors.grey)), - ) - ], + color: isOk ? Colors.green : Colors.grey))), ), - TextButton( - onPressed: onPressed, - child: Text( - translate(isOk ? "CLOSE" : "OPEN"), - style: TextStyle(fontWeight: FontWeight.bold), - )), - const Divider(height: 0) + Expanded( + flex: 3, + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerRight, + child: TextButton( + onPressed: onPressed, + child: Text( + translate(isOk ? "CLOSE" : "OPEN"), + style: TextStyle(fontWeight: FontWeight.bold), + )))), ], ); } From 53f496c0e4eb8d8b0a3e101faf438501aa20a501 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 30 Jul 2022 07:09:31 +0800 Subject: [PATCH 10/33] avoid changing id manually Signed-off-by: 21pages --- libs/hbb_common/src/config.rs | 32 +++++++++++++++++++++++- libs/hbb_common/src/lib.rs | 18 +++++++++++++ libs/hbb_common/src/password_security.rs | 2 +- src/main.rs | 6 +++-- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index f47be3da3..0782a0fde 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -298,8 +298,37 @@ impl Config { fn load() -> Config { let mut config = Config::load_::(""); - let (password, _, store) = decrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION); + let mut store = false; + let (password, _, store1) = decrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION); config.password = password; + store |= store1; + let mut id_valid = false; + let (id, encrypted, store2) = decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION); + if encrypted { + config.id = id; + id_valid = true; + store |= store2; + } else { + if crate::get_modified_time(&Self::file_("")) + .checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation + .unwrap_or(crate::get_exe_time()) + < crate::get_exe_time() + { + id_valid = true; + store = true; + } + } + if !id_valid { + for _ in 0..3 { + if let Some(id) = Config::get_auto_id() { + config.id = id; + store = true; + break; + } else { + log::error!("Failed to generate new id"); + } + } + } if store { config.store(); } @@ -309,6 +338,7 @@ impl Config { fn store(&self) { let mut config = self.clone(); config.password = encrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION); + config.id = encrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION); Config::store_(&config, ""); } diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 2fdd74cd5..48fbfe23c 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -202,6 +202,24 @@ pub fn get_modified_time(path: &std::path::Path) -> SystemTime { .unwrap_or(UNIX_EPOCH) } +pub fn get_created_time(path: &std::path::Path) -> SystemTime { + std::fs::metadata(&path) + .map(|m| m.created().unwrap_or(UNIX_EPOCH)) + .unwrap_or(UNIX_EPOCH) +} + +pub fn get_exe_time() -> SystemTime { + std::env::current_exe().map_or(UNIX_EPOCH, |path| { + let m = get_modified_time(&path); + let c = get_created_time(&path); + if m > c { + m + } else { + c + } + }) +} + pub fn get_uuid() -> Vec { #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Ok(id) = machine_uid::get() { diff --git a/libs/hbb_common/src/password_security.rs b/libs/hbb_common/src/password_security.rs index ba57c11c4..55a6825fa 100644 --- a/libs/hbb_common/src/password_security.rs +++ b/libs/hbb_common/src/password_security.rs @@ -108,7 +108,7 @@ pub fn encrypt_vec_or_original(v: &[u8], version: &str) -> Vec { v.to_owned() } -// String: password +// Vec: password // bool: whether decryption is successful // bool: whether should store to re-encrypt when load pub fn decrypt_vec_or_original(v: &[u8], current_version: &str) -> (Vec, bool, bool) { diff --git a/src/main.rs b/src/main.rs index 7dcd962bf..aecc2ec4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -166,7 +166,7 @@ fn main() { } fn import_config(path: &str) { - use hbb_common::{config::*, get_modified_time}; + use hbb_common::{config::*, get_exe_time, get_modified_time}; let path2 = path.replace(".toml", "2.toml"); let path2 = std::path::Path::new(&path2); let path = std::path::Path::new(path); @@ -176,7 +176,9 @@ fn import_config(path: &str) { log::info!("Empty source config, skipped"); return; } - if get_modified_time(&path) > get_modified_time(&Config::file()) { + if get_modified_time(&path) > get_modified_time(&Config::file()) + && get_modified_time(&path) < get_exe_time() + { if store_path(Config::file(), config).is_err() { log::info!("config written"); } From 747cc794f8adb044fed10e78ba4c7b72a63f9c9c Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 1 Aug 2022 21:32:59 +0800 Subject: [PATCH 11/33] fix flutter3 warning upgrade dependencies --- flutter/android/app/build.gradle | 2 +- flutter/lib/models/chat_model.dart | 45 ++++----- flutter/lib/pages/chat_page.dart | 25 +++-- flutter/pubspec.lock | 146 +++++++++++++++++++++++++---- flutter/pubspec.yaml | 9 +- 5 files changed, 163 insertions(+), 64 deletions(-) diff --git a/flutter/android/app/build.gradle b/flutter/android/app/build.gradle index 79bf6426a..a2a1a02a3 100644 --- a/flutter/android/app/build.gradle +++ b/flutter/android/app/build.gradle @@ -32,7 +32,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 31 + compileSdkVersion 32 sourceSets { main.java.srcDirs += 'src/main/kotlin' } diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index eaf8d2243..149b60a46 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:dash_chat/dash_chat.dart'; +import 'package:dash_chat_2/dash_chat_2.dart'; import 'package:flutter/material.dart'; import '../widgets/overlay.dart'; @@ -11,8 +11,8 @@ class MessageBody { List chatMessages; MessageBody(this.chatUser, this.chatMessages); - void add(ChatMessage cm) { - this.chatMessages.add(cm); + void insert(ChatMessage cm) { + this.chatMessages.insert(0, cm); } void clear() { @@ -24,19 +24,15 @@ class ChatModel with ChangeNotifier { static final clientModeID = -1; final ChatUser me = ChatUser( - uid: "", - name: "Me", + id: "", + firstName: "Me", ); late final Map _messages = Map() ..[clientModeID] = MessageBody(me, []); - final _scroller = ScrollController(); - var _currentID = clientModeID; - ScrollController get scroller => _scroller; - Map get messages => _messages; int get currentID => _currentID; @@ -62,8 +58,8 @@ class ChatModel with ChangeNotifier { "Failed to changeCurrentID,remote user doesn't exist"); } final chatUser = ChatUser( - uid: client.peerId, - name: client.name, + id: client.peerId, + firstName: client.name, ); _messages[id] = MessageBody(chatUser, []); _currentID = id; @@ -80,48 +76,39 @@ class ChatModel with ChangeNotifier { late final chatUser; if (id == clientModeID) { chatUser = ChatUser( - name: FFI.ffiModel.pi.username, - uid: FFI.getId(), + firstName: FFI.ffiModel.pi.username, + id: FFI.getId(), ); } else { final client = FFI.serverModel.clients[id]; if (client == null) { return debugPrint("Failed to receive msg,user doesn't exist"); } - chatUser = ChatUser(uid: client.peerId, name: client.name); + chatUser = ChatUser(id: client.peerId, firstName: client.name); } if (!_messages.containsKey(id)) { _messages[id] = MessageBody(chatUser, []); } - _messages[id]!.add(ChatMessage(text: text, user: chatUser)); + _messages[id]!.insert( + ChatMessage(text: text, user: chatUser, createdAt: DateTime.now())); _currentID = id; notifyListeners(); - scrollToBottom(); - } - - scrollToBottom() { - Future.delayed(Duration(milliseconds: 500), () { - _scroller.animateTo(_scroller.position.maxScrollExtent, - duration: Duration(milliseconds: 200), - curve: Curves.fastLinearToSlowEaseIn); - }); } send(ChatMessage message) { - if (message.text != null && message.text!.isNotEmpty) { - _messages[_currentID]?.add(message); + if (message.text.isNotEmpty) { + _messages[_currentID]?.insert(message); if (_currentID == clientModeID) { - FFI.setByName("chat_client_mode", message.text!); + FFI.setByName("chat_client_mode", message.text); } else { final msg = Map() ..["id"] = _currentID - ..["text"] = message.text!; + ..["text"] = message.text; FFI.setByName("chat_server_mode", jsonEncode(msg)); } } notifyListeners(); - scrollToBottom(); } close() { diff --git a/flutter/lib/pages/chat_page.dart b/flutter/lib/pages/chat_page.dart index 527f2a8c6..ce139d062 100644 --- a/flutter/lib/pages/chat_page.dart +++ b/flutter/lib/pages/chat_page.dart @@ -1,4 +1,4 @@ -import 'package:dash_chat/dash_chat.dart'; +import 'package:dash_chat_2/dash_chat_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/models/chat_model.dart'; @@ -23,7 +23,7 @@ class ChatPage extends StatelessWidget implements PageShape { final id = entry.key; final user = entry.value.chatUser; return PopupMenuItem( - child: Text("${user.name} ${user.uid}"), + child: Text("${user.firstName} ${user.id}"), value: id, ); }).toList(); @@ -44,19 +44,24 @@ class ChatPage extends StatelessWidget implements PageShape { return Stack( children: [ DashChat( - inputContainerStyle: BoxDecoration(color: Colors.white70), - sendOnEnter: false, - // if true,reload keyboard everytime,need fix onSend: (chatMsg) { chatModel.send(chatMsg); }, - user: chatModel.me, + currentUser: chatModel.me, messages: chatModel.messages[chatModel.currentID]?.chatMessages ?? [], - // default scrollToBottom has bug https://github.com/fayeed/dash_chat/issues/53 - scrollToBottom: false, - scrollController: chatModel.scroller, + messageOptions: MessageOptions( + showOtherUsersAvatar: false, + showTime: true, + messageDecorationBuilder: (_, __, ___) => + defaultMessageDecoration( + color: MyTheme.accent80, + borderTopLeft: 8, + borderTopRight: 8, + borderBottomRight: 8, + borderBottomLeft: 8, + )), ), chatModel.currentID == ChatModel.clientModeID ? SizedBox.shrink() @@ -68,7 +73,7 @@ class ChatPage extends StatelessWidget implements PageShape { color: MyTheme.accent80), SizedBox(width: 5), Text( - "${currentUser.name ?? ""} ${currentUser.uid ?? ""}", + "${currentUser.firstName} ${currentUser.id}", style: TextStyle(color: MyTheme.accent50), ), ], diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index a1db4ba6c..ec709b959 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -29,6 +29,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + cached_network_image: + dependency: transitive + description: + name: cached_network_image + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" characters: dependency: transitive description: @@ -71,6 +92,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.2" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.2" cupertino_icons: dependency: "direct main" description: @@ -78,13 +106,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" - dash_chat: + dash_chat_2: dependency: "direct main" description: - name: dash_chat + name: dash_chat_2 url: "https://pub.dartlang.org" source: hosted - version: "1.1.16" + version: "0.0.12" device_info: dependency: "direct main" description: @@ -195,6 +223,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" flutter_breadcrumb: dependency: "direct main" description: @@ -202,6 +237,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -247,6 +289,13 @@ packages: description: flutter source: sdk version: "0.0.0" + html: + dependency: transitive + description: + name: html + url: "https://pub.dartlang.org" + source: hosted + version: "0.15.0" http: dependency: "direct main" description: @@ -345,6 +394,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" package_info: dependency: "direct main" description: @@ -449,16 +505,14 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "6.0.3" qr_code_scanner: dependency: "direct main" description: - path: "." - ref: fix_break_changes_platform - resolved-ref: "0feca6f15042c279ff575c559a3430df917b623d" - url: "https://github.com/Heap-Hop/qr_code_scanner.git" - source: git - version: "0.7.0" + name: qr_code_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" quiver: dependency: transitive description: @@ -466,6 +520,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.0" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.27.5" settings_ui: dependency: "direct main" description: @@ -541,6 +602,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + sqflite: + dependency: transitive + description: + name: sqflite + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1+1" stack_trace: dependency: transitive description: @@ -562,6 +637,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0+2" term_glyph: dependency: transitive description: @@ -583,13 +665,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.4.0" - transparent_image: - dependency: transitive - description: - name: transparent_image - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" tuple: dependency: "direct main" description: @@ -674,6 +749,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + video_player: + dependency: transitive + description: + name: video_player + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.5" + video_player_android: + dependency: transitive + description: + name: video_player_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.8" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.5" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.3" + video_player_web: + dependency: transitive + description: + name: video_player_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" wakelock: dependency: "direct main" description: @@ -745,5 +855,5 @@ packages: source: hosted version: "0.1.0" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0 <3.0.0" flutter: ">=3.0.0" diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index fc01b3c83..2ee7ec1ac 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: ffi: ^1.1.2 path_provider: ^2.0.2 external_path: ^1.0.1 - provider: ^5.0.0 + provider: ^6.0.3 tuple: ^2.0.0 wakelock: ^0.5.2 device_info: ^2.0.2 @@ -41,15 +41,12 @@ dependencies: url_launcher: ^6.0.9 shared_preferences: ^2.0.6 toggle_switch: ^1.4.0 - dash_chat: ^1.1.16 + dash_chat_2: ^0.0.12 draggable_float_widget: ^0.0.2 settings_ui: ^2.0.2 flutter_breadcrumb: ^1.0.1 http: ^0.13.4 - qr_code_scanner: - git: - url: https://github.com/Heap-Hop/qr_code_scanner.git - ref: fix_break_changes_platform + qr_code_scanner: ^1.0.0 zxing2: ^0.1.0 image_picker: ^0.8.5 image: ^3.1.3 From a9f40df2bcb2cd1cbb7ddfcba896c86ded78d8d1 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 1 Aug 2022 22:31:10 +0800 Subject: [PATCH 12/33] fix_privacy_mod_on_login: set some options after login Signed-off-by: fufesou --- src/client.rs | 21 +++++++++++++++++---- src/ui/remote.rs | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/client.rs b/src/client.rs index 2d8e6be36..6a5db19e2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -946,10 +946,6 @@ impl LoginConfigHandler { msg.lock_after_session_end = BoolOption::Yes.into(); n += 1; } - if self.get_toggle_option("privacy-mode") { - msg.privacy_mode = BoolOption::Yes.into(); - n += 1; - } if self.get_toggle_option("disable-audio") { msg.disable_audio = BoolOption::Yes.into(); n += 1; @@ -973,6 +969,23 @@ impl LoginConfigHandler { } } + pub fn get_option_message_after_login(&self) -> Option { + if self.is_port_forward || self.is_file_transfer { + return None; + } + let mut n = 0; + let mut msg = OptionMessage::new(); + if self.get_toggle_option("privacy-mode") { + msg.privacy_mode = BoolOption::Yes.into(); + n += 1; + } + if n > 0 { + Some(msg) + } else { + None + } + } + fn get_image_quality_enum(&self, q: &str, ignore_default: bool) -> Option { if q == "low" { Some(ImageQuality::Low) diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 48e059797..0f6642182 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -2076,6 +2076,22 @@ impl Remote { 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 { if let Ok(msg_in) = Message::parse_from_bytes(&data) { match msg_in.union { @@ -2084,6 +2100,7 @@ impl Remote { self.first_frame = true; self.handler.call2("closeSuccess", &make_args!()); self.handler.call("adaptSize", &make_args!()); + self.send_opts_after_login(peer).await; } let incomming_format = CodecFormat::from(&vf); if self.video_format != incomming_format { From de923fdd2e03b6be7df53207cae8ed696dad7c2a Mon Sep 17 00:00:00 2001 From: 21pages Date: Tue, 2 Aug 2022 11:29:48 +0800 Subject: [PATCH 13/33] fix: hide restart menu item if version < 1.1.10 Signed-off-by: 21pages --- src/ui/remote.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ui/remote.rs b/src/ui/remote.rs index f948f964a..1a446317d 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -23,10 +23,6 @@ use clipboard::{ get_rx_clip_client, server_clip_file, }; use enigo::{self, Enigo, KeyboardControllable}; -use hbb_common::fs::{ - can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult, - RemoveJobMeta, -}; use hbb_common::{ allow_err, config::{Config, LocalConfig, PeerConfig}, @@ -43,6 +39,13 @@ use hbb_common::{ 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)] use crate::clipboard_file::*; @@ -2604,6 +2607,9 @@ impl Interface for Handler { pi_sciter.set_item("hostname", pi.hostname.clone()); pi_sciter.set_item("platform", pi.platform.clone()); pi_sciter.set_item("sas_enabled", pi.sas_enabled); + if get_version_number(&pi.version) < get_version_number("1.1.10") { + self.call2("setPermission", &make_args!("restart", false)); + } if self.is_file_transfer() { if pi.username.is_empty() { self.on_error("No active console user logged on, please connect and logon first."); From 3c2abf970401fa9246dbb7b91d85e2e208fa5d8b Mon Sep 17 00:00:00 2001 From: MaySoMusician Date: Tue, 2 Aug 2022 21:26:23 +0900 Subject: [PATCH 14/33] Add Japanese option Signed-off-by: MaySoMusician --- src/lang.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lang.rs b/src/lang.rs index 073f47694..400c4dd95 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -12,6 +12,7 @@ mod fr; mod hu; mod id; mod it; +mod ja; mod pl; mod ptbr; mod ru; @@ -41,6 +42,7 @@ lazy_static::lazy_static! { ("tr", "Türkçe"), ("vn", "Tiếng Việt"), ("pl", "Polski"), + ("ja", "日本語"), ]); } @@ -87,6 +89,7 @@ pub fn translate_locale(name: String, locale: &str) -> String { "sk" => sk::T.deref(), "vn" => vn::T.deref(), "pl" => pl::T.deref(), + "ja" => ja::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { From 7a9d1007c542750edfe8d0ada1a7b8e215415d8f Mon Sep 17 00:00:00 2001 From: MaySoMusician Date: Tue, 2 Aug 2022 21:26:41 +0900 Subject: [PATCH 15/33] Add Japanese translation file Signed-off-by: MaySoMusician --- src/lang/ja.rs | 303 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/lang/ja.rs diff --git a/src/lang/ja.rs b/src/lang/ja.rs new file mode 100644 index 000000000..5c6ba1da7 --- /dev/null +++ b/src/lang/ja.rs @@ -0,0 +1,303 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "状態"), + ("Your Desktop", "デスクトップ"), + ("desk_tip", "このIDとパスワードであなたのデスクトップにアクセスできます。"), + ("Password", "パスワード"), + ("Ready", "準備完了"), + ("Established", "接続完了"), + ("connecting_status", "RuskDeskネットワークに接続中..."), + ("Enable Service", "サービスを有効化"), + ("Start Service", "サービスを開始"), + ("Service is running", "サービスは動作中"), + ("Service is not running", "サービスは動作していません"), + ("not_ready_status", "準備できていません。接続を確認してください。"), + ("Control Remote Desktop", "リモートのデスクトップを操作する"), + ("Transfer File", "ファイルを転送"), + ("Connect", "接続"), + ("Recent Sessions", "最近のセッション"), + ("Address Book", "アドレス帳"), + ("Confirmation", "確認用"), + ("TCP Tunneling", "TCPトンネリング"), + ("Remove", "削除"), + ("Refresh random password", "ランダムパスワードを再生成"), + ("Set your own password", "自分のパスワードを設定"), + ("Enable Keyboard/Mouse", "キーボード・マウスを有効化"), + ("Enable Clipboard", "クリップボードを有効化"), + ("Enable File Transfer", "ファイル転送を有効化"), + ("Enable TCP Tunneling", "TCPトンネリングを有効化"), + ("IP Whitelisting", "IPホワイトリスト"), + ("ID/Relay Server", "認証・中継サーバー"), + ("Stop service", "サービスを停止"), + ("Change ID", "IDを変更"), + ("Website", "公式サイト"), + ("About", "情報"), + ("Mute", "ミュート"), + ("Audio Input", "音声入力デバイス"), + ("Enhancements", "追加機能"), + ("Hardware Codec", "ハードウェア コーデック"), + ("Adaptive Bitrate", "アダプティブビットレート"), + ("ID Server", "認証サーバー"), + ("Relay Server", "中継サーバー"), + ("API Server", "APIサーバー"), + ("invalid_http", "http:// もしくは https:// から入力してください"), + ("Invalid IP", "無効なIP"), + ("id_change_tip", "使用できるのは大文字・小文字のアルファベット、数字、アンダースコア(_)のみです。初めの文字はアルファベットにする必要があります。6文字から16文字までです。"), + ("Invalid format", "無効な形式"), + ("server_not_support", "サーバー側でまだサポートされていません"), + ("Not available", "利用不可"), + ("Too frequent", "使用量が多すぎです"), + ("Cancel", "キャンセル"), + ("Skip", "スキップ"), + ("Close", "閉じる"), + ("Retry", "再試行"), + ("OK", "OK"), + ("Password Required", "パスワードが必要"), + ("Please enter your password", "パスワードを入力してください"), + ("Remember password", "パスワードを記憶する"), + ("Wrong Password", "パスワードが間違っています"), + ("Do you want to enter again?", "もう一度入力しますか?"), + ("Connection Error", "接続エラー"), + ("Error", "エラー"), + ("Reset by the peer", "相手がリセットしました"), + ("Connecting...", "接続中..."), + ("Connection in progress. Please wait.", "接続中です。しばらくお待ちください。"), + ("Please try 1 minute later", "1分後にもう一度お試しください"), + ("Login Error", "ログインエラー"), + ("Successful", "成功"), + ("Connected, waiting for image...", "接続完了、画像を取得中..."), + ("Name", "名前"), + ("Type", "種類"), + ("Modified", "最終更新"), + ("Size", "サイズ"), + ("Show Hidden Files", "隠しファイルを表示"), + ("Receive", "受信"), + ("Send", "送信"), + ("Refresh File", "ファイルを更新"), + ("Local", "ローカル"), + ("Remote", "リモート"), + ("Remote Computer", "リモート側コンピューター"), + ("Local Computer", "ローカル側コンピューター"), + ("Confirm Delete", "削除の確認"), + ("Delete", "削除"), + ("Properties", "プロパティ"), + ("Multi Select", "複数選択"), + ("Empty Directory", "空のディレクトリ"), + ("Not an empty directory", "空ではないディレクトリ"), + ("Are you sure you want to delete this file?", "本当にこのファイルを削除しますか?"), + ("Are you sure you want to delete this empty directory?", "本当にこの空のディレクトリを削除しますか?"), + ("Are you sure you want to delete the file of this directory?", "本当にこのディレクトリ内のファイルを削除しますか?"), + ("Do this for all conflicts", "他のすべてにも適用する"), + ("This is irreversible!", "この操作は元に戻せません!"), + ("Deleting", "削除中"), + ("files", "ファイル"), + ("Waiting", "待機中"), + ("Finished", "完了"), + ("Speed", "速度"), + ("Custom Image Quality", "画質を調整"), + ("Privacy mode", "プライバシーモード"), + ("Block user input", "ユーザーの入力をブロック"), + ("Unblock user input", "ユーザーの入力を許可"), + ("Adjust Window", "ウィンドウを調整"), + ("Original", "オリジナル"), + ("Shrink", "縮小"), + ("Stretch", "伸縮"), + ("Good image quality", "画質優先"), + ("Balanced", "バランス"), + ("Optimize reaction time", "速度優先"), + ("Custom", "カスタム"), + ("Show remote cursor", "リモート側のカーソルを表示"), + ("Show quality monitor", "品質モニターを表示"), + ("Disable clipboard", "クリップボードを無効化"), + ("Lock after session end", "セッション終了後にロックする"), + ("Insert", "送信"), + ("Insert Lock", "ロック命令を送信"), + ("Refresh", "更新"), + ("ID does not exist", "IDが存在しません"), + ("Failed to connect to rendezvous server", "ランデブーサーバーに接続できませんでした"), + ("Please try later", "後でもう一度お試しください"), + ("Remote desktop is offline", "リモート側デスクトップがオフラインです"), + ("Key mismatch", "キーが一致しません"), + ("Timeout", "タイムアウト"), + ("Failed to connect to relay server", "中継サーバーに接続できませんでした"), + ("Failed to connect via rendezvous server", "ランデブーサーバー経由で接続できませんでした"), + ("Failed to connect via relay server", "中継サーバー経由で接続できませんでした"), + ("Failed to make direct connection to remote desktop", "リモート側デスクトップと直接接続できませんでした"), + ("Set Password", "パスワードを設定"), + ("OS Password", "OSのパスワード"), + ("install_tip", "RustDeskがUACの影響によりリモート側で正常に動作しない場合があります。UACを回避するには、下のボタンをクリックしてシステムにRustDeskをインストールしてください。"), + ("Click to upgrade", "アップグレード"), + ("Click to download", "ダウンロード"), + ("Click to update", "アップデート"), + ("Configure", "設定"), + ("config_acc", "リモートからあなたのデスクトップを操作するには、RustDeskに「アクセシビリティ」権限を与える必要があります。"), + ("config_screen", "リモートからあなたのデスクトップにアクセスするには、RustDeskに「画面収録」権限を与える必要があります。"), + ("Installing ...", "インストール中..."), + ("Install", "インストール"), + ("Installation", "インストール"), + ("Installation Path", "インストール先のパス"), + ("Create start menu shortcuts", "スタートメニューにショートカットを作成する"), + ("Create desktop icon", "デスクトップにアイコンを作成する"), + ("agreement_tip", "インストールを開始することで、ライセンス条項に同意したとみなされます。"), + ("Accept and Install", "同意してインストール"), + ("End-user license agreement", "エンドユーザー ライセンス条項"), + ("Generating ...", "生成中 ..."), + ("Your installation is lower version.", "インストール済みのバージョンが古いです。"), + ("not_close_tcp_tip", "トンネルを使用中はこのウィンドウを閉じないでください"), + ("Listening ...", "リッスン中 ..."), + ("Remote Host", "リモートのホスト"), + ("Remote Port", "リモートのポート"), + ("Action", "操作"), + ("Add", "追加"), + ("Local Port", "ローカルのポート"), + ("setup_server_tip", "接続をより速くするには、自分のサーバーをセットアップしてください"), + ("Too short, at least 6 characters.", "短すぎます。最低6文字です。"), + ("The confirmation is not identical.", "確認用と一致しません。"), + ("Permissions", "権限"), + ("Accept", "承諾"), + ("Dismiss", "無視"), + ("Disconnect", "切断"), + ("Allow using keyboard and mouse", "キーボード・マウスの使用を許可"), + ("Allow using clipboard", "クリップボードの使用を許可"), + ("Allow hearing sound", "サウンドの受信を許可"), + ("Allow file copy and paste", "ファイルのコピーアンドペーストを許可"), + ("Connected", "接続済み"), + ("Direct and encrypted connection", "接続は暗号化され、直接つながっている"), + ("Relayed and encrypted connection", "接続は暗号化され、中継されている"), + ("Direct and unencrypted connection", "接続は暗号化されてなく、直接つながっている"), + ("Relayed and unencrypted connection", "接続は暗号化されてなく、中継されている"), + ("Enter Remote ID", "リモートのIDを入力"), + ("Enter your password", "パスワードを入力"), + ("Logging in...", "ログイン中..."), + ("Enable RDP session sharing", "RDPセッション共有を有効化"), + ("Auto Login", "自動ログイン"), + ("Enable Direct IP Access", "直接IPアクセスを有効化"), + ("Rename", "名前の変更"), + ("Space", "スペース"), + ("Create Desktop Shortcut", "デスクトップにショートカットを作成する"), + ("Change Path", "パスを変更"), + ("Create Folder", "フォルダを作成"), + ("Please enter the folder name", "フォルダ名を入力してください"), + ("Fix it", "修復"), + ("Warning", "注意"), + ("Login screen using Wayland is not supported", "Waylandを使用したログインスクリーンはサポートされていません"), + ("Reboot required", "再起動が必要"), + ("Unsupported display server ", "サポートされていないディスプレイサーバー"), + ("x11 expected", "X11 が必要です"), + ("Port", "ポート"), + ("Settings", "設定"), + ("Username", "ユーザー名"), + ("Invalid port", "無効なポート"), + ("Closed manually by the peer", "相手が手動で切断しました"), + ("Enable remote configuration modification", "リモート設定変更を有効化"), + ("Run without install", "インストールせずに実行"), + ("Always connected via relay", "常に中継サーバー経由で接続"), + ("Always connect via relay", "常に中継サーバー経由で接続"), + ("whitelist_tip", "ホワイトリストに登録されたIPからのみ接続を許可します"), + ("Login", "ログイン"), + ("Logout", "ログアウト"), + ("Tags", "タグ"), + ("Search ID", "IDを検索"), + ("Current Wayland display server is not supported", "現在のWaylandディスプレイサーバーはサポートされていません"), + ("whitelist_sep", "カンマやセミコロン、空白、改行で区切ってください"), + ("Add ID", "IDを追加"), + ("Add Tag", "タグを追加"), + ("Unselect all tags", "全てのタグを選択解除"), + ("Network error", "ネットワークエラー"), + ("Username missed", "ユーザー名がありません"), + ("Password missed", "パスワードがありません"), + ("Wrong credentials", "資格情報が間違っています"), + ("Edit Tag", "タグを編集"), + ("Unremember Password", "パスワードの記憶を解除"), + ("Favorites", "お気に入り"), + ("Add to Favorites", "お気に入りに追加"), + ("Remove from Favorites", "お気に入りから削除"), + ("Empty", "空"), + ("Invalid folder name", "無効なフォルダ名"), + ("Socks5 Proxy", "SOCKS5プロキシ"), + ("Hostname", "ホスト名"), + ("Discovered", "探知済み"), + ("install_daemon_tip", "起動時に開始するには、システムサービスをインストールする必要があります。"), + ("Remote ID", "リモートのID"), + ("Paste", "ペースト"), + ("Paste here?", "ここにペースト?"), + ("Are you sure to close the connection?", "本当に切断しますか?"), + ("Download new version", "新しいバージョンをダウンロード"), + ("Touch mode", "タッチモード"), + ("Mouse mode", "マウスモード"), + ("One-Finger Tap", "1本指でタップ"), + ("Left Mouse", "マウス左クリック"), + ("One-Long Tap", "1本指でロングタップ"), + ("Two-Finger Tap", "2本指でタップ"), + ("Right Mouse", "マウス右クリック"), + ("One-Finger Move", "1本指でドラッグ"), + ("Double Tap & Move", "2本指でタップ&ドラッグ"), + ("Mouse Drag", "マウスドラッグ"), + ("Three-Finger vertically", "3本指で縦方向"), + ("Mouse Wheel", "マウスホイール"), + ("Two-Finger Move", "2本指でドラッグ"), + ("Canvas Move", "キャンバスの移動"), + ("Pinch to Zoom", "ピンチしてズーム"), + ("Canvas Zoom", "キャンバスのズーム"), + ("Reset canvas", "キャンバスのリセット"), + ("No permission of file transfer", "ファイル転送の権限がありません"), + ("Note", "ノート"), + ("Connection", "接続"), + ("Share Screen", "画面を共有"), + ("CLOSE", "閉じる"), + ("OPEN", "開く"), + ("Chat", "チャット"), + ("Total", "計"), + ("items", "個のアイテム"), + ("Selected", "選択済み"), + ("Screen Capture", "画面キャプチャ"), + ("Input Control", "入力操作"), + ("Audio Capture", "音声キャプチャ"), + ("File Connection", "ファイルの接続"), + ("Screen Connection", "画面の接続"), + ("Do you accept?", "承諾しますか?"), + ("Open System Setting", "端末設定を開く"), + ("How to get Android input permission?", "Androidの入力権限を取得するには?"), + ("android_input_permission_tip1", "このAndroid端末をリモートの端末からマウスやタッチで操作するには、RustDeskに「アクセシビリティ」サービスの使用を許可する必要があります。"), + ("android_input_permission_tip2", "次の端末設定ページに進み、「インストール済みアプリ」から「RestDesk Input」をオンにしてください。"), + ("android_new_connection_tip", "新しい操作リクエストが届きました。この端末を操作しようとしています。"), + ("android_service_will_start_tip", "「画面キャプチャ」をオンにするとサービスが自動的に開始され、他の端末がこの端末への接続をリクエストできるようになります。"), + ("android_stop_service_tip", "サービスを停止すると、現在確立されている接続が全て自動的に閉じられます。"), + ("android_version_audio_tip", "現在のAndroidバージョンでは音声キャプチャはサポートされていません。Android 10以降にアップグレードしてください。"), + ("android_start_service_tip", "「サービスを開始」をタップするか「画面キャプチャ」を開くと、画面共有サービスが開始されます。"), + ("Account", "アカウント"), + ("Overwrite", "上書き"), + ("This file exists, skip or overwrite this file?", "このファイルは存在しています。スキップするか上書きしますか?"), + ("Quit", "終了"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), // @TODO: Update url when someone translates the document + ("Help", "ヘルプ"), + ("Failed", "失敗"), + ("Succeeded", "成功"), + ("Someone turns on privacy mode, exit", "プライバシーモードがオンになりました。終了します。"), + ("Unsupported", "サポートされていません"), + ("Peer denied", "相手が拒否しました"), + ("Please install plugins", "プラグインをインストールしてください"), + ("Peer exit", "相手が終了しました"), + ("Failed to turn off", "オフにできませんでした"), + ("Turned off", "オフになりました"), + ("In privacy mode", "プライバシーモード開始"), + ("Out privacy mode", "プライバシーモード終了"), + ("Language", "言語"), + ("Keep RustDesk background service", "RustDesk バックグラウンドサービスを維持"), + ("Ignore Battery Optimizations", "バッテリーの最適化を無効にする"), + ("android_open_battery_optimizations_tip", "この機能を使わない場合は、次のRestDeskアプリ設定ページから「バッテリー」に進み、「制限なし」の選択を外してください"), + ("Connection not allowed", "接続が許可されていません"), + ("Use temporary password", "使い捨てのパスワードを使用"), + ("Use permanent password", "固定のパスワードを使用"), + ("Use both passwords", "どちらのパスワードも使用"), + ("Set permanent password", "固定のパスワードを設定"), + ("Set temporary password length", "使い捨てのパスワードの長さを設定"), + ("Enable Remote Restart", "リモートからの再起動を有効化"), + ("Allow remote restart", "リモートからの再起動を許可"), + ("Restart Remote Device", "リモートの端末を再起動"), + ("Are you sure you want to restart", "本当に再起動しますか"), + ("Restarting Remote Device", "リモート端末を再起動中"), + ("remote_restarting_tip", "リモート端末は再起動中です。このメッセージボックスを閉じて、しばらくした後に固定のパスワードを使用して再接続してください。"), + ].iter().cloned().collect(); +} From 84f737067caf6bd820ddca2259ed2ea037667156 Mon Sep 17 00:00:00 2001 From: SuoDizzy <99581810+SuoDizzy@users.noreply.github.com> Date: Wed, 3 Aug 2022 09:05:53 +0300 Subject: [PATCH 16/33] Grammatical errors in README Finnish translation Replaced some words to be more sensible (such as from "aja" to "suorita") and fixed some grammar errors. ("Kirjoittaa" not "Kirjoita") Previously a finnish person could easily tell it wasnt by a finnish person. --- README-FI.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README-FI.md b/README-FI.md index 1258bb550..5f38d2e42 100644 --- a/README-FI.md +++ b/README-FI.md @@ -13,7 +13,7 @@ Juttele meidän kanssa: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](htt [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09) -Vielä yksi etätyöpöytäohjelmisto, ohjelmoitu Rust-kielellä. Toimii suoraan pakkauksesta, ei tarvitse asetuksia. Hallitset täysin tietojasi, ei tarvitse murehtia turvallisuutta. Voit käyttää meidän rendezvous/relay-palvelinta, [aseta omasi](https://rustdesk.com/server), tai [kirjoita oma rendezvous/relay-palvelin](https://github.com/rustdesk/rustdesk-server-demo). +Vielä yksi etätyöpöytäohjelmisto, ohjelmoitu Rust-kielellä. Toimii suoraan pakkauksesta, ei tarvitse asetusta. Hallitset täysin tietojasi, ei tarvitse murehtia turvallisuutta. Voit käyttää meidän rendezvous/relay-palvelinta, [aseta omasi](https://rustdesk.com/server), tai [kirjoittaa oma rendezvous/relay-palvelin](https://github.com/rustdesk/rustdesk-server-demo). RustDesk toivottaa avustukset tervetulleiksi kaikilta. Katso lisätietoja [`CONTRIBUTING.md`](CONTRIBUTING.md) avun saamiseksi. @@ -45,9 +45,9 @@ Desktop-versiot käyttävät [sciter](https://sciter.com/) graafisena käyttöli - Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static - Linux/MacOS: vcpkg install libvpx libyuv opus -- aja `cargo run` +- suorita `cargo run` -## Kuinka rakentaa Linuxissa +## Kuinka rakentaa Linux:issa ### Ubuntu 18 (Debian 10) @@ -79,7 +79,7 @@ export VCPKG_ROOT=$HOME/vcpkg vcpkg/vcpkg install libvpx libyuv opus ``` -### Korjaa libvpx (Fedora-linux-versiota varten) +### Korjaa libvpx (Fedora) ```sh cd vcpkg/buildtrees/libvpx/src @@ -107,7 +107,7 @@ VCPKG_ROOT=$HOME/vcpkg cargo run ### Vaihda Wayland-ympäristö X11 (Xorg)-ympäristöön -RustDesk ei tue Waylandia. Tarkista [tämä](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) asettamaan Xorg oletus GNOME-istuntona. +RustDesk ei tue Waylandia. Tarkista [tämä](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) asettamalla Xorg oletus GNOME-istuntoon. ## Kuinka rakennetaan Dockerin kanssa @@ -119,13 +119,13 @@ cd rustdesk docker build -t "rustdesk-builder" . ``` -Sitten, joka kerta kun sinun on rakennettava sovellus, aja seuraava komento: +Sitten, joka kerta kun sinun on rakennettava sovellus, suorita seuraava komento: ```sh docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder ``` -Huomaa, että ensimmäinen rakentaminen saattaa kestää pitempään ennen kuin riippuvuudet on siirretty välimuistiin, seuraavat rakentamiset ovat nopeampia. Lisäksi, jos sinun on määritettävä eri argumentteja rakentamiskomennolle, saatat tehdä sen niin, että komennon lopussa `-kohdassa. Esimerkiksi, jos haluat rakentaa optimoidun julkaisuversion, sinun on ajettava komento yllä siten, että sitä seuraa argumentti`--release`. Suoritettava tiedosto on saatavilla järjestelmäsi kohdehakemistossa, ja se voidaan suorittaa seuraavan kera: +Huomaa, että ensimmäinen rakentaminen saattaa kestää pitempään ennen kuin riippuvuudet on siirretty välimuistiin, seuraavat rakentamiset ovat nopeampia. Lisäksi, jos sinun on määritettävä eri väittämiä rakentamiskomennolle, saatat tehdä sen niin, että komennon lopussa `-kohdassa. Esimerkiksi, jos haluat rakentaa optimoidun julkaisuversion, sinun on ajettava komento yllä siten, että sitä seuraa väittämä`--release`. Suoritettava tiedosto on saatavilla järjestelmäsi kohdehakemistossa, ja se voidaan suorittaa seuraavan kera: ```sh target/debug/rustdesk From 8b56a1a271c0762a78bb20c9d63a5a444d1c4eb1 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 4 Aug 2022 09:26:15 +0800 Subject: [PATCH 17/33] https://github.com/rustdesk/rustdesk/issues/1177 --- src/ui/index.tis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/index.tis b/src/ui/index.tis index be6e2c355..256f00c44 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -3,7 +3,7 @@ stdout.println("current platform:", OS); stdout.println("is_xfce: ", is_xfce); // html min-width, min-height not working on mac, below works for all -view.windowMinSize = (scaleIt(500), scaleIt(300)); +view.windowMinSize = (scaleIt(560), scaleIt(300)); var app; var tmp = handler.get_connect_status(); From 94791f1fefa7a5593de7251250c64185812d14b8 Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Fri, 5 Aug 2022 14:26:04 +0200 Subject: [PATCH 18/33] Add files via upload Add Dutch translation --- src/lang/nl.rs | 303 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/lang/nl.rs diff --git a/src/lang/nl.rs b/src/lang/nl.rs new file mode 100644 index 000000000..5b2838bc1 --- /dev/null +++ b/src/lang/nl.rs @@ -0,0 +1,303 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "Status"), + ("Your Desktop", "Uw Bureaublad"), + ("desk_tip", "Uw bureaublad is toegankelijk via de ID en het wachtwoord hieronder."), + ("Password", "Wachtwoord"), + ("Ready", "Klaar"), + ("Established", "Bevestigd"), + ("connecting_status", "Verbinding maken met het RustDesk netwerk..."), + ("Enable Service", "Service Inschakelen"), + ("Start Service", "Start Service"), + ("Service is running", "De service draait."), + ("Service is not running", "De service draait niet"), + ("not_ready_status", "Niet klaar, controleer de netwerkverbinding"), + ("Control Remote Desktop", "Beheer Extern Bureaublad"), + ("Transfer File", "Bestand Overzetten"), + ("Connect", "Verbinden"), + ("Recent Sessions", "Recente Behandelingen"), + ("Address Book", "Adresboek"), + ("Confirmation", "Bevestiging"), + ("TCP Tunneling", "TCP Tunneling"), + ("Remove", "Verwijder"), + ("Refresh random password", "Vernieuw willekeurig wachtwoord"), + ("Set your own password", "Stel je eigen wachtwoord in"), + ("Enable Keyboard/Mouse", "Toetsenbord/Muis Inschakelen"), + ("Enable Clipboard", "Klembord Inschakelen"), + ("Enable File Transfer", "Bestandsoverdracht Inschakelen"), + ("Enable TCP Tunneling", "TCP Tunneling Inschakelen"), + ("IP Whitelisting", "IP Witte Lijst"), + ("ID/Relay Server", "ID/Relay Server"), + ("Stop service", "Stop service"), + ("Change ID", "Wijzig ID"), + ("Website", "Website"), + ("About", "Over"), + ("Mute", "Geluid uit"), + ("Audio Input", "Audio Ingang"), + ("Enhancements", "Verbeteringen"), + ("Hardware Codec", "Hardware Codec"), + ("Adaptive Bitrate", "Aangepaste Bitsnelheid"), + ("ID Server", "ID Server"), + ("Relay Server", "Relay Server"), + ("API Server", "API Server"), + ("invalid_http", "Moet beginnen met http:// of https://"), + ("Invalid IP", "Ongeldig IP"), + ("id_change_tip", "Alleen de letters a-z, A-Z, 0-9, _ (underscore) kunnen worden gebruikt. De eerste letter moet a-z, A-Z zijn. De lengte moet tussen 6 en 16 liggen."), + ("Invalid format", "Ongeldig formaat"), + ("server_not_support", "Nog niet ondersteund door de server"), + ("Not available", "Niet beschikbaar"), + ("Too frequent", "Te vaak"), + ("Cancel", "Annuleer"), + ("Skip", "Overslaan"), + ("Close", "Sluit"), + ("Retry", "Probeer opnieuw"), + ("OK", "OK"), + ("Password Required", "Wachtwoord vereist"), + ("Please enter your password", "Voer uw wachtwoord in"), + ("Remember password", "Wachtwoord onthouden"), + ("Wrong Password", "Verkeerd wachtwoord"), + ("Do you want to enter again?", "Wil je opnieuw invoeren?"), + ("Connection Error", "Fout bij verbinding"), + ("Error", "Fout"), + ("Reset by the peer", "Reset door de peer"), + ("Connecting...", "Verbinding maken..."), + ("Connection in progress. Please wait.", "Verbinding in uitvoering. Even geduld a.u.b."), + ("Please try 1 minute later", "Probeer 1 minuut later"), + ("Login Error", "Login Fout"), + ("Successful", "Succesvol"), + ("Connected, waiting for image...", "Verbonden, wacht op beeld..."), + ("Name", "Naam"), + ("Type", "Type"), + ("Modified", "Gewijzigd"), + ("Size", "Grootte"), + ("Show Hidden Files", "Verborgen bestanden tonen"), + ("Receive", "Ontvangen"), + ("Send", "Verzenden"), + ("Refresh File", "Bestand Verversen"), + ("Local", "Lokaal"), + ("Remote", "Op afstand"), + ("Remote Computer", "Externe Computer"), + ("Local Computer", "Locale Computer"), + ("Confirm Delete", "Bevestig Verwijderen"), + ("Delete", "Verwijder"), + ("Properties", "Eigenschappen"), + ("Multi Select", "Meervoudig selecteren"), + ("Empty Directory", "Lege Map"), + ("Not an empty directory", "Geen Lege Map"), + ("Are you sure you want to delete this file?", "Weet je zeker dat je dit bestand wilt verwijderen?"), + ("Are you sure you want to delete this empty directory?", "Weet je zeker dat je deze lege map wilt verwijderen?"), + ("Are you sure you want to delete the file of this directory?", "Weet je zeker dat je het bestand uit deze map wilt verwijderen?"), + ("Do this for all conflicts", "Doe dit voor alle conflicten"), + ("This is irreversible!", "Dit is onomkeerbaar!"), + ("Deleting", "Verwijderen"), + ("files", "bestanden"), + ("Waiting", "Wachten"), + ("Finished", "Voltooid"), + ("Speed", "Snelheid"), + ("Custom Image Quality", "Aangepaste beeldkwaliteit"), + ("Privacy mode", "Privacymodus"), + ("Block user input", "Gebruikersinvoer blokkeren"), + ("Unblock user input", "Gebruikersinvoer opheffen"), + ("Adjust Window", "Venster Aanpassen"), + ("Original", "Origineel"), + ("Shrink", "Verkleinen"), + ("Stretch", "Uitrekken"), + ("Good image quality", "Goede beeldkwaliteit"), + ("Balanced", "Gebalanceerd"), + ("Optimize reaction time", "Optimaliseer reactietijd"), + ("Custom", "Aangepast"), + ("Show remote cursor", "Toon cursor op extern bureaublad"), + ("Show quality monitor", "Kwaliteitsmonitor tonen"), + ("Disable clipboard", "Klembord uitschakelen"), + ("Lock after session end", "Vergrendelen na einde sessie"), + ("Insert", "Invoegen"), + ("Insert Lock", "Vergrendeling Invoegen"), + ("Refresh", "Vernieuwen"), + ("ID does not exist", "ID bestaat niet"), + ("Failed to connect to rendezvous server", "Verbinding met rendez-vous-server mislukt"), + ("Please try later", "Probeer later opnieuw"), + ("Remote desktop is offline", "Extern bureaublad is offline"), + ("Key mismatch", "Code onjuist"), + ("Timeout", "Time-out"), + ("Failed to connect to relay server", "Verbinding met relayserver mislukt"), + ("Failed to connect via rendezvous server", "Verbinding via rendez-vous-server mislukt"), + ("Failed to connect via relay server", "Verbinding via relaisserver mislukt"), + ("Failed to make direct connection to remote desktop", "Onmogelijk direct verbinding te maken met extern bureaublad"), + ("Set Password", "Wachtwoord Instellen"), + ("OS Password", "OS Wachtwoord"), + ("install_tip", "Je gebruikt een niet genstalleerde versie. Als gevolg van UAC-beperkingen is het in sommige gevallen niet mogelijk om als controleterminal de muis en het toetsenbord te bedienen of het scherm over te nemen. Klik op de knop hieronder om RustDesk op het systeem te installeren om het bovenstaande probleem te voorkomen."), + ("Click to upgrade", "Klik voor upgrade"), + ("Click to download", "Klik om te downloaden"), + ("Click to update", "Klik om bij te werken"), + ("Configure", "Configureren"), + ("config_acc", "Om je bureaublad op afstand te kunnen bedienen, moet je RustDesk \"toegankelijkheid\" toestemming geven."), + ("config_screen", "Om toegang te krijgen tot het externe bureaublad, moet je RustDesk de toestemming \"schermregistratie\" geven."), + ("Installing ...", "Installeren ..."), + ("Install", "Installeer"), + ("Installation", "Installatie"), + ("Installation Path", "Installatie Pad"), + ("Create start menu shortcuts", "Startmenu snelkoppelingen maken"), + ("Create desktop icon", "Bureaubladpictogram maken"), + ("agreement_tip", "Het starten van de installatie betekent het accepteren van de licentieovereenkomst."), + ("Accept and Install", "Accepteren en installeren"), + ("End-user license agreement", "Licentieovereenkomst eindgebruiker"), + ("Generating ...", "Genereert ..."), + ("Your installation is lower version.", "Uw installatie is een lagere versie."), + ("not_close_tcp_tip", "Gelieve dit venster niet te sluiten wanneer u de tunnel gebruikt"), + ("Listening ...", "Luisteren ..."), + ("Remote Host", "Externe Host"), + ("Remote Port", "Externe Poort"), + ("Action", "Actie"), + ("Add", "Toevoegen"), + ("Local Port", "Lokale Poort"), + ("setup_server_tip", "Als u een snellere verbindingssnelheid nodig heeft, kunt u ervoor kiezen om uw eigen server te creren"), + ("Too short, at least 6 characters.", "Te kort, minstens 6 tekens."), + ("The confirmation is not identical.", "De bevestiging is niet identiek."), + ("Permissions", "Machtigingen"), + ("Accept", "Accepteren"), + ("Dismiss", "Afwijzen"), + ("Disconnect", "Verbinding verbreken"), + ("Allow using keyboard and mouse", "Gebruik toetsenbord en muis toestaan"), + ("Allow using clipboard", "Gebruik klembord toestaan"), + ("Allow hearing sound", "Geluidsweergave toestaan"), + ("Allow file copy and paste", "Kopiren en plakken van bestanden toestaan"), + ("Connected", "Verbonden"), + ("Direct and encrypted connection", "Directe en versleutelde verbinding"), + ("Relayed and encrypted connection", "Doorgeschakelde en versleutelde verbinding"), + ("Direct and unencrypted connection", "Directe en niet-versleutelde verbinding"), + ("Relayed and unencrypted connection", "Doorgeschakelde en niet-versleutelde verbinding"), + ("Enter Remote ID", "Voer Extern ID in"), + ("Enter your password", "Voer uw wachtwoord in"), + ("Logging in...", "Aanmelden..."), + ("Enable RDP session sharing", "Delen van RDP-sessie inschakelen"), + ("Auto Login", "Automatisch Aanmelden"), + ("Enable Direct IP Access", "Directe IP-toegang Inschakelen"), + ("Rename", "Naam wijzigen"), + ("Space", "Spatie"), + ("Create Desktop Shortcut", "Snelkoppeling op bureaublad maken"), + ("Change Path", "Pad wijzigen"), + ("Create Folder", "Map Maken"), + ("Please enter the folder name", "Geef de mapnaam op"), + ("Fix it", "Repareer het"), + ("Warning", "Waarschuwing"), + ("Login screen using Wayland is not supported", "Aanmeldingsscherm via Wayland wordt niet ondersteund"), + ("Reboot required", "Opnieuw opstarten vereist"), + ("Unsupported display server ", "Niet-ondersteunde weergaveserver"), + ("x11 expected", "x11 verwacht"), + ("Port", "Port"), + ("Settings", "Instellingen"), + ("Username", "Gebruikersnaam"), + ("Invalid port", "Ongeldige poort"), + ("Closed manually by the peer", "Handmatig gesloten door de peer"), + ("Enable remote configuration modification", "Wijziging configuratie op afstand inschakelen"), + ("Run without install", "Uitvoeren zonder installatie"), + ("Always connected via relay", "Altijd verbonden via relay"), + ("Always connect via relay", "Altijd verbinden via relay"), + ("whitelist_tip", "Alleen een IP-adres op de witte lijst krijgt toegang tot mijn toestel"), + ("Login", "Log In"), + ("Logout", "Log Uit"), + ("Tags", "Labels"), + ("Search ID", "Zoek ID"), + ("Current Wayland display server is not supported", "Huidige Wayland weergaveserver wordt niet ondersteund"), + ("whitelist_sep", "Gescheiden door komma, puntkomma, spatie of nieuwe regel"), + ("Add ID", "ID Toevoegen"), + ("Add Tag", "Label Toevoegen"), + ("Unselect all tags", "Alle labels verwijderen"), + ("Network error", "Netwerkfout"), + ("Username missed", "Gebruikersnaam gemist"), + ("Password missed", "Wachtwoord vergeten"), + ("Wrong credentials", "Verkeerde inloggegevens"), + ("Edit Tag", "Label Bewerken"), + ("Unremember Password", "Wachtwoord vergeten"), + ("Favorites", "Favorieten"), + ("Add to Favorites", "Toevoegen aan Favorieten"), + ("Remove from Favorites", "Verwijderen uit Favorieten"), + ("Empty", "Leeg"), + ("Invalid folder name", "Ongeldige mapnaam"), + ("Socks5 Proxy", "Socks5 Proxy"), + ("Hostname", "Hostnaam"), + ("Discovered", "Ontdekt"), + ("install_daemon_tip", "Om bij het opstarten van de computer te kunnen beginnen, moet je de systeemdienst installeren."), + ("Remote ID", "Externe ID"), + ("Paste", "Plakken"), + ("Paste here?", "Hier plakken"), + ("Are you sure to close the connection?", "Weet je zeker dat je de verbinding wilt sluiten?"), + ("Download new version", "Download nieuwe versie"), + ("Touch mode", "Aanraak modus"), + ("Mouse mode", "Muismodus"), + ("One-Finger Tap", "En-Vinger Tik"), + ("Left Mouse", "Linkermuis"), + ("One-Long Tap", "n-Vinger-Lange-Tik"), + ("Two-Finger Tap", "Twee-Vingers-Tik"), + ("Right Mouse", "Rechter muis"), + ("One-Finger Move", "En-Vinger-Verplaatsing"), + ("Double Tap & Move", "Dubbel Tik en Verplaatsen"), + ("Mouse Drag", "Muis Slepen"), + ("Three-Finger vertically", "Drie-Vinger verticaal"), + ("Mouse Wheel", "Muiswiel"), + ("Two-Finger Move", "Twee-Vingers Verplaatsen"), + ("Canvas Move", "Canvas Verplaatsen"), + ("Pinch to Zoom", "Knijp om te Zoomen"), + ("Canvas Zoom", "Canvas Zoom"), + ("Reset canvas", "Reset canvas"), + ("No permission of file transfer", "Geen toestemming voor bestandsoverdracht"), + ("Note", "Opmerking"), + ("Connection", "Verbinding"), + ("Share Screen", "Scherm Delen"), + ("CLOSE", "SLUITEN"), + ("OPEN", "OPEN"), + ("Chat", "Chat"), + ("Total", "Totaal"), + ("items", "items"), + ("Selected", "Geselecteerd"), + ("Screen Capture", "Schermopname"), + ("Input Control", "Invoercontrole"), + ("Audio Capture", "Audio Opnemen"), + ("File Connection", "Bestandsverbinding"), + ("Screen Connection", "Schermverbinding"), + ("Do you accept?", "Sta je toe?"), + ("Open System Setting", "Systeeminstelling Openen"), + ("How to get Android input permission?", "Hoe krijg ik Android invoer toestemming?"), + ("android_input_permission_tip1", "Om ervoor te zorgen dat een extern apparaat uw Android-apparaat kan besturen via muis of aanraking, moet u RustDesk toestaan om de \"Toegankelijkheid"\ service te gebruiken."), + ("android_input_permission_tip2", "Ga naar de volgende pagina met systeeminstellingen, zoek en ga naar [Genstalleerde Services], schakel de service [RustDesk Input] in."), + ("android_new_connection_tip", "Er is een nieuw controleverzoek binnengekomen, dat uw huidige apparaat wil controleren."), + ("android_service_will_start_tip", "Als u \"Schermopname\" inschakelt, wordt de service automatisch gestart, zodat andere apparaten een verbinding met uw apparaat kunnen aanvragen."), + ("android_stop_service_tip", "Het sluiten van de service zal automatisch alle gemaakte verbindingen sluiten."), + ("android_version_audio_tip", "De huidige versie van Android ondersteunt geen audio-opname, upgrade naar Android 10 of hoger."), + ("android_start_service_tip", "Druk op [Start Service] of op de permissie OPEN [Screenshot] om de service voor het overnemen van het scherm te starten."), + ("Account", "Account"), + ("Overwrite", "Overschrijven"), + ("This file exists, skip or overwrite this file?", "Dit bestand bestaat reeds, overslaan of overschrijven?"), + ("Quit", "Afsluiten"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), + ("Help", "https://rustdesk.com/docs/en/manual/linux/#x11-required"), + ("Failed", "Mislukt"), + ("Succeeded", "Geslaagd"), + ("Someone turns on privacy mode, exit", "Iemand schakelt privacymodus in, afsluiten"), + ("Unsupported", "Niet Ondersteund"), + ("Peer denied", "Peer geweigerd"), + ("Please install plugins", "Installeer plugins"), + ("Peer exit", "Peer afgesloten"), + ("Failed to turn off", "Uitschakelen mislukt"), + ("Turned off", "Uitgeschakeld"), + ("In privacy mode", "In privacymodus"), + ("Out privacy mode", Uit privacymodus""), + ("Language", "Taal"), + ("Keep RustDesk background service", "RustDesk achtergronddienst behouden"), + ("Ignore Battery Optimizations", "Negeer Batterij Optimalisaties"), + ("android_open_battery_optimizations_tip", "Ga naar de volgende pagina met instellingen"), + ("Connection not allowed", "Verbinding niet toegestaan"), + ("Use temporary password", "Tijdelijk wachtwoord gebruiken"), + ("Use permanent password", "Gebruik permanent wachtwoord"), + ("Use both passwords", "Gebruik beide wachtwoorden"), + ("Set permanent password", "Stel permanent wachtwoord in"), + ("Set temporary password length", "Lengte tijdelijk wachtwoord instellen"), + ("Enable Remote Restart", "Schakel Herstart op afstand in"), + ("Allow remote restart", "Opnieuw Opstarten op afstand toestaan"), + ("Restart Remote Device", "Apparaat op afstand herstarten"), + ("Are you sure you want to restart", "Weet je zeker dat je wilt herstarten"), + ("Restarting Remote Device", "Apparaat op afstand herstarten"), + ("remote_restarting_tip", "Apparaat op afstand wordt opnieuw opgestart, sluit dit bericht en maak na een ogenblik opnieuw verbinding met het permanente wachtwoord."), + ].iter().cloned().collect(); +} From e3d00bc6a63f760611ddc08efc3372a7ab1c8755 Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Fri, 5 Aug 2022 14:33:07 +0200 Subject: [PATCH 19/33] Add Dutch translation --- src/lang.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/lang.rs b/src/lang.rs index 400c4dd95..38b97a41a 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -8,18 +8,18 @@ mod de; mod en; mod eo; mod es; -mod fr; mod hu; +mod fr; mod id; mod it; -mod ja; -mod pl; +mod nl; mod ptbr; mod ru; mod sk; mod tr; mod tw; mod vn; +mod pl; lazy_static::lazy_static! { pub static ref LANGS: Value = @@ -28,6 +28,7 @@ lazy_static::lazy_static! { ("it", "Italiano"), ("fr", "Français"), ("de", "Deutsch"), + ("nl","Nederlands"), ("cn", "简体中文"), ("tw", "繁體中文"), ("pt", "Português"), @@ -42,7 +43,6 @@ lazy_static::lazy_static! { ("tr", "Türkçe"), ("vn", "Tiếng Việt"), ("pl", "Polski"), - ("ja", "日本語"), ]); } @@ -89,19 +89,16 @@ pub fn translate_locale(name: String, locale: &str) -> String { "sk" => sk::T.deref(), "vn" => vn::T.deref(), "pl" => pl::T.deref(), - "ja" => ja::T.deref(), _ => en::T.deref(), }; 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(); - } + v.to_string() + } else { + if lang != "en" { + if let Some(v) = en::T.get(&name as &str) { + return v.to_string(); } - } else { - return v.to_string(); } + name } - name } From 8848b3e357ca685eec68bc7a901d09f96574632a Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Fri, 5 Aug 2022 14:34:49 +0200 Subject: [PATCH 20/33] Add new Dutch translation Add Dutch translation From e5e57943cb31ad6937d8b9d153e1ee73c6f6458a Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 5 Aug 2022 23:32:51 +0800 Subject: [PATCH 21/33] revert nl lang, because it screw up lang.rs, and nl.rs is not valid utf-8 file, can not be compiled --- src/lang.rs | 23 ++-- src/lang/nl.rs | 303 ------------------------------------------------- 2 files changed, 13 insertions(+), 313 deletions(-) delete mode 100644 src/lang/nl.rs diff --git a/src/lang.rs b/src/lang.rs index 38b97a41a..400c4dd95 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -8,18 +8,18 @@ mod de; mod en; mod eo; mod es; -mod hu; mod fr; +mod hu; mod id; mod it; -mod nl; +mod ja; +mod pl; mod ptbr; mod ru; mod sk; mod tr; mod tw; mod vn; -mod pl; lazy_static::lazy_static! { pub static ref LANGS: Value = @@ -28,7 +28,6 @@ lazy_static::lazy_static! { ("it", "Italiano"), ("fr", "Français"), ("de", "Deutsch"), - ("nl","Nederlands"), ("cn", "简体中文"), ("tw", "繁體中文"), ("pt", "Português"), @@ -43,6 +42,7 @@ lazy_static::lazy_static! { ("tr", "Türkçe"), ("vn", "Tiếng Việt"), ("pl", "Polski"), + ("ja", "日本語"), ]); } @@ -89,16 +89,19 @@ pub fn translate_locale(name: String, locale: &str) -> String { "sk" => sk::T.deref(), "vn" => vn::T.deref(), "pl" => pl::T.deref(), + "ja" => ja::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { - v.to_string() - } else { - if lang != "en" { - if let Some(v) = en::T.get(&name as &str) { - return v.to_string(); + if v.is_empty() { + if lang != "en" { + if let Some(v) = en::T.get(&name as &str) { + return v.to_string(); + } } + } else { + return v.to_string(); } - name } + name } diff --git a/src/lang/nl.rs b/src/lang/nl.rs deleted file mode 100644 index 5b2838bc1..000000000 --- a/src/lang/nl.rs +++ /dev/null @@ -1,303 +0,0 @@ -lazy_static::lazy_static! { -pub static ref T: std::collections::HashMap<&'static str, &'static str> = - [ - ("Status", "Status"), - ("Your Desktop", "Uw Bureaublad"), - ("desk_tip", "Uw bureaublad is toegankelijk via de ID en het wachtwoord hieronder."), - ("Password", "Wachtwoord"), - ("Ready", "Klaar"), - ("Established", "Bevestigd"), - ("connecting_status", "Verbinding maken met het RustDesk netwerk..."), - ("Enable Service", "Service Inschakelen"), - ("Start Service", "Start Service"), - ("Service is running", "De service draait."), - ("Service is not running", "De service draait niet"), - ("not_ready_status", "Niet klaar, controleer de netwerkverbinding"), - ("Control Remote Desktop", "Beheer Extern Bureaublad"), - ("Transfer File", "Bestand Overzetten"), - ("Connect", "Verbinden"), - ("Recent Sessions", "Recente Behandelingen"), - ("Address Book", "Adresboek"), - ("Confirmation", "Bevestiging"), - ("TCP Tunneling", "TCP Tunneling"), - ("Remove", "Verwijder"), - ("Refresh random password", "Vernieuw willekeurig wachtwoord"), - ("Set your own password", "Stel je eigen wachtwoord in"), - ("Enable Keyboard/Mouse", "Toetsenbord/Muis Inschakelen"), - ("Enable Clipboard", "Klembord Inschakelen"), - ("Enable File Transfer", "Bestandsoverdracht Inschakelen"), - ("Enable TCP Tunneling", "TCP Tunneling Inschakelen"), - ("IP Whitelisting", "IP Witte Lijst"), - ("ID/Relay Server", "ID/Relay Server"), - ("Stop service", "Stop service"), - ("Change ID", "Wijzig ID"), - ("Website", "Website"), - ("About", "Over"), - ("Mute", "Geluid uit"), - ("Audio Input", "Audio Ingang"), - ("Enhancements", "Verbeteringen"), - ("Hardware Codec", "Hardware Codec"), - ("Adaptive Bitrate", "Aangepaste Bitsnelheid"), - ("ID Server", "ID Server"), - ("Relay Server", "Relay Server"), - ("API Server", "API Server"), - ("invalid_http", "Moet beginnen met http:// of https://"), - ("Invalid IP", "Ongeldig IP"), - ("id_change_tip", "Alleen de letters a-z, A-Z, 0-9, _ (underscore) kunnen worden gebruikt. De eerste letter moet a-z, A-Z zijn. De lengte moet tussen 6 en 16 liggen."), - ("Invalid format", "Ongeldig formaat"), - ("server_not_support", "Nog niet ondersteund door de server"), - ("Not available", "Niet beschikbaar"), - ("Too frequent", "Te vaak"), - ("Cancel", "Annuleer"), - ("Skip", "Overslaan"), - ("Close", "Sluit"), - ("Retry", "Probeer opnieuw"), - ("OK", "OK"), - ("Password Required", "Wachtwoord vereist"), - ("Please enter your password", "Voer uw wachtwoord in"), - ("Remember password", "Wachtwoord onthouden"), - ("Wrong Password", "Verkeerd wachtwoord"), - ("Do you want to enter again?", "Wil je opnieuw invoeren?"), - ("Connection Error", "Fout bij verbinding"), - ("Error", "Fout"), - ("Reset by the peer", "Reset door de peer"), - ("Connecting...", "Verbinding maken..."), - ("Connection in progress. Please wait.", "Verbinding in uitvoering. Even geduld a.u.b."), - ("Please try 1 minute later", "Probeer 1 minuut later"), - ("Login Error", "Login Fout"), - ("Successful", "Succesvol"), - ("Connected, waiting for image...", "Verbonden, wacht op beeld..."), - ("Name", "Naam"), - ("Type", "Type"), - ("Modified", "Gewijzigd"), - ("Size", "Grootte"), - ("Show Hidden Files", "Verborgen bestanden tonen"), - ("Receive", "Ontvangen"), - ("Send", "Verzenden"), - ("Refresh File", "Bestand Verversen"), - ("Local", "Lokaal"), - ("Remote", "Op afstand"), - ("Remote Computer", "Externe Computer"), - ("Local Computer", "Locale Computer"), - ("Confirm Delete", "Bevestig Verwijderen"), - ("Delete", "Verwijder"), - ("Properties", "Eigenschappen"), - ("Multi Select", "Meervoudig selecteren"), - ("Empty Directory", "Lege Map"), - ("Not an empty directory", "Geen Lege Map"), - ("Are you sure you want to delete this file?", "Weet je zeker dat je dit bestand wilt verwijderen?"), - ("Are you sure you want to delete this empty directory?", "Weet je zeker dat je deze lege map wilt verwijderen?"), - ("Are you sure you want to delete the file of this directory?", "Weet je zeker dat je het bestand uit deze map wilt verwijderen?"), - ("Do this for all conflicts", "Doe dit voor alle conflicten"), - ("This is irreversible!", "Dit is onomkeerbaar!"), - ("Deleting", "Verwijderen"), - ("files", "bestanden"), - ("Waiting", "Wachten"), - ("Finished", "Voltooid"), - ("Speed", "Snelheid"), - ("Custom Image Quality", "Aangepaste beeldkwaliteit"), - ("Privacy mode", "Privacymodus"), - ("Block user input", "Gebruikersinvoer blokkeren"), - ("Unblock user input", "Gebruikersinvoer opheffen"), - ("Adjust Window", "Venster Aanpassen"), - ("Original", "Origineel"), - ("Shrink", "Verkleinen"), - ("Stretch", "Uitrekken"), - ("Good image quality", "Goede beeldkwaliteit"), - ("Balanced", "Gebalanceerd"), - ("Optimize reaction time", "Optimaliseer reactietijd"), - ("Custom", "Aangepast"), - ("Show remote cursor", "Toon cursor op extern bureaublad"), - ("Show quality monitor", "Kwaliteitsmonitor tonen"), - ("Disable clipboard", "Klembord uitschakelen"), - ("Lock after session end", "Vergrendelen na einde sessie"), - ("Insert", "Invoegen"), - ("Insert Lock", "Vergrendeling Invoegen"), - ("Refresh", "Vernieuwen"), - ("ID does not exist", "ID bestaat niet"), - ("Failed to connect to rendezvous server", "Verbinding met rendez-vous-server mislukt"), - ("Please try later", "Probeer later opnieuw"), - ("Remote desktop is offline", "Extern bureaublad is offline"), - ("Key mismatch", "Code onjuist"), - ("Timeout", "Time-out"), - ("Failed to connect to relay server", "Verbinding met relayserver mislukt"), - ("Failed to connect via rendezvous server", "Verbinding via rendez-vous-server mislukt"), - ("Failed to connect via relay server", "Verbinding via relaisserver mislukt"), - ("Failed to make direct connection to remote desktop", "Onmogelijk direct verbinding te maken met extern bureaublad"), - ("Set Password", "Wachtwoord Instellen"), - ("OS Password", "OS Wachtwoord"), - ("install_tip", "Je gebruikt een niet genstalleerde versie. Als gevolg van UAC-beperkingen is het in sommige gevallen niet mogelijk om als controleterminal de muis en het toetsenbord te bedienen of het scherm over te nemen. Klik op de knop hieronder om RustDesk op het systeem te installeren om het bovenstaande probleem te voorkomen."), - ("Click to upgrade", "Klik voor upgrade"), - ("Click to download", "Klik om te downloaden"), - ("Click to update", "Klik om bij te werken"), - ("Configure", "Configureren"), - ("config_acc", "Om je bureaublad op afstand te kunnen bedienen, moet je RustDesk \"toegankelijkheid\" toestemming geven."), - ("config_screen", "Om toegang te krijgen tot het externe bureaublad, moet je RustDesk de toestemming \"schermregistratie\" geven."), - ("Installing ...", "Installeren ..."), - ("Install", "Installeer"), - ("Installation", "Installatie"), - ("Installation Path", "Installatie Pad"), - ("Create start menu shortcuts", "Startmenu snelkoppelingen maken"), - ("Create desktop icon", "Bureaubladpictogram maken"), - ("agreement_tip", "Het starten van de installatie betekent het accepteren van de licentieovereenkomst."), - ("Accept and Install", "Accepteren en installeren"), - ("End-user license agreement", "Licentieovereenkomst eindgebruiker"), - ("Generating ...", "Genereert ..."), - ("Your installation is lower version.", "Uw installatie is een lagere versie."), - ("not_close_tcp_tip", "Gelieve dit venster niet te sluiten wanneer u de tunnel gebruikt"), - ("Listening ...", "Luisteren ..."), - ("Remote Host", "Externe Host"), - ("Remote Port", "Externe Poort"), - ("Action", "Actie"), - ("Add", "Toevoegen"), - ("Local Port", "Lokale Poort"), - ("setup_server_tip", "Als u een snellere verbindingssnelheid nodig heeft, kunt u ervoor kiezen om uw eigen server te creren"), - ("Too short, at least 6 characters.", "Te kort, minstens 6 tekens."), - ("The confirmation is not identical.", "De bevestiging is niet identiek."), - ("Permissions", "Machtigingen"), - ("Accept", "Accepteren"), - ("Dismiss", "Afwijzen"), - ("Disconnect", "Verbinding verbreken"), - ("Allow using keyboard and mouse", "Gebruik toetsenbord en muis toestaan"), - ("Allow using clipboard", "Gebruik klembord toestaan"), - ("Allow hearing sound", "Geluidsweergave toestaan"), - ("Allow file copy and paste", "Kopiren en plakken van bestanden toestaan"), - ("Connected", "Verbonden"), - ("Direct and encrypted connection", "Directe en versleutelde verbinding"), - ("Relayed and encrypted connection", "Doorgeschakelde en versleutelde verbinding"), - ("Direct and unencrypted connection", "Directe en niet-versleutelde verbinding"), - ("Relayed and unencrypted connection", "Doorgeschakelde en niet-versleutelde verbinding"), - ("Enter Remote ID", "Voer Extern ID in"), - ("Enter your password", "Voer uw wachtwoord in"), - ("Logging in...", "Aanmelden..."), - ("Enable RDP session sharing", "Delen van RDP-sessie inschakelen"), - ("Auto Login", "Automatisch Aanmelden"), - ("Enable Direct IP Access", "Directe IP-toegang Inschakelen"), - ("Rename", "Naam wijzigen"), - ("Space", "Spatie"), - ("Create Desktop Shortcut", "Snelkoppeling op bureaublad maken"), - ("Change Path", "Pad wijzigen"), - ("Create Folder", "Map Maken"), - ("Please enter the folder name", "Geef de mapnaam op"), - ("Fix it", "Repareer het"), - ("Warning", "Waarschuwing"), - ("Login screen using Wayland is not supported", "Aanmeldingsscherm via Wayland wordt niet ondersteund"), - ("Reboot required", "Opnieuw opstarten vereist"), - ("Unsupported display server ", "Niet-ondersteunde weergaveserver"), - ("x11 expected", "x11 verwacht"), - ("Port", "Port"), - ("Settings", "Instellingen"), - ("Username", "Gebruikersnaam"), - ("Invalid port", "Ongeldige poort"), - ("Closed manually by the peer", "Handmatig gesloten door de peer"), - ("Enable remote configuration modification", "Wijziging configuratie op afstand inschakelen"), - ("Run without install", "Uitvoeren zonder installatie"), - ("Always connected via relay", "Altijd verbonden via relay"), - ("Always connect via relay", "Altijd verbinden via relay"), - ("whitelist_tip", "Alleen een IP-adres op de witte lijst krijgt toegang tot mijn toestel"), - ("Login", "Log In"), - ("Logout", "Log Uit"), - ("Tags", "Labels"), - ("Search ID", "Zoek ID"), - ("Current Wayland display server is not supported", "Huidige Wayland weergaveserver wordt niet ondersteund"), - ("whitelist_sep", "Gescheiden door komma, puntkomma, spatie of nieuwe regel"), - ("Add ID", "ID Toevoegen"), - ("Add Tag", "Label Toevoegen"), - ("Unselect all tags", "Alle labels verwijderen"), - ("Network error", "Netwerkfout"), - ("Username missed", "Gebruikersnaam gemist"), - ("Password missed", "Wachtwoord vergeten"), - ("Wrong credentials", "Verkeerde inloggegevens"), - ("Edit Tag", "Label Bewerken"), - ("Unremember Password", "Wachtwoord vergeten"), - ("Favorites", "Favorieten"), - ("Add to Favorites", "Toevoegen aan Favorieten"), - ("Remove from Favorites", "Verwijderen uit Favorieten"), - ("Empty", "Leeg"), - ("Invalid folder name", "Ongeldige mapnaam"), - ("Socks5 Proxy", "Socks5 Proxy"), - ("Hostname", "Hostnaam"), - ("Discovered", "Ontdekt"), - ("install_daemon_tip", "Om bij het opstarten van de computer te kunnen beginnen, moet je de systeemdienst installeren."), - ("Remote ID", "Externe ID"), - ("Paste", "Plakken"), - ("Paste here?", "Hier plakken"), - ("Are you sure to close the connection?", "Weet je zeker dat je de verbinding wilt sluiten?"), - ("Download new version", "Download nieuwe versie"), - ("Touch mode", "Aanraak modus"), - ("Mouse mode", "Muismodus"), - ("One-Finger Tap", "En-Vinger Tik"), - ("Left Mouse", "Linkermuis"), - ("One-Long Tap", "n-Vinger-Lange-Tik"), - ("Two-Finger Tap", "Twee-Vingers-Tik"), - ("Right Mouse", "Rechter muis"), - ("One-Finger Move", "En-Vinger-Verplaatsing"), - ("Double Tap & Move", "Dubbel Tik en Verplaatsen"), - ("Mouse Drag", "Muis Slepen"), - ("Three-Finger vertically", "Drie-Vinger verticaal"), - ("Mouse Wheel", "Muiswiel"), - ("Two-Finger Move", "Twee-Vingers Verplaatsen"), - ("Canvas Move", "Canvas Verplaatsen"), - ("Pinch to Zoom", "Knijp om te Zoomen"), - ("Canvas Zoom", "Canvas Zoom"), - ("Reset canvas", "Reset canvas"), - ("No permission of file transfer", "Geen toestemming voor bestandsoverdracht"), - ("Note", "Opmerking"), - ("Connection", "Verbinding"), - ("Share Screen", "Scherm Delen"), - ("CLOSE", "SLUITEN"), - ("OPEN", "OPEN"), - ("Chat", "Chat"), - ("Total", "Totaal"), - ("items", "items"), - ("Selected", "Geselecteerd"), - ("Screen Capture", "Schermopname"), - ("Input Control", "Invoercontrole"), - ("Audio Capture", "Audio Opnemen"), - ("File Connection", "Bestandsverbinding"), - ("Screen Connection", "Schermverbinding"), - ("Do you accept?", "Sta je toe?"), - ("Open System Setting", "Systeeminstelling Openen"), - ("How to get Android input permission?", "Hoe krijg ik Android invoer toestemming?"), - ("android_input_permission_tip1", "Om ervoor te zorgen dat een extern apparaat uw Android-apparaat kan besturen via muis of aanraking, moet u RustDesk toestaan om de \"Toegankelijkheid"\ service te gebruiken."), - ("android_input_permission_tip2", "Ga naar de volgende pagina met systeeminstellingen, zoek en ga naar [Genstalleerde Services], schakel de service [RustDesk Input] in."), - ("android_new_connection_tip", "Er is een nieuw controleverzoek binnengekomen, dat uw huidige apparaat wil controleren."), - ("android_service_will_start_tip", "Als u \"Schermopname\" inschakelt, wordt de service automatisch gestart, zodat andere apparaten een verbinding met uw apparaat kunnen aanvragen."), - ("android_stop_service_tip", "Het sluiten van de service zal automatisch alle gemaakte verbindingen sluiten."), - ("android_version_audio_tip", "De huidige versie van Android ondersteunt geen audio-opname, upgrade naar Android 10 of hoger."), - ("android_start_service_tip", "Druk op [Start Service] of op de permissie OPEN [Screenshot] om de service voor het overnemen van het scherm te starten."), - ("Account", "Account"), - ("Overwrite", "Overschrijven"), - ("This file exists, skip or overwrite this file?", "Dit bestand bestaat reeds, overslaan of overschrijven?"), - ("Quit", "Afsluiten"), - ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), - ("Help", "https://rustdesk.com/docs/en/manual/linux/#x11-required"), - ("Failed", "Mislukt"), - ("Succeeded", "Geslaagd"), - ("Someone turns on privacy mode, exit", "Iemand schakelt privacymodus in, afsluiten"), - ("Unsupported", "Niet Ondersteund"), - ("Peer denied", "Peer geweigerd"), - ("Please install plugins", "Installeer plugins"), - ("Peer exit", "Peer afgesloten"), - ("Failed to turn off", "Uitschakelen mislukt"), - ("Turned off", "Uitgeschakeld"), - ("In privacy mode", "In privacymodus"), - ("Out privacy mode", Uit privacymodus""), - ("Language", "Taal"), - ("Keep RustDesk background service", "RustDesk achtergronddienst behouden"), - ("Ignore Battery Optimizations", "Negeer Batterij Optimalisaties"), - ("android_open_battery_optimizations_tip", "Ga naar de volgende pagina met instellingen"), - ("Connection not allowed", "Verbinding niet toegestaan"), - ("Use temporary password", "Tijdelijk wachtwoord gebruiken"), - ("Use permanent password", "Gebruik permanent wachtwoord"), - ("Use both passwords", "Gebruik beide wachtwoorden"), - ("Set permanent password", "Stel permanent wachtwoord in"), - ("Set temporary password length", "Lengte tijdelijk wachtwoord instellen"), - ("Enable Remote Restart", "Schakel Herstart op afstand in"), - ("Allow remote restart", "Opnieuw Opstarten op afstand toestaan"), - ("Restart Remote Device", "Apparaat op afstand herstarten"), - ("Are you sure you want to restart", "Weet je zeker dat je wilt herstarten"), - ("Restarting Remote Device", "Apparaat op afstand herstarten"), - ("remote_restarting_tip", "Apparaat op afstand wordt opnieuw opgestart, sluit dit bericht en maak na een ogenblik opnieuw verbinding met het permanente wachtwoord."), - ].iter().cloned().collect(); -} From 2f8b300518f6c887c6f5f88c814c123b928e0cca Mon Sep 17 00:00:00 2001 From: Crashys <99598990+crashys@users.noreply.github.com> Date: Mon, 8 Aug 2022 14:08:58 +0200 Subject: [PATCH 22/33] Create pt_PT New language translation (Portuguese / Portugal) --- src/lang/pt_PT | 303 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/lang/pt_PT diff --git a/src/lang/pt_PT b/src/lang/pt_PT new file mode 100644 index 000000000..e6e282575 --- /dev/null +++ b/src/lang/pt_PT @@ -0,0 +1,303 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "Estado"), + ("Your Desktop", "Ambiente de Trabalho"), + ("desk_tip", "O seu Ambiente de Trabalho pode ser acedido com este ID e palavra-passe."), + ("Password", "Senha"), + ("Ready", "Pronto"), + ("Established", "Estabelecido"), + ("connecting_status", "A ligar à rede do RustDesk..."), + ("Enable Service", "Activar Serviço"), + ("Start Service", "Iniciar Serviço"), + ("Service is running", "Serviço está activo"), + ("Service is not running", "Serviço não está activo"), + ("not_ready_status", "Indisponível. Por favor verifique a sua ligação"), + ("Control Remote Desktop", "Controle o Ambiente de Trabalho à distância"), + ("Transfer File", "Transferir Ficheiro"), + ("Connect", "Ligar"), + ("Recent Sessions", "Sessões recentes"), + ("Address Book", "Lista de Endereços"), + ("Confirmation", "Confirmação"), + ("TCP Tunneling", "Túnel TCP"), + ("Remove", "Remover"), + ("Refresh random password", "Actualizar palavra-chave"), + ("Set your own password", "Configure a sua palavra-passe"), + ("Enable Keyboard/Mouse", "Activar Teclado/Rato"), + ("Enable Clipboard", "Activar Área de Transferência"), + ("Enable File Transfer", "Activar Transferência de Ficheiros"), + ("Enable TCP Tunneling", "Activar Túnel TCP"), + ("IP Whitelisting", "Whitelist de IP"), + ("ID/Relay Server", "Servidor ID/Relay"), + ("Stop service", "Parar serviço"), + ("Change ID", "Alterar ID"), + ("Website", "Website"), + ("About", "Sobre"), + ("Mute", "Emudecer"), + ("Audio Input", "Entrada de Áudio"), + ("Enhancements", "Melhorias"), + ("Hardware Codec", ""), + ("Adaptive Bitrate", ""), + ("ID Server", "Servidor de ID"), + ("Relay Server", "Servidor de Relay"), + ("API Server", "Servidor da API"), + ("invalid_http", "deve iniciar com http:// ou https://"), + ("Invalid IP", "IP inválido"), + ("id_change_tip", "Somente os caracteres a-z, A-Z, 0-9 e _ (sublinhado) são permitidos. A primeira letra deve ser a-z, A-Z. Comprimento entre 6 e 16."), + ("Invalid format", "Formato inválido"), + ("server_not_support", "Ainda não suportado pelo servidor"), + ("Not available", "Indisponível"), + ("Too frequent", "Muito frequente"), + ("Cancel", "Cancelar"), + ("Skip", "Passar"), + ("Close", "Fechar"), + ("Retry", "Tentar novamente"), + ("OK", "Confirmar"), + ("Password Required", "Palavra-chave Necessária"), + ("Please enter your password", "Por favor introduza a sua palavra-chave"), + ("Remember password", "Memorizar palavra-chave"), + ("Wrong Password", "Palavra-chave inválida"), + ("Do you want to enter again?", "Deseja tentar novamente??"), + ("Connection Error", "Erro de Ligação"), + ("Error", "Erro"), + ("Reset by the peer", "Reiniciado pelo destino"), + ("Connecting...", "A Ligar..."), + ("Connection in progress. Please wait.", "Ligação em progresso. Aguarde por favor."), + ("Please try 1 minute later", "Por favor tente após 1 minuto"), + ("Login Error", "Erro de Login"), + ("Successful", "Sucesso"), + ("Connected, waiting for image...", "Ligado. A aguardar pela imagem..."), + ("Name", "Nome"), + ("Type", "Tipo"), + ("Modified", "Modificado"), + ("Size", "Tamanho"), + ("Show Hidden Files", "Mostrar Ficheiros Ocultos"), + ("Receive", "Receber"), + ("Send", "Enviar"), + ("Refresh File", "Actualizar Ficheiro"), + ("Local", "Local"), + ("Remote", "Remoto"), + ("Remote Computer", "Computador Remoto"), + ("Local Computer", "Computador Local"), + ("Confirm Delete", "Confirmar Apagar"), + ("Delete", "Apagar"), + ("Properties", "Propriedades"), + ("Multi Select", "Selecção Múltipla"), + ("Empty Directory", "Directório Vazio"), + ("Not an empty directory", "Directório não está vazio"), + ("Are you sure you want to delete this file?", "Tem certeza que deseja apagar este ficheiro?"), + ("Are you sure you want to delete this empty directory?", "Tem certeza que deseja apagar este directório vazio?"), + ("Are you sure you want to delete the file of this directory?", "Tem certeza que deseja apagar este ficheiro deste directório?"), + ("Do this for all conflicts", "Fazer isto para todos os conflictos"), + ("This is irreversible!", "Isto é irreversível!"), + ("Deleting", "A apagar"), + ("files", "ficheiros"), + ("Waiting", "A aguardar"), + ("Finished", "Completo"), + ("Speed", "Velocidade"), + ("Custom Image Quality", "Qualidade Visual Personalizada"), + ("Privacy mode", "Modo privado"), + ("Block user input", "Bloquear entrada de utilizador"), + ("Unblock user input", "Desbloquear entrada de utilizador"), + ("Adjust Window", "Ajustar Janela"), + ("Original", "Original"), + ("Shrink", "Reduzir"), + ("Stretch", "Aumentar"), + ("Good image quality", "Qualidade visual boa"), + ("Balanced", "Equilibrada"), + ("Optimize reaction time", "Optimizar tempo de reacção"), + ("Custom", "Personalizado"), + ("Show remote cursor", "Mostrar cursor remoto"), + ("Show quality monitor", ""), + ("Disable clipboard", "Desabilitar área de transferência"), + ("Lock after session end", "Bloquear após o fim da sessão"), + ("Insert", "Inserir"), + ("Insert Lock", "Bloquear Inserir"), + ("Refresh", "Actualizar"), + ("ID does not exist", "ID não existente"), + ("Failed to connect to rendezvous server", "Falha ao ligar ao servidor de rendezvous"), + ("Please try later", "Por favor tente mais tarde"), + ("Remote desktop is offline", "Ambiente de trabalho remoto está desligado"), + ("Key mismatch", "Chaves incompatíveis"), + ("Timeout", "Tempo esgotado"), + ("Failed to connect to relay server", "Falha ao ligar ao servidor de relay"), + ("Failed to connect via rendezvous server", "Falha ao ligar ao servidor de rendezvous"), + ("Failed to connect via relay server", "Falha ao ligar através do servidor de relay"), + ("Failed to make direct connection to remote desktop", "Falha ao fazer ligação directa ao desktop remoto"), + ("Set Password", "Definir palavra-chave"), + ("OS Password", "Senha do SO"), + ("install_tip", "Devido ao UAC, o RustDesk não funciona correctamente em alguns casos. Para evitar o UAC, por favor clique no botão abaixo para instalar o RustDesk no sistema."), + ("Click to update", "Clique para fazer a actualização"), + ("Click to download", "Clique para carregar"), + ("Click to update", "Clique para fazer a actualização"), + ("Configure", "Configurar"), + ("config_acc", "Para controlar o seu Ambiente de Trabalho remotamente, é preciso conceder ao RustDesk permissões de \"Acessibilidade\"."), + ("config_screen", "Para aceder ao seu Ambiente de Trabalho remotamente, é preciso conceder ao RustDesk permissões de \"Gravar a Tela\"/"), + ("Installing ...", "A Instalar ..."), + ("Install", "Instalar"), + ("Installation", "Instalação"), + ("Installation Path", "Caminho da Instalação"), + ("Create start menu shortcuts", "Criar atalhos no menu iniciar"), + ("Create desktop icon", "Criar ícone no ambiente de trabalho"), + ("agreement_tip", "Ao iniciar a instalação, você concorda com o acordo de licença."), + ("Accept and Install", "Aceitar e Instalar"), + ("End-user license agreement", "Acordo de licença do utilizador final"), + ("Generating ...", "A Gerar ..."), + ("Your installation is lower version.", "A sua instalação é de uma versão anterior."), + ("not_close_tcp_tip", "Não feche esta janela enquanto estiver a utilizar o túnel"), + ("Listening ...", "A escuta ..."), + ("Remote Host", "Host Remoto"), + ("Remote Port", "Porta Remota"), + ("Action", "Acção"), + ("Add", "Adicionar"), + ("Local Port", "Porta Local"), + ("setup_server_tip", "Para uma ligação mais rápida, por favor configure seu próprio servidor"), + ("Too short, at least 6 characters.", "Muito curto, pelo menos 6 caracteres."), + ("The confirmation is not identical.", "A confirmação não é idêntica."), + ("Permissions", "Permissões"), + ("Accept", "Aceitar"), + ("Dismiss", "Dispensar"), + ("Disconnect", "Desconectar"), + ("Allow using keyboard and mouse", "Permitir o uso de teclado e rato"), + ("Allow using clipboard", "Permitir o uso da área de transferência"), + ("Allow hearing sound", "Permitir ouvir som"), + ("Allow file copy and paste", "Permitir copiar e mover ficheiros"), + ("Connected", "Ligado"), + ("Direct and encrypted connection", "Ligação directa e encriptada"), + ("Relayed and encrypted connection", "Ligação via relay e encriptada"), + ("Direct and unencrypted connection", "Ligação direta e não encriptada"), + ("Relayed and unencrypted connection", "Ligação via relay e não encriptada"), + ("Enter Remote ID", "Introduza o ID Remoto"), + ("Enter your password", "Introduza a sua palavra-chave"), + ("Logging in...", "A efectuar Login..."), + ("Enable RDP session sharing", "Activar partilha de sessão RDP"), + ("Auto Login", "Login Automático (Somente válido se você activou \"Bloquear após o fim da sessão\")"), + ("Enable Direct IP Access", "Activar Acesso IP Directo"), + ("Rename", "Renomear"), + ("Space", "Espaço"), + ("Create Desktop Shortcut", "Criar Atalho no Ambiente de Trabalho"), + ("Change Path", "Alterar Caminho"), + ("Create Folder", "Criar Diretório"), + ("Please enter the folder name", "Por favor introduza o nome do diretório"), + ("Fix it", "Reparar"), + ("Warning", "Aviso"), + ("Login screen using Wayland is not supported", "Tela de Login com Wayland não é suportada"), + ("Reboot required", "Reinicialização necessária"), + ("Unsupported display server ", "Servidor de display não suportado"), + ("x11 expected", "x11 em falha"), + ("Port", "Porta"), + ("Settings", "Configurações"), + ("Username", "Nome de utilizador"), + ("Invalid port", "Porta inválida"), + ("Closed manually by the peer", "Fechada manualmente pelo destino"), + ("Enable remote configuration modification", "Habilitar modificações de configuração remotas"), + ("Run without install", "Executar sem instalar"), + ("Always connected via relay", "Sempre conectado via relay"), + ("Always connect via relay", "Sempre conectar via relay"), + ("whitelist_tip", "Somente IPs na whitelist podem me acessar"), + ("Login", "Login"), + ("Logout", "Sair"), + ("Tags", "Tags"), + ("Search ID", "Procurar ID"), + ("Current Wayland display server is not supported", "Servidor de display Wayland atual não é suportado"), + ("whitelist_sep", "Separado por vírcula, ponto-e-vírgula, espaços ou nova linha"), + ("Add ID", "Adicionar ID"), + ("Add Tag", "Adicionar Tag"), + ("Unselect all tags", "Desselecionar todas as tags"), + ("Network error", "Erro de rede"), + ("Username missed", "Nome de utilizador em falta"), + ("Password missed", "Palavra-chave em falta"), + ("Wrong credentials", "Nome de utilizador ou palavra-chave incorrectos"), + ("Edit Tag", "Editar Tag"), + ("Unremember Password", "Esquecer Palavra-chave"), + ("Favorites", "Favoritos"), + ("Add to Favorites", "Adicionar aos Favoritos"), + ("Remove from Favorites", "Remover dos Favoritos"), + ("Empty", "Vazio"), + ("Invalid folder name", "Nome de diretório inválido"), + ("Socks5 Proxy", "Proxy Socks5"), + ("Hostname", "Nome de anfitrião"), + ("Discovered", "Descoberto"), + ("install_daemon_tip", "Para inicialização junto do sistema, deve instalar o serviço de sistema."), + ("Remote ID", "ID Remoto"), + ("Paste", "Colar"), + ("Paste here?", "Colar aqui?"), + ("Are you sure to close the connection?", "Tem certeza que deseja fechar a ligação?"), + ("Download new version", "Transferir nova versão"), + ("Touch mode", "Modo toque"), + ("Mouse mode", "Modo rato"), + ("One-Finger Tap", "Toque com um dedo"), + ("Left Mouse", "Botão esquerdo do rato"), + ("One-Long Tap", "Um toque longo"), + ("Two-Finger Tap", "Toque com dois dedos"), + ("Right Mouse", "Botão direito do rato"), + ("One-Finger Move", "Mover com um dedo"), + ("Double Tap & Move", "Toque duplo & mover"), + ("Mouse Drag", "Arrastar com o rato"), + ("Three-Finger vertically", "Três dedos verticalmente"), + ("Mouse Wheel", "Roda do rato"), + ("Two-Finger Move", "Mover com dois dedos"), + ("Canvas Move", "Mover Tela"), + ("Pinch to Zoom", "Beliscar para Zoom"), + ("Canvas Zoom", "Zoom na Tela"), + ("Reset canvas", "Reiniciar tela"), + ("No permission of file transfer", "Sem permissões de transferência de ficheiro"), + ("Note", "Nota"), + ("Connection", "Ligação"), + ("Share Screen", "Partilhar ecran"), + ("CLOSE", "FECHAR"), + ("OPEN", "ABRIR"), + ("Chat", "Conversar"), + ("Total", "Total"), + ("items", "itens"), + ("Selected", "Seleccionado"), + ("Screen Capture", "Captura de Ecran"), + ("Input Control", "Controle de Entrada"), + ("Audio Capture", "Captura de Áudio"), + ("File Connection", "Ligação de Arquivo"), + ("Screen Connection", "Ligação de Ecran"), + ("Do you accept?", "Aceita?"), + ("Open System Setting", "Abrir Configurações do Sistema"), + ("How to get Android input permission?", "Como activar a permissão de entrada do Android?"), + ("android_input_permission_tip1", "Para que um dispositivo remoto controle o seu dispositivo Android via rato ou toque, você precisa permitir que o RustDesk use o serviço \"Acessibilidade\"."), + ("android_input_permission_tip2", "Por favor vá para a próxima página de configuração do sistema, encontre e entre [Serviços Instalados], ACTIVE o serviço [RustDesk Input]."), + ("android_new_connection_tip", "Nova requisição de controle recebida, solicita o controle do seu dispositivo atual."), + ("android_service_will_start_tip", "Activar a Captura de Ecran irá automaticamente inicializar o serviço, permitindo que outros dispositivos solicitem uma ligação deste dispositivo."), + ("android_stop_service_tip", "Fechar o serviço irá automaticamente fechar todas as ligações estabelecidas."), + ("android_version_audio_tip", "A versão atual do Android não suporta captura de áudio, por favor actualize para o Android 10 ou maior."), + ("android_start_service_tip", "Toque [Iniciar Serviço] ou abra a permissão [Captura de Ecran] para iniciar o serviço de partilha de ecran."), + ("Account", "Conta"), + ("Overwrite", "Substituir"), + ("This file exists, skip or overwrite this file?", "Este ficheiro já existe, ignorar ou substituir este ficheiro?"), + ("Quit", "Saída"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), + ("Help", "Ajuda"), + ("Failed", "Falhou"), + ("Succeeded", "Conseguiu"), + ("Someone turns on privacy mode, exit", "Alguém activou o modo de privacidade, desligue"), + ("Unsupported", "Sem suporte"), + ("Peer denied", "Remoto negado"), + ("Please install plugins", "Por favor instale plugins"), + ("Peer exit", "Saída do Remoto"), + ("Failed to turn off", "Falha ao desligar"), + ("Turned off", "Desligado"), + ("In privacy mode", "Em modo de privacidade"), + ("Out privacy mode", "Sair do modo de privacidade"), + ("Language", "Linguagem"), + ("Keep RustDesk background service", "Manter o serviço RustDesk em funcionamento"), + ("Ignore Battery Optimizations", "Ignorar optimizações de Bateria"), + ("android_open_battery_optimizations_tip", ""), + ("Connection not allowed", "Ligação não autorizada"), + ("Use temporary password", "Utilizar palavra-chave temporária"), + ("Use permanent password", "Utilizar palavra-chave permanente"), + ("Use both passwords", "Utilizar ambas as palavras-chave"), + ("Set permanent password", "Definir palavra-chave permanente"), + ("Set temporary password length", "Definir tamanho de palavra-chave temporária"), + ("Enable Remote Restart", "Activar reiniciar remoto"), + ("Allow remote restart", "Permitir reiniciar remoto"), + ("Restart Remote Device", "Reiniciar Dispositivo Remoto"), + ("Are you sure you want to restart", "Tem a certeza que pretende reiniciar"), + ("Restarting Remote Device", "A reiniciar sistema remoto"), + ("remote_restarting_tip", ""), + ].iter().cloned().collect(); +} From 560d623e84e85b496f6e454472c25230b6fb27e1 Mon Sep 17 00:00:00 2001 From: rklein Date: Tue, 9 Aug 2022 12:19:03 +0200 Subject: [PATCH 23/33] fix #1226: add missing apt dependencies to Dockerfile Signed-off-by: rklein --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c08563614..5d15ff723 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM debian WORKDIR / -RUN apt update -y && apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo +RUN apt update -y && apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev RUN git clone https://github.com/microsoft/vcpkg && cd vcpkg && git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics From 780b42d0ba726d114431971c4f871388098978e6 Mon Sep 17 00:00:00 2001 From: kingtous Date: Wed, 10 Aug 2022 11:33:50 +0800 Subject: [PATCH 24/33] feat: adapt macos dark mode --- Cargo.lock | 334 +++++++++++++++++++++++++++++- Cargo.toml | 3 +- flutter/pubspec.lock | 308 +++++++++++++-------------- mac-tray.png => mac-tray-dark.png | Bin mac-tray-light.png | Bin 0 -> 475 bytes src/ui/macos.rs | 13 +- 6 files changed, 499 insertions(+), 159 deletions(-) rename mac-tray.png => mac-tray-dark.png (100%) create mode 100644 mac-tray-light.png diff --git a/Cargo.lock b/Cargo.lock index 2d9ac2cac..a6ed80add 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + [[package]] name = "ahash" version = "0.7.6" @@ -138,6 +144,17 @@ dependencies = [ "x11rb", ] +[[package]] +name = "async-broadcast" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61" +dependencies = [ + "event-listener", + "futures-core", + "parking_lot 0.12.1", +] + [[package]] name = "async-channel" version = "1.6.1" @@ -149,6 +166,20 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + [[package]] name = "async-io" version = "1.7.0" @@ -168,6 +199,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "async-lock" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +dependencies = [ + "event-listener", +] + [[package]] name = "async-process" version = "1.4.0" @@ -185,6 +225,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-task" version = "4.3.0" @@ -973,6 +1024,23 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "dark-light" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b83576e2eee2d9cdaa8d08812ae59cbfe1b5ac7ac5ac4b8400303c6148a88c1" +dependencies = [ + "dconf_rs", + "detect-desktop-environment", + "dirs", + "objc", + "rust-ini", + "web-sys", + "winreg 0.8.0", + "zbus", + "zvariant", +] + [[package]] name = "darling" version = "0.13.4" @@ -1138,6 +1206,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "dconf_rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" + [[package]] name = "default-net" version = "0.11.0" @@ -1160,6 +1234,23 @@ dependencies = [ "byteorder", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "detect-desktop-environment" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810" + [[package]] name = "digest" version = "0.10.3" @@ -1180,6 +1271,15 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -1190,6 +1290,17 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1216,6 +1327,15 @@ dependencies = [ "libloading", ] +[[package]] +name = "dlv-list" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "docopt" version = "1.1.1" @@ -1292,6 +1412,27 @@ dependencies = [ "syn", ] +[[package]] +name = "enumflags2" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" +dependencies = [ + "enumflags2_derive", + "serde 1.0.139", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -2094,13 +2235,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", ] [[package]] @@ -2163,6 +2313,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hound" version = "3.4.0" @@ -2318,7 +2474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg 1.1.0", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -3128,6 +3284,26 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "ordered-multimap" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" +dependencies = [ + "dlv-list", + "hashbrown 0.9.1", +] + +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_str_bytes" version = "6.2.0" @@ -3929,6 +4105,16 @@ dependencies = [ "which 3.1.1", ] +[[package]] +name = "rust-ini" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" +dependencies = [ + "cfg-if 1.0.0", + "ordered-multimap", +] + [[package]] name = "rust-pulsectl" version = "0.2.12" @@ -3977,6 +4163,7 @@ dependencies = [ "core-graphics 0.22.3", "cpal", "ctrlc", + "dark-light", "dasp", "default-net", "dispatch", @@ -4289,6 +4476,17 @@ dependencies = [ "serde 1.0.139", ] +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4335,6 +4533,21 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sha2" version = "0.10.2" @@ -4464,6 +4677,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.1.3" @@ -4854,7 +5073,7 @@ dependencies = [ "futures-io", "futures-sink", "futures-util", - "hashbrown", + "hashbrown 0.12.3", "pin-project-lite", "slab", "tokio", @@ -4963,6 +5182,16 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +[[package]] +name = "uds_windows" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi 0.3.9", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -5571,6 +5800,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "winreg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winreg" version = "0.10.1" @@ -5674,6 +5912,70 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "zbus" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8f1a037b2c4a67d9654dc7bdfa8ff2e80555bbefdd3c1833c1d1b27c963a6b" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "dirs", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "lazy_static", + "nix 0.23.1", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde 1.0.139", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi 0.3.9", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8fb5186d1c87ae88cf234974c240671238b4a679158ad3b94ec465237349a6" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_names" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a408fd8a352695690f53906dc7fd036be924ec51ea5e05666ff42685ed0af5" +dependencies = [ + "serde 1.0.139", + "static_assertions", + "zvariant", +] + [[package]] name = "zstd" version = "0.9.2+zstd.1.5.1" @@ -5702,3 +6004,29 @@ dependencies = [ "cc", "libc", ] + +[[package]] +name = "zvariant" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd68e4e6432ef19df47d7e90e2e72b5e7e3d778e0ae3baddf12b951265cc758" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde 1.0.139", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e977eaa3af652f63d479ce50d924254ad76722a6289ec1a1eac3231ca30430" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 7f185db6b..f48a47d9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ core-foundation = "0.9" core-graphics = "0.22" include_dir = "0.7.2" tray-item = "0.7" # looks better than trayicon +dark-light = "0.2" [target.'cfg(target_os = "linux")'.dependencies] psimple = { package = "libpulse-simple-binding", version = "2.25" } @@ -138,7 +139,7 @@ identifier = "com.carriez.rustdesk" icon = ["32x32.png", "128x128.png", "128x128@2x.png"] deb_depends = ["libgtk-3-0", "libxcb-randr0", "libxdo3", "libxfixes3", "libxcb-shape0", "libxcb-xfixes0", "libasound2", "libsystemd0", "pulseaudio", "python3-pip", "curl"] osx_minimum_system_version = "10.14" -resources = ["mac-tray.png"] +resources = ["mac-tray-light.png","mac-tray-dark.png"] #https://github.com/johnthagen/min-sized-rust [profile.release] diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index ec709b959..8af54209e 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -5,217 +5,217 @@ packages: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "3.3.0" + version: "3.3.1" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.0" cached_network_image: dependency: transitive description: name: cached_network_image - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.3.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.16.0" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "0.3.3" + version: "0.3.3+1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.0.4" + version: "1.0.5" dash_chat_2: dependency: "direct main" description: name: dash_chat_2 - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.0.12" device_info: dependency: "direct main" description: name: device_info - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.3" device_info_platform_interface: dependency: transitive description: name: device_info_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.1" draggable_float_widget: dependency: "direct main" description: name: draggable_float_widget - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.0.2" event_bus: dependency: transitive description: name: event_bus - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.0" external_path: dependency: "direct main" description: name: external_path - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.3.0" ffi: dependency: "direct main" description: name: ffi - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.2.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.1.2" firebase_analytics: dependency: "direct main" description: name: firebase_analytics - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "9.1.8" + version: "9.3.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "3.1.6" + version: "3.3.0" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "0.4.0+13" + version: "0.4.2" firebase_core: dependency: transitive description: name: firebase_core - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.17.0" + version: "1.20.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "4.4.0" + version: "4.5.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.6.4" + version: "1.7.1" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.1" flutter: @@ -227,58 +227,58 @@ packages: dependency: transitive description: name: flutter_blurhash - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.7.0" flutter_breadcrumb: dependency: "direct main" description: name: flutter_breadcrumb - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.1" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.3.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "0.9.2" + version: "0.9.3" flutter_parsed_text: dependency: transitive description: name: flutter_parsed_text - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.6" + version: "2.0.7" flutter_rust_bridge: dependency: "direct main" description: name: flutter_rust_bridge - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.30.0" + version: "1.41.0" flutter_smart_dialog: dependency: "direct main" description: name: flutter_smart_dialog - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "4.3.1" + version: "4.5.4+1" flutter_test: dependency: "direct dev" description: flutter @@ -293,301 +293,301 @@ packages: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.15.0" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "0.13.4" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "4.0.0" + version: "4.0.1" image: dependency: "direct main" description: name: image - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "3.1.3" + version: "3.2.0" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.8.5+3" image_picker_android: dependency: transitive description: name: image_picker_android - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "0.8.4+13" + version: "0.8.5+2" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.8" image_picker_ios: dependency: transitive description: name: image_picker_ios - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "0.8.5+2" + version: "0.8.5+6" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.5.0" + version: "2.6.1" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.17.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.6.4" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.4" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.7.0" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.0" octo_image: dependency: transitive description: name: octo_image - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.2" package_info: dependency: "direct main" description: name: package_info - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.2" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.8.1" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.10" + version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.14" + version: "2.0.17" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.9" + version: "2.0.11" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.1.6" + version: "2.1.7" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.6" + version: "2.0.7" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.11.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "4.4.0" + version: "5.0.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.2" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.0.3" qr_code_scanner: dependency: "direct main" description: name: qr_code_scanner - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.1.0" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.27.5" settings_ui: dependency: "direct main" description: name: settings_ui - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.2" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.15" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.1" sky_engine: @@ -599,259 +599,259 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.8.2" sqflite: dependency: transitive description: name: sqflite - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.3" + version: "2.0.3+1" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.1+1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.0+2" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.4.9" toggle_switch: dependency: "direct main" description: name: toggle_switch - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.0" tuple: dependency: "direct main" description: name: tuple - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.3.0" + version: "1.3.1" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "6.1.2" + version: "6.1.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "6.0.16" + version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.5" + version: "2.1.0" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.0.11" + version: "2.0.13" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.1" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.2" video_player: dependency: transitive description: name: video_player - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.4.5" + version: "2.4.6" video_player_android: dependency: transitive description: name: video_player_android - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.8" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.5" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "5.1.3" + version: "5.1.4" video_player_web: dependency: transitive description: name: video_player_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.12" wakelock: dependency: "direct main" description: name: wakelock - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.5.6" wakelock_macos: dependency: transitive description: name: wakelock_macos - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.4.0" wakelock_platform_interface: dependency: transitive description: name: wakelock_platform_interface - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.3.0" wakelock_web: dependency: transitive description: name: wakelock_web - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.4.0" wakelock_windows: dependency: transitive description: name: wakelock_windows - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.0" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.5.2" + version: "2.6.1" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.0+1" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "5.3.1" + version: "6.1.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.1.1" zxing2: dependency: "direct main" description: name: zxing2 - url: "https://pub.dartlang.org" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.0" sdks: diff --git a/mac-tray.png b/mac-tray-dark.png similarity index 100% rename from mac-tray.png rename to mac-tray-dark.png diff --git a/mac-tray-light.png b/mac-tray-light.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e107410ce32019410c055f63885874e97747cd GIT binary patch literal 475 zcmV<10VMv3P)Px$l}SWFR5(wC)61)mQ544U&l5%D4=@oEM^Ypc9fL!T7$Em3*C}N}Mh42vgc4Cw zl#p9;NiuNBz(^eiC_@HJC>bbQTl>}9$?3NzZ|}37_1$Z)y>^USrIZmIK>aSq6gIN6I0SHKAzYT^@&CaLBB zca>5eVs#6iseoGM!X|7^a&w~ORz*F=wdNVCfFGFFgrOww2LKkJHnFa674Q@F7V4Ut zg@-C#rWT&RFG=#S^FB$p?+ z#yz;$i;Z@JRHtxd3;f1eoa*{fN*Tgo?CYi%_mZsb05kCtvwQRkTG~eWMK7^h>P?L# z`P_d@vs!bO^dPk#({ZJzJ;jbBpQ`o`(1xVGyq(yMMOcMj?V-KGC0y@M>K_$GlQWUr RfZ_lE002ovPDHLkV1i>W*+&2X literal 0 HcmV?d00001 diff --git a/src/ui/macos.rs b/src/ui/macos.rs index 188fbb603..3c7a7dcd0 100644 --- a/src/ui/macos.rs +++ b/src/ui/macos.rs @@ -13,6 +13,7 @@ use objc::{ }; use sciter::{make_args, Host}; use std::{ffi::c_void, rc::Rc}; +use dark_light; static APP_HANDLER_IVAR: &str = "GoDeskAppHandler"; @@ -233,7 +234,17 @@ pub fn make_tray() { set_delegate(None); } use tray_item::TrayItem; - if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), "mac-tray.png") { + let mode = dark_light::detect(); + let mut icon_path = ""; + match mode { + dark_light::Mode::Dark => { + icon_path = "mac-tray-light.png"; + }, + dark_light::Mode::Light => { + icon_path = "mac-tray-dark.png"; + }, + } + if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), icon_path) { tray.add_label(&format!( "{} {}", crate::get_app_name(), From 91fd3c5442bf77dc70dd8b7b63a2217e9b9ff120 Mon Sep 17 00:00:00 2001 From: jkhsjdhjs Date: Thu, 11 Aug 2022 17:28:19 +0200 Subject: [PATCH 25/33] fix desktop entry categories The category "Other" isn't a valid category [1] and causes unwanted behavior on some DE's [2]. Thus I remove this category and add the main category "Network" instead. I also add the additional categories "RemoteAccess", since rustdesk is a tool to remotely access computers, and "GTK", because it's based on GTK libraries. [1] https://specifications.freedesktop.org/menu-spec/latest/apa.html [2] https://aur.archlinux.org/packages/rustdesk-bin#comment-877405 --- rustdesk.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustdesk.desktop b/rustdesk.desktop index 11c7daad0..c9cf1f254 100644 --- a/rustdesk.desktop +++ b/rustdesk.desktop @@ -8,7 +8,7 @@ Icon=/usr/share/rustdesk/files/rustdesk.png Terminal=false Type=Application StartupNotify=true -Categories=Other; +Categories=Network;RemoteAccess;GTK; Keywords=internet; Actions=new-window; From 3a5efb575ee33947f00f993d076f9a2056d11604 Mon Sep 17 00:00:00 2001 From: cooperbang <75366896+cooperbang@users.noreply.github.com> Date: Fri, 12 Aug 2022 12:44:25 +0200 Subject: [PATCH 26/33] Update AppImageBuilder.yml --- appimage/AppImageBuilder.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appimage/AppImageBuilder.yml b/appimage/AppImageBuilder.yml index 0ca62e97c..08a4f0786 100644 --- a/appimage/AppImageBuilder.yml +++ b/appimage/AppImageBuilder.yml @@ -40,12 +40,12 @@ AppDir: - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates universe - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic multiverse - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates multiverse - - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted - universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security main restricted - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security universe - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security multiverse include: + - libc6:amd64 - libgcc1:amd64 - libgcrypt20:amd64 - libgtk-3-0:amd64 @@ -95,4 +95,4 @@ AppDir: command: ./AppRun AppImage: arch: x86_64 - update-information: guess \ No newline at end of file + update-information: guess From 9fbb114301d729102534a3010b6455a7c8b55c78 Mon Sep 17 00:00:00 2001 From: kordood Date: Sun, 14 Aug 2022 14:03:17 +0900 Subject: [PATCH 27/33] Create ko.rs Signed-off-by: kordood --- src/lang/ko.rs | 303 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/lang/ko.rs diff --git a/src/lang/ko.rs b/src/lang/ko.rs new file mode 100644 index 000000000..a0292adcb --- /dev/null +++ b/src/lang/ko.rs @@ -0,0 +1,303 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "상태"), + ("Your Desktop", "당신의 데스크탑"), + ("desk_tip", "아래 ID와 비밀번호를 통해 당신의 데스크탑으로 접속할 수 있습니다."), + ("Password", "비밀번호"), + ("Ready", "준비"), + ("Established", "연결됨"), + ("connecting_status", "RustDesk 네트워크로 연결중입니다..."), + ("Enable Service", "서비스 활성화"), + ("Start Service", "서비스 시작"), + ("Service is running", "서비스 동작중"), + ("Service is not running", "서비스가 동작하고 있지 않습니다"), + ("not_ready_status", "준비되지 않음. 연결을 확인해주시길 바랍니다."), + ("Control Remote Desktop", "원격 데스크탑 제어"), + ("Transfer File", "파일 전송"), + ("Connect", "접속하기"), + ("Recent Sessions", "최근 세션"), + ("Address Book", "세션 주소록"), + ("Confirmation", "확인"), + ("TCP Tunneling", "TCP 터널링"), + ("Remove", "삭제"), + ("Refresh random password", "랜덤 비밀번호 새로고침"), + ("Set your own password", "개인 비밀번호 설정"), + ("Enable Keyboard/Mouse", "키보드/마우스 활성화"), + ("Enable Clipboard", "클립보드 활성화"), + ("Enable File Transfer", "파일 전송 활성화"), + ("Enable TCP Tunneling", "TCP 터널링 활성화"), + ("IP Whitelisting", "IP 화이트리스트"), + ("ID/Relay Server", "ID/Relay 서버"), + ("Stop service", "서비스 중단"), + ("Change ID", "ID 변경"), + ("Website", "웹사이트"), + ("About", "정보"), + ("Mute", "음소거"), + ("Audio Input", "오디오 입력"), + ("Enhancements", ""), + ("Hardware Codec", "하드웨어 코덱"), + ("Adaptive Bitrate", "가변 비트레이트"), + ("ID Server", "ID 서버"), + ("Relay Server", "Relay 서버"), + ("API Server", "API 서버"), + ("invalid_http", "다음과 같이 시작해야 합니다. http:// 또는 https://"), + ("Invalid IP", "유효하지 않은 IP"), + ("id_change_tip", "a-z, A-Z, 0-9, _(밑줄 문자)만 입력 가능합니다. 첫 문자는 a-z 혹은 A-Z로 시작해야 합니다. 길이는 6 ~ 16글자가 요구됩니다."), + ("Invalid format", "유효하지 않은 형식"), + ("server_not_support", "해당 서버가 아직 지원하지 않습니다"), + ("Not available", "불가능"), + ("Too frequent", "너무 잦은 시도"), + ("Cancel", "취소"), + ("Skip", "넘기기"), + ("Close", "닫기"), + ("Retry", "재시도"), + ("OK", "확인"), + ("Password Required", "비밀번호 입력"), + ("Please enter your password", "비밀번호를 입력해주세요"), + ("Remember password", "이 비밀번호 기억하기"), + ("Wrong Password", "틀린 비밀번호"), + ("Do you want to enter again?", "다시 접속하시겠습니까?"), + ("Connection Error", "연결 에러"), + ("Error", "에러"), + ("Reset by the peer", "다른 접속자에 의해 초기화됨"), + ("Connecting...", "연결중..."), + ("Connection in progress. Please wait.", "연결중입니다. 잠시만 기다려주세요."), + ("Please try 1 minute later", "1분 뒤 다시 시도해주세요"), + ("Login Error", "로그인 에러"), + ("Successful", "성공"), + ("Connected, waiting for image...", "연결됨. 이미지를 기다리는중..."), + ("Name", "이름"), + ("Type", "유형"), + ("Modified", "수정됨"), + ("Size", "크기"), + ("Show Hidden Files", "숨김 파일 보기"), + ("Receive", "받기"), + ("Send", "보내기"), + ("Refresh File", "파일 새로고침"), + ("Local", "로컬"), + ("Remote", "원격"), + ("Remote Computer", "원격 컴퓨터"), + ("Local Computer", "로컬 컴퓨터"), + ("Confirm Delete", "삭제 재확인"), + ("Delete", "삭제"), + ("Properties", "속성"), + ("Multi Select", "다중 선택"), + ("Empty Directory", "빈 디렉터리"), + ("Not an empty directory", "디렉터리가 비어있지 않습니다"), + ("Are you sure you want to delete this file?", "정말로 해당 파일을 삭제하시겠습니까?"), + ("Are you sure you want to delete this empty directory?", "정말로 비어있는 해당 디렉터리를 삭제하시겠습니까?"), + ("Are you sure you want to delete the file of this directory?", "정말로 해당 파일 혹은 디렉터리를 삭제하시겠습니까?"), + ("Do this for all conflicts", "모든 충돌에 대해 해당 작업 수행"), + ("This is irreversible!", "해당 결정은 돌이킬 수 없습니다!"), + ("Deleting", "삭제중"), + ("files", "파일"), + ("Waiting", "대기중"), + ("Finished", "완료됨"), + ("Speed", "속도"), + ("Custom Image Quality", "이미지 품질 조정"), + ("Privacy mode", "개인정보 보호 모드"), + ("Block user input", "사용자 입력 차단"), + ("Unblock user input", "사용자 입력 차단 해제"), + ("Adjust Window", "화면 조정"), + ("Original", "원본"), + ("Shrink", "축소"), + ("Stretch", "확대"), + ("Good image quality", "최적 이미지 품질"), + ("Balanced", "균형"), + ("Optimize reaction time", "반응 시간 최적화"), + ("Custom", "커스텀"), + ("Show remote cursor", "원격 커서 보이기"), + ("Show quality monitor", "품질 모니터 띄우기"), + ("Disable clipboard", "클립보드 비활성화"), + ("Lock after session end", "세션 종료 후 화면 잠금"), + ("Insert", "입력"), + ("Insert Lock", "입력 잠금"), + ("Refresh", "새로고침"), + ("ID does not exist", "ID가 존재하지 않습니다"), + ("Failed to connect to rendezvous server", "rendezvous 서버에 접속을 실패하였습니다"), + ("Please try later", "다시 시도해주세요"), + ("Remote desktop is offline", "원격 데스크탑이 연결되어 있지 않습니다"), + ("Key mismatch", "키가 일치하지 않습니다."), + ("Timeout", "시간 초과"), + ("Failed to connect to relay server", "relay 서버에 접속을 실패하였습니다"), + ("Failed to connect via rendezvous server", "rendezvous 서버를 통한 접속에 실패하였습니다"), + ("Failed to connect via relay server", "relay 서버를 통한 접속에 실패하였습니다"), + ("Failed to make direct connection to remote desktop", "원격 데스크탑으로의 직접 연결 생성에 실패하였습니다"), + ("Set Password", "비밀번호 설정"), + ("OS Password", "OS 비밀번호"), + ("install_tip", "UAC로 인해, RustDesk가 원격지일 때 일부 기능이 동작하지 않을 수 있습니다. UAC 문제를 방지하려면, 아래 버튼을 클릭하여 RustDesk를 시스템에 설치해주세요."), + ("Click to upgrade", "클릭하여 업그레이드"), + ("Click to download", "클릭하여 다운로드"), + ("Click to update", "클릭하여 업데이트"), + ("Configure", "구성"), + ("config_acc", "당신의 데스크탑을 원격으로 제어하기 전에, RustDesk에게 \"Accessibility (접근성)\" 권한을 부여해야 합니다."), + ("config_screen", "당신의 데스크탑을 원격으로 제어하기 전에, RustDesk에게 \"Screen Recording (화면 녹화)\" 권한을 부여해야 합니다."), + ("Installing ...", "설치중 ..."), + ("Install", "설치하기"), + ("Installation", "설치"), + ("Installation Path", "설치 경로"), + ("Create start menu shortcuts", "시작 메뉴에 바로가기 생성"), + ("Create desktop icon", "데스크탑 아이콘 생성"), + ("agreement_tip", "설치를 시작하기 전에, 라이선스 약관에 동의를 해야합니다."), + ("Accept and Install", "동의 및 설치"), + ("End-user license agreement", "최종 사용자 라이선스 약관 동의"), + ("Generating ...", "생성중 ..."), + ("Your installation is lower version.", "설치 버전이 최신 버전이 아닙니다."), + ("not_close_tcp_tip", "연결을 사용하는 동안 이 창을 끄지 마세요"), + ("Listening ...", "연결 대기중 ..."), + ("Remote Host", "원격 호스트"), + ("Remote Port", "원격 포트"), + ("Action", "액션"), + ("Add", "추가"), + ("Local Port", "로컬 포트"), + ("setup_server_tip", "빠른 접속을 위해, 당신의 서버를 설정하세요"), + ("Too short, at least 6 characters.", "너무 짧습니다, 최소 6글자 이상 입력해주세요."), + ("The confirmation is not identical.", "확인용 입력이 일치하지 않습니다."), + ("Permissions", "권한"), + ("Accept", "수락"), + ("Dismiss", "거부"), + ("Disconnect", "연결 종료"), + ("Allow using keyboard and mouse", "키보드와 마우스 허용"), + ("Allow using clipboard", "클립보드 허용"), + ("Allow hearing sound", "소리 듣기 허용"), + ("Allow file copy and paste", "파일 복사 및 붙여넣기 허용"), + ("Connected", "연결됨"), + ("Direct and encrypted connection", "암호화된 직접 연결"), + ("Relayed and encrypted connection", "암호화된 릴레이 연결"), + ("Direct and unencrypted connection", "암호화되지 않은 직접 연결"), + ("Relayed and unencrypted connection", "암호화되지 않은 릴레이 연결"), + ("Enter Remote ID", "원격지 ID를 입력하세요"), + ("Enter your password", "비밀번호를 입력하세요"), + ("Logging in...", "로그인 중..."), + ("Enable RDP session sharing", "RDP 세션 공유를 활성화하세요"), + ("Auto Login", "자동 로그인"), + ("Enable Direct IP Access", "IP 직접 접근 활성화하세요"), + ("Rename", "이름 변경"), + ("Space", "공간"), + ("Create Desktop Shortcut", "데스크탑 바로가기 생성"), + ("Change Path", "경로 변경"), + ("Create Folder", "폴더 생성"), + ("Please enter the folder name", "폴더명을 입력해주세요"), + ("Fix it", "문제 해결"), + ("Warning", "경고"), + ("Login screen using Wayland is not supported", "Wayland를 사용한 로그인 화면이 지원되지 않습니다"), + ("Reboot required", "재부팅이 필요합니다"), + ("Unsupported display server ", "지원하지 않는 디스플레이 서버"), + ("x11 expected", "x11 예상됨"), + ("Port", "포트"), + ("Settings", "설정"), + ("Username", "사용자명"), + ("Invalid port", "유효하지 않은 포트"), + ("Closed manually by the peer", "다른 사용자에 의해 종료됨"), + ("Enable remote configuration modification", "원격 구성 변경 활성화"), + ("Run without install", "설치 없이 실행"), + ("Always connected via relay", "항상 relay를 통해 접속됨"), + ("Always connect via relay", "항상 relay를 통해 접속하기"), + ("whitelist_tip", "화이트리스트에 있는 IP만 현 데스크탑에 접속 가능합니다"), + ("Login", "로그인"), + ("Logout", "로그아웃"), + ("Tags", "태그"), + ("Search ID", "ID 검색"), + ("Current Wayland display server is not supported", "현재 Wayland 디스플레이 서버가 지원되지 않습니다"), + ("whitelist_sep", "다음 글자로 구분합니다. ',(콤마) ;(세미콜론) 띄어쓰기 혹은 줄바꿈'"), + ("Add ID", "ID 추가"), + ("Add Tag", "태그 추가"), + ("Unselect all tags", "모든 태그 선택 해제"), + ("Network error", "네트워크 에러"), + ("Username missed", "사용자명 누락"), + ("Password missed", "비밀번호 누락"), + ("Wrong credentials", "틀린 인증 정보"), + ("Edit Tag", "태그 수정"), + ("Unremember Password", "패스워드 기억하지 않기"), + ("Favorites", "즐겨찾기"), + ("Add to Favorites", "즐겨찾기에 추가"), + ("Remove from Favorites", "즐겨찾기에서 삭제"), + ("Empty", "비어 있음"), + ("Invalid folder name", "유효하지 않은 폴더명"), + ("Socks5 Proxy", "Socks5 프록시"), + ("Hostname", "호스트명"), + ("Discovered", "찾음"), + ("install_daemon_tip", "부팅된 이후 시스템 서비스에 설치해야 합니다."), + ("Remote ID", "원격지 ID"), + ("Paste", "붙여넣기"), + ("Paste here?", "여기에 붙여넣겠습니까?"), + ("Are you sure to close the connection?", "정말로 연결을 종료하시겠습니까?"), + ("Download new version", "최신 버전 다운로드"), + ("Touch mode", "터치 모드"), + ("Mouse mode", "마우스 모드"), + ("One-Finger Tap", "한 손가락 탭"), + ("Left Mouse", "왼쪽 마우스"), + ("One-Long Tap", "길게 누르기"), + ("Two-Finger Tap", "두 손가락 탭"), + ("Right Mouse", "오른쪽 마우스"), + ("One-Finger Move", "한 손가락 이동"), + ("Double Tap & Move", "두 번 탭 하고 이동"), + ("Mouse Drag", "마우스 드래그"), + ("Three-Finger vertically", "세 손가락 세로로"), + ("Mouse Wheel", "마우스 휠"), + ("Two-Finger Move", "두 손가락 이동"), + ("Canvas Move", "캔버스 이동"), + ("Pinch to Zoom", "확대/축소"), + ("Canvas Zoom", "캔버스 확대"), + ("Reset canvas", "캔버스 초기화"), + ("No permission of file transfer", "파일 전송 권한이 없습니다"), + ("Note", "노트"), + ("Connection", "연결"), + ("Share Screen", "화면 공유"), + ("CLOSE", "종료"), + ("OPEN", "열기"), + ("Chat", "채팅"), + ("Total", "총합"), + ("items", "개체"), + ("Selected", "선택됨"), + ("Screen Capture", "화면 캡처"), + ("Input Control", "입력 제어"), + ("Audio Capture", "오디오 캡처"), + ("File Connection", "파일 전송"), + ("Screen Connection", "화면 전송"), + ("Do you accept?", "동의하십니까?"), + ("Open System Setting", "시스템 설정 열기"), + ("How to get Android input permission?", "안드로이드 입력 권한에 어떻게 접근합니까?"), + ("android_input_permission_tip1", "원격지로서 마우스나 터치를 통해 Android 장치를 제어하려면 RustDesk에서 \"Accessibility (접근성)\" 서비스 사용을 허용해야 합니다."), + ("android_input_permission_tip2", "시스템 설정 페이지로 이동하여 [설치된 서비스]에서 [RustDesk Input] 서비스를 켜십시오."), + ("android_new_connection_tip", "현재 장치의 새로운 제어 요청이 수신되었습니다."), + ("android_service_will_start_tip", "\"화면 캡처\"를 켜면 서비스가 자동으로 시작되어 다른 장치에서 사용자 장치에 대한 연결을 요청할 수 있습니다."), + ("android_stop_service_tip", "서비스를 종료하면 모든 연결이 자동으로 닫힙니다."), + ("android_version_audio_tip", "현재 Android 버전은 오디오 캡처를 지원하지 않습니다. Android 10 이상으로 업그레이드하십시오."), + ("android_start_service_tip", "[서비스 시작] 또는 [화면 캡처] 권한을 눌러 화면 공유 서비스를 시작합니다."), + ("Account", "계정"), + ("Overwrite", "덮어쓰기"), + ("This file exists, skip or overwrite this file?", "해당 파일이 이미 존재합니다, 넘어가거나 덮어쓰시겠습니까?"), + ("Quit", "종료"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), + ("Help", "지원"), + ("Failed", "실패"), + ("Succeeded", "성공"), + ("Someone turns on privacy mode, exit", "누군가가 개인정보 보호 모드를 활성화하여 종료됩니다"), + ("Unsupported", "지원되지 않음"), + ("Peer denied", "다른 사용자에 의해 거부됨"), + ("Please install plugins", "플러그인을 설치해주세요"), + ("Peer exit", "다른 사용자가 나감"), + ("Failed to turn off", "종료에 실패함"), + ("Turned off", "종료됨"), + ("In privacy mode", "개인정보 보호 모드 진입"), + ("Out privacy mode", "개인정보 보호 모드 나감"), + ("Language", "언어"), + ("Keep RustDesk background service", "RustDesk 백그라운드 서비스로 유지하기"), + ("Ignore Battery Optimizations", "배터리 최적화 무시하기"), + ("android_open_battery_optimizations_tip", "해당 기능을 비활성화하려면 RustDesk 응용 프로그램 설정 페이지로 이동하여 [배터리]에서 [제한 없음] 선택을 해제하십시오."), + ("Connection not allowed", "연결이 허용되지 않음"), + ("Use temporary password", "임시 비밀번호 사용"), + ("Use permanent password", "영구 비밀번호 사용"), + ("Use both passwords", "두 비밀번호 (임시/영구) 사용"), + ("Set permanent password", "영구 비밀번호 설정"), + ("Set temporary password length", "임시 비밀번호 길이 설정"), + ("Enable Remote Restart", "원격지 재시작 활성화"), + ("Allow remote restart", "원격지 재시작 허용"), + ("Restart Remote Device", "원격 기기 재시작"), + ("Are you sure you want to restart", "정말로 재시작 하시겠습니까"), + ("Restarting Remote Device", "원격 기기를 다시 시작하는중"), + ("remote_restarting_tip", "원격 장치를 다시 시작하는 중입니다. 이 메시지 상자를 닫고 잠시 후 영구 비밀번호로 다시 연결하십시오."), + ].iter().cloned().collect(); +} \ No newline at end of file From 7cb9540c3fb4630cb7a2c9d38a7190b775202e67 Mon Sep 17 00:00:00 2001 From: Software Magic <16600519+SoftwareMagicIT@users.noreply.github.com> Date: Sun, 14 Aug 2022 10:17:53 +0200 Subject: [PATCH 28/33] Added missing translation and changed some mistakes My first contribute. I added missing translations and changed some mistakes --- src/lang/it.rs | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/lang/it.rs b/src/lang/it.rs index 8058806c2..f608753e1 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -35,9 +35,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("About", "Informazioni"), ("Mute", "Silenzia"), ("Audio Input", "Input audio"), - ("Enhancements", ""), - ("Hardware Codec", ""), - ("Adaptive Bitrate", ""), + ("Enhancements", "Miglioramenti"), + ("Hardware Codec", "Codifica Hardware"), + ("Adaptive Bitrate", "Bitrate Adattivo"), ("ID Server", "ID server"), ("Relay Server", "Server relay"), ("API Server", "Server API"), @@ -53,10 +53,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Close", "Chiudi"), ("Retry", "Riprova"), ("OK", "OK"), - ("Password Required", "Password richiesta"), + ("Password Required", "Password Richiesta"), ("Please enter your password", "Inserisci la tua password"), ("Remember password", "Ricorda password"), - ("Wrong Password", "Password errata"), + ("Wrong Password", "Password Errata"), ("Do you want to enter again?", "Vuoi riprovare?"), ("Connection Error", "Errore di connessione"), ("Error", "Errore"), @@ -64,7 +64,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Connecting...", "Connessione..."), ("Connection in progress. Please wait.", "Connessione in corso. Attendi."), ("Please try 1 minute later", "Per favore riprova fra 1 minuto"), - ("Login Error", "Errore di login"), + ("Login Error", "Errore Login"), ("Successful", "Successo"), ("Connected, waiting for image...", "Connesso, in attesa dell'immagine..."), ("Name", "Nome"), @@ -101,8 +101,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Unblock user input", "Sbloccare l'input dell'utente"), ("Adjust Window", "Adatta la finestra"), ("Original", "Originale"), - ("Shrink", "Restringi"), - ("Stretch", "Allarga"), + ("Shrink", "Scala"), + ("Stretch", "Adatta"), ("Good image quality", "Buona qualità immagine"), ("Balanced", "Bilanciato"), ("Optimize reaction time", "Ottimizza il tempo di reazione"), @@ -220,7 +220,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Discovered", "Rilevati"), ("install_daemon_tip", "Per avviarsi all'accensione, è necessario installare il servizio di sistema."), ("Remote ID", "ID remoto"), - ("Paste", "Impasto"), + ("Paste", "Incolla"), ("Paste here?", "Incolla qui?"), ("Are you sure to close the connection?", "Sei sicuro di voler chiudere la connessione?"), ("Download new version", "Scarica nuova versione"), @@ -239,8 +239,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Two-Finger Move", "Movimento con due dita"), ("Canvas Move", "Sposta tela"), ("Pinch to Zoom", "Pizzica per zoomare"), - ("Canvas Zoom", "Zoom tela"), - ("Reset canvas", "Ripristina tela"), + ("Canvas Zoom", "Zoom canvas"), + ("Reset canvas", "Ripristina canvas"), ("No permission of file transfer", "Nessun permesso di trasferimento di file"), ("Note", "Nota"), ("Connection", "Connessione"), @@ -276,7 +276,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Succeeded", "Successo"), ("Someone turns on privacy mode, exit", "Qualcuno attiva la modalità privacy, esci"), ("Unsupported", "Non supportato"), - ("Peer denied", "Pari negato"), + ("Peer denied", "Peer negato"), ("Please install plugins", "Si prega di installare i plugin"), ("Peer exit", "Uscita tra pari"), ("Failed to turn off", "Impossibile spegnere"), @@ -287,17 +287,17 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", ""), ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), - ("Connection not allowed", ""), - ("Use temporary password", ""), - ("Use permanent password", ""), - ("Use both passwords", ""), - ("Set permanent password", ""), - ("Set temporary password length", ""), - ("Enable Remote Restart", ""), - ("Allow remote restart", ""), - ("Restart Remote Device", ""), - ("Are you sure you want to restart", ""), - ("Restarting Remote Device", ""), - ("remote_restarting_tip", ""), + ("Connection not allowed", "Connessione non consentita"), + ("Use temporary password", "Usa password temporanea"), + ("Use permanent password", "Usa password permanente"), + ("Use both passwords", "Usa entrambe le password"), + ("Set permanent password", "Imposta password permanente"), + ("Set temporary password length", "Imposta lunghezza passwod temporanea"), + ("Enable Remote Restart", "Abilita riavvio da remoto"), + ("Allow remote restart", "Consenti riavvio da remoto"), + ("Restart Remote Device", "Riavvia dispositivo remoto"), + ("Are you sure you want to restart", "Sei sicuro di voler riavviare?"), + ("Restarting Remote Device", "Il dispositivo remoto si sta riavviando"), + ("remote_restarting_tip", "Riavviare il dispositivo remoto"), ].iter().cloned().collect(); } From bb99dcab6b5dd2c792ce21c1d0d7f9790d01a069 Mon Sep 17 00:00:00 2001 From: kordood Date: Tue, 16 Aug 2022 10:55:24 +0900 Subject: [PATCH 29/33] Update lang.rs to add Korean language Signed-off-by: kordood --- src/lang.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lang.rs b/src/lang.rs index 400c4dd95..22085a34d 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -13,6 +13,7 @@ mod hu; mod id; mod it; mod ja; +mod ko; mod pl; mod ptbr; mod ru; @@ -43,6 +44,7 @@ lazy_static::lazy_static! { ("vn", "Tiếng Việt"), ("pl", "Polski"), ("ja", "日本語"), + ("ko", "한국어"), ]); } @@ -90,6 +92,7 @@ pub fn translate_locale(name: String, locale: &str) -> String { "vn" => vn::T.deref(), "pl" => pl::T.deref(), "ja" => ja::T.deref(), + "ja" => ko::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { From 1f0ba830dfb6f3e5458866f1b29dd353fa89b31d Mon Sep 17 00:00:00 2001 From: kordood Date: Tue, 16 Aug 2022 14:51:10 +0900 Subject: [PATCH 30/33] Fix a typo of locale name Signed-off-by: kordood --- src/lang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang.rs b/src/lang.rs index 22085a34d..7157f9b42 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -92,7 +92,7 @@ pub fn translate_locale(name: String, locale: &str) -> String { "vn" => vn::T.deref(), "pl" => pl::T.deref(), "ja" => ja::T.deref(), - "ja" => ko::T.deref(), + "ko" => ko::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { From 49b6cf198ccff53edbf416b098a5938772b3b784 Mon Sep 17 00:00:00 2001 From: Daniel Ehrhardt Date: Fri, 19 Aug 2022 07:18:47 +0200 Subject: [PATCH 31/33] Added new Free Public Server to Readme --- README-CS.md | 3 ++- README-DE.md | 2 ++ README-ES.md | 2 ++ README-FA.md | 2 ++ README-FI.md | 2 ++ README-FR.md | 2 ++ README-HU.md | 2 ++ README-ID.md | 4 +++- README-IT.md | 4 +++- README-JP.md | 4 +++- README-KR.md | 4 +++- README-ML.md | 4 +++- README-NL.md | 4 +++- README-PL.md | 4 +++- README-PTBR.md | 2 ++ README-RU.md | 4 +++- README-VN.md | 4 +++- README-ZH.md | 2 ++ README.md | 3 ++- 19 files changed, 47 insertions(+), 11 deletions(-) diff --git a/README-CS.md b/README-CS.md index f6fa2fbf0..4f2c0e80f 100644 --- a/README-CS.md +++ b/README-CS.md @@ -29,7 +29,8 @@ Níže jsou uvedeny servery zdarma k vašemu použití (údaje se mohou v čase | --------- | ------------- | ------------------ | | Soul | AWS lightsail | 1 VCPU / 0,5GB RAM | | Singapur | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Softwarové součásti, na kterých závisí diff --git a/README-DE.md b/README-DE.md index 4e9929997..eb468d569 100644 --- a/README-DE.md +++ b/README-DE.md @@ -28,6 +28,8 @@ Hier sind die Server, die du kostenlos nutzen kannst, es kann sein das sich dies | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | | Singapore | Vultr | 1 VCPU / 1GB RAM | | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Codext | 2 VCPU / 4GB RAM | +| Germany | Hetzner | 4 VCPU / 8GB RAM | ## Abhängigkeiten diff --git a/README-ES.md b/README-ES.md index 1aab59213..7ceed149a 100644 --- a/README-ES.md +++ b/README-ES.md @@ -28,6 +28,8 @@ A continuación se muestran los servidores que está utilizando de forma gratuit | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-FA.md b/README-FA.md index 818e62fa8..5fd3c0d03 100644 --- a/README-FA.md +++ b/README-FA.md @@ -32,6 +32,8 @@ | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## وابستگی ها diff --git a/README-FI.md b/README-FI.md index 5f38d2e42..2e4c99ba6 100644 --- a/README-FI.md +++ b/README-FI.md @@ -27,6 +27,8 @@ Alla on palvelimia, joita voit käyttää ilmaiseksi, ne saattavat muuttua ajan | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Riippuvuudet diff --git a/README-FR.md b/README-FR.md index 9a303e6e6..3e33cb322 100644 --- a/README-FR.md +++ b/README-FR.md @@ -26,6 +26,8 @@ Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut ch - Séoul, AWS lightsail, 1 VCPU/0.5G RAM - Singapour, Vultr, 1 VCPU/1G RAM - Dallas, Vultr, 1 VCPU/1G RAM +- Germany, Codext, 2 VCPU / 4GB RAM +- Germany, Hetzner, 4 VCPU / 8GB RAM ## Dépendances diff --git a/README-HU.md b/README-HU.md index 7055ed446..3960d8b40 100644 --- a/README-HU.md +++ b/README-HU.md @@ -35,6 +35,8 @@ Ezalatt az üzenet alatt találhatóak azok a publikus szerverek, amelyeket ingy | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-ID.md b/README-ID.md index 363d4263b..3ea9bc454 100644 --- a/README-ID.md +++ b/README-ID.md @@ -26,7 +26,9 @@ Di bawah ini adalah server yang bisa Anda gunakan secara gratis, dapat berubah s | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-IT.md b/README-IT.md index a3f36af55..a79c28153 100644 --- a/README-IT.md +++ b/README-IT.md @@ -26,7 +26,9 @@ Qui sotto trovate i server che possono essere usati gratuitamente, la lista potr | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dipendenze diff --git a/README-JP.md b/README-JP.md index fb55d0ced..c1722a90f 100644 --- a/README-JP.md +++ b/README-JP.md @@ -31,7 +31,9 @@ RustDeskは誰からの貢献も歓迎します。 貢献するには [`CONTRIBU | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## 依存関係 diff --git a/README-KR.md b/README-KR.md index 00564e298..c7cf423da 100644 --- a/README-KR.md +++ b/README-KR.md @@ -31,7 +31,9 @@ RustDesk는 모든 기여를 환영합니다. 기여하고자 한다면 [`CONTRI | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## 의존관계 diff --git a/README-ML.md b/README-ML.md index d2931a2c7..45496b129 100644 --- a/README-ML.md +++ b/README-ML.md @@ -26,7 +26,9 @@ | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## ഡിപെൻഡൻസികൾ diff --git a/README-NL.md b/README-NL.md index 5db299e7c..8a4a119fc 100644 --- a/README-NL.md +++ b/README-NL.md @@ -26,7 +26,9 @@ Onderstaande servers zijn de servers die je gratis kunt gebruiken, ze kunnen op | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Afhankelijkheden diff --git a/README-PL.md b/README-PL.md index 119af95cf..d3b298d5a 100644 --- a/README-PL.md +++ b/README-PL.md @@ -26,7 +26,9 @@ Poniżej znajdują się serwery, z których można korzystać za darmo, może si | --------- | ------------- | ------------------ | | Seul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapur | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Zależności diff --git a/README-PTBR.md b/README-PTBR.md index 955456256..020941831 100644 --- a/README-PTBR.md +++ b/README-PTBR.md @@ -28,6 +28,8 @@ Abaixo estão os servidores que você está utilizando de graça, ele pode mudar | Seul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapura | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependências diff --git a/README-RU.md b/README-RU.md index a9d81152c..d610f2dc5 100644 --- a/README-RU.md +++ b/README-RU.md @@ -32,7 +32,9 @@ RustDesk приветствует вклад каждого. Смотрите [` | --------- | ------------- | ------------------ | | Сеул | AWS lightsail | 1 VCPU / 0.5GB RAM | | Сингапур | Vultr | 1 VCPU / 1GB RAM | -| Даллас | Vultr | 1 VCPU / 1GB RAM | | +| Даллас | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Зависимости diff --git a/README-VN.md b/README-VN.md index b39005a31..641b80ebd 100644 --- a/README-VN.md +++ b/README-VN.md @@ -35,7 +35,9 @@ Dưới đây là những máy chủ mà bạn có thể sử dụng mà không | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-ZH.md b/README-ZH.md index 0c3e7d5c1..e17254670 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -27,6 +27,8 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https: - 首尔, AWS lightsail, 1 VCPU/0.5G RAM - 新加坡, Vultr, 1 VCPU/1G RAM - 达拉斯, Vultr, 1 VCPU/1G RAM +- Germany, Codext, 2 VCPU / 4GB RAM +- Germany, Hetzner, 4 VCPU / 8GB RAM ## 依赖 diff --git a/README.md b/README.md index 346600f61..79a4b18d3 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ Below are the servers you are using for free, it may change along the time. If y | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies From 0649a49d1746bb288d0ae009f95e753582b1c3d3 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 31 Jul 2022 19:06:49 +0800 Subject: [PATCH 32/33] fix 10054: change direct to relay when RST Signed-off-by: 21pages --- Cargo.lock | 22 ++++++++++++ Cargo.toml | 1 + libs/hbb_common/src/config.rs | 1 + src/client.rs | 68 ++++++++++++++++++++++++++--------- src/port_forward.rs | 50 ++++++++++++++++++++++++-- src/ui/remote.rs | 31 +++++++++++++++- 6 files changed, 152 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6ed80add..89d31556b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1470,6 +1470,27 @@ dependencies = [ "synstructure", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "error-code" version = "2.3.1" @@ -4168,6 +4189,7 @@ dependencies = [ "default-net", "dispatch", "enigo", + "errno", "evdev", "flexi_logger", "flutter_rust_bridge", diff --git a/Cargo.toml b/Cargo.toml index f48a47d9b..aaa01e3ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ num_cpus = "1.13" bytes = { version = "1.2", features = ["serde"] } default-net = "0.11.0" wol-rs = "0.9.1" +errno = "0.2.8" [target.'cfg(not(target_os = "linux"))'.dependencies] reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features=false } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 26871a958..d7cdb82ce 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -21,6 +21,7 @@ use std::{ pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; pub const CONNECT_TIMEOUT: u64 = 18_000; +pub const READ_TIMEOUT: u64 = 30_000; pub const REG_INTERVAL: i64 = 12_000; pub const COMPRESS_LEVEL: i32 = 3; const SERIAL: i32 = 3; diff --git a/src/client.rs b/src/client.rs index 6a5db19e2..a73d4b60e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -24,7 +24,10 @@ use hbb_common::{ allow_err, anyhow::{anyhow, Context}, bail, - config::{Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, RELAY_PORT, RENDEZVOUS_TIMEOUT}, + config::{ + Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT, + RENDEZVOUS_TIMEOUT, + }, log, message_proto::{option_message::BoolOption, *}, protobuf::Message as _, @@ -116,8 +119,9 @@ impl Client { key: &str, token: &str, conn_type: ConnType, + interface: impl Interface, ) -> ResultType<(Stream, bool)> { - match Self::_start(peer, key, token, conn_type).await { + match Self::_start(peer, key, token, conn_type, interface).await { Err(err) => { let err_str = err.to_string(); if err_str.starts_with("Failed") { @@ -135,6 +139,7 @@ impl Client { key: &str, token: &str, conn_type: ConnType, + interface: impl Interface, ) -> ResultType<(Stream, bool)> { // to-do: remember the port for each peer, so that we can retry easier let any_addr = Config::get_any_listen_addr(); @@ -181,7 +186,11 @@ impl Client { log::info!("#{} punch attempt with {}, id: {}", i, my_addr, peer); let mut msg_out = RendezvousMessage::new(); use hbb_common::protobuf::Enum; - let nat_type = NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT); + let nat_type = if interface.is_force_relay() { + NatType::SYMMETRIC + } else { + NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT) + }; msg_out.set_punch_hole_request(PunchHoleRequest { id: peer.to_owned(), token: token.to_owned(), @@ -233,7 +242,15 @@ impl Client { let mut conn = Self::create_relay(peer, rr.uuid, rr.relay_server, key, conn_type) .await?; - Self::secure_connection(peer, signed_id_pk, key, &mut conn).await?; + Self::secure_connection( + peer, + signed_id_pk, + key, + &mut conn, + false, + interface, + ) + .await?; return Ok((conn, false)); } _ => { @@ -274,6 +291,7 @@ impl Client { key, token, conn_type, + interface, ) .await } @@ -292,6 +310,7 @@ impl Client { key: &str, token: &str, conn_type: ConnType, + interface: impl Interface, ) -> ResultType<(Stream, bool)> { let direct_failures = PeerConfig::load(peer_id).direct_failures; let mut connect_timeout = 0; @@ -329,8 +348,8 @@ impl Client { let start = std::time::Instant::now(); // NOTICE: Socks5 is be used event in intranet. Which may be not a good way. let mut conn = socket_client::connect_tcp(peer, local_addr, connect_timeout).await; - let direct = !conn.is_err(); - if conn.is_err() { + let mut direct = !conn.is_err(); + if interface.is_force_relay() || conn.is_err() { if !relay_server.is_empty() { conn = Self::request_relay( peer_id, @@ -348,6 +367,7 @@ impl Client { conn.err().unwrap() ); } + direct = false; } else { bail!("Failed to make direct connection to remote desktop"); } @@ -360,7 +380,7 @@ impl Client { } let mut conn = conn?; log::info!("{:?} used to establish connection", start.elapsed()); - Self::secure_connection(peer_id, signed_id_pk, key, &mut conn).await?; + Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface).await?; Ok((conn, direct)) } @@ -369,6 +389,8 @@ impl Client { signed_id_pk: Vec, key: &str, conn: &mut Stream, + direct: bool, + mut interface: impl Interface, ) -> ResultType<()> { let rs_pk = get_rs_pk(if key.is_empty() { hbb_common::config::RS_PUB_KEY @@ -394,9 +416,15 @@ impl Client { return Ok(()); } }; - match timeout(CONNECT_TIMEOUT, conn.next()).await? { + match timeout(READ_TIMEOUT, conn.next()).await? { Some(res) => { - let bytes = res?; + let bytes = match res { + Ok(bytes) => bytes, + Err(err) => { + interface.set_force_relay(direct, false); + bail!("{}", err); + } + }; if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { if let Some(message::Union::SignedId(si)) = msg_in.union { if let Ok((id, their_pk_b)) = decode_id_pk(&si.id, &sign_pk) { @@ -786,6 +814,7 @@ pub struct LoginConfigHandler { session_id: u64, pub supported_encoding: Option<(bool, bool)>, pub restarting_remote_device: bool, + pub force_relay: bool, } impl Deref for LoginConfigHandler { @@ -812,6 +841,7 @@ impl LoginConfigHandler { self.session_id = rand::random(); self.supported_encoding = None; self.restarting_remote_device = false; + self.force_relay = false; } pub fn should_auto_login(&self) -> String { @@ -1418,6 +1448,8 @@ pub trait Interface: Send + Clone + 'static + Sized { fn msgbox(&self, msgtype: &str, title: &str, text: &str); fn handle_login_error(&mut self, err: &str) -> bool; fn handle_peer_info(&mut self, pi: PeerInfo); + fn set_force_relay(&mut self, direct: bool, received: bool); + fn is_force_relay(&self) -> bool; async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream); async fn handle_login_from_ui(&mut self, password: String, remember: bool, peer: &mut Stream); async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream); @@ -1579,14 +1611,16 @@ lazy_static::lazy_static! { pub fn check_if_retry(msgtype: &str, title: &str, text: &str) -> bool { msgtype == "error" && title == "Connection Error" - && !text.to_lowercase().contains("offline") - && !text.to_lowercase().contains("exist") - && !text.to_lowercase().contains("handshake") - && !text.to_lowercase().contains("failed") - && !text.to_lowercase().contains("resolve") - && !text.to_lowercase().contains("mismatch") - && !text.to_lowercase().contains("manually") - && !text.to_lowercase().contains("not allowed") + && (text.contains("10054") + || text.contains("104") + || (!text.to_lowercase().contains("offline") + && !text.to_lowercase().contains("exist") + && !text.to_lowercase().contains("handshake") + && !text.to_lowercase().contains("failed") + && !text.to_lowercase().contains("resolve") + && !text.to_lowercase().contains("mismatch") + && !text.to_lowercase().contains("manually") + && !text.to_lowercase().contains("not allowed"))) } #[inline] diff --git a/src/port_forward.rs b/src/port_forward.rs index a17ee8259..9a697da42 100644 --- a/src/port_forward.rs +++ b/src/port_forward.rs @@ -1,7 +1,7 @@ use crate::client::*; use hbb_common::{ allow_err, bail, - config::CONNECT_TIMEOUT, + config::READ_TIMEOUT, futures::{SinkExt, StreamExt}, log, message_proto::*, @@ -105,22 +105,61 @@ async fn connect_and_login( key: &str, token: &str, is_rdp: bool, +) -> ResultType> { + let mut res = connect_and_login_2( + id, + password, + ui_receiver, + interface.clone(), + forward, + key, + token, + is_rdp, + ) + .await; + if res.is_err() && interface.is_force_relay() { + res = connect_and_login_2( + id, + password, + ui_receiver, + interface, + forward, + key, + token, + is_rdp, + ) + .await; + } + res +} + +async fn connect_and_login_2( + id: &str, + password: &str, + ui_receiver: &mut mpsc::UnboundedReceiver, + interface: impl Interface, + forward: &mut Framed, + key: &str, + token: &str, + is_rdp: bool, ) -> ResultType> { let conn_type = if is_rdp { ConnType::RDP } else { ConnType::PORT_FORWARD }; - let (mut stream, _) = Client::start(id, key, token, conn_type).await?; + let (mut stream, direct) = Client::start(id, key, token, conn_type, interface.clone()).await?; let mut interface = interface; let mut buffer = Vec::new(); + let mut received = false; loop { tokio::select! { - res = timeout(CONNECT_TIMEOUT, stream.next()) => match res { + res = timeout(READ_TIMEOUT, stream.next()) => match res { Err(_) => { bail!("Timeout"); } Ok(Some(Ok(bytes))) => { + received = true; let msg_in = Message::parse_from_bytes(&bytes)?; match msg_in.union { Some(message::Union::Hash(hash)) => { @@ -143,6 +182,11 @@ async fn connect_and_login( _ => {} } } + Ok(Some(Err(err))) => { + log::error!("Connection closed: {}", err); + interface.set_force_relay(direct, received); + bail!("Connection closed: {}", err); + } _ => { bail!("Reset by the peer"); } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 1a446317d..c9dd45888 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -53,6 +53,7 @@ use crate::{ client::*, common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}, }; +use errno; type Video = AssetPtr; @@ -1456,12 +1457,21 @@ impl Remote { async fn io_loop(&mut self, key: &str, token: &str) { let stop_clipboard = self.start_clipboard(); let mut last_recv_time = Instant::now(); + let mut received = false; let conn_type = if self.handler.is_file_transfer() { ConnType::FILE_TRANSFER } else { ConnType::default() }; - match Client::start(&self.handler.id, key, token, conn_type).await { + match Client::start( + &self.handler.id, + key, + token, + conn_type, + self.handler.clone(), + ) + .await + { Ok((mut peer, direct)) => { SERVER_KEYBOARD_ENABLED.store(true, Ordering::SeqCst); SERVER_CLIPBOARD_ENABLED.store(true, Ordering::SeqCst); @@ -1484,11 +1494,13 @@ impl Remote { match res { Err(err) => { log::error!("Connection closed: {}", err); + self.handler.set_force_relay(direct, received); self.handler.msgbox("error", "Connection Error", &err.to_string()); break; } Ok(ref bytes) => { last_recv_time = Instant::now(); + received = true; self.data_count.fetch_add(bytes.len(), Ordering::Relaxed); if !self.handle_msg_from_peer(bytes, &mut peer).await { break @@ -2695,6 +2707,23 @@ impl Interface for Handler { handle_test_delay(t, peer).await; } } + + fn set_force_relay(&mut self, direct: bool, received: bool) { + let mut lc = self.lc.write().unwrap(); + lc.force_relay = false; + if direct && !received { + let errno = errno::errno().0; + log::info!("errno is {}", errno); + // TODO + if cfg!(windows) && errno == 10054 || !cfg!(windows) && errno == 104 { + lc.force_relay = true; + } + } + } + + fn is_force_relay(&self) -> bool { + self.lc.read().unwrap().force_relay + } } impl Handler { From a7c87a5f573def7620507f94b375996b9ff6f14c Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 24 Aug 2022 16:23:36 +0800 Subject: [PATCH 33/33] option to enable force-always-relay Signed-off-by: 21pages --- src/client.rs | 2 +- src/ui/ab.tis | 3 +-- src/ui/remote.rs | 27 ++++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/client.rs b/src/client.rs index a73d4b60e..9f5338a6c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -841,7 +841,7 @@ impl LoginConfigHandler { self.session_id = rand::random(); self.supported_encoding = None; self.restarting_remote_device = false; - self.force_relay = false; + self.force_relay = !self.get_option("force-always-relay").is_empty(); } pub fn should_auto_login(&self) -> String { diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 28fa62352..658783623 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -316,7 +316,7 @@ class SessionList: Reactor.Component {
  • {translate('Connect')}
  • {translate('Transfer File')}
  • {translate('TCP Tunneling')}
  • - {false && !handler.using_public_server() &&
  • {svg_checkmark}{translate('Always connect via relay')}
  • } +
  • {svg_checkmark}{translate('Always connect via relay')}
  • RDP
  • {translate('WOL')}
  • @@ -396,7 +396,6 @@ class SessionList: Reactor.Component { if (el) { var force = handler.get_peer_option(id, "force-always-relay"); el.attributes.toggleClass("selected", force == "Y"); - el.attributes.toggleClass("line-through", force != "Y"); } var conn = this.$(menu #connect); if (conn) { diff --git a/src/ui/remote.rs b/src/ui/remote.rs index c9dd45888..25aacd26d 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -2085,18 +2085,18 @@ impl Remote { 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); - } + .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 { @@ -2714,9 +2714,10 @@ impl Interface for Handler { if direct && !received { let errno = errno::errno().0; log::info!("errno is {}", errno); - // TODO + // TODO: check mac and ios if cfg!(windows) && errno == 10054 || !cfg!(windows) && errno == 104 { lc.force_relay = true; + lc.set_option("force-always-relay".to_owned(), "Y".to_owned()); } } }