Merge branch 'rustdesk:master' into master

This commit is contained in:
Asura 2022-07-04 17:15:43 +08:00 committed by GitHub
commit 082f851d4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 239 additions and 86 deletions

View File

@ -43,7 +43,7 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode|navigation"
android:exported="true" android:exported="true"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:launchMode="singleTop" android:launchMode="singleTop"

View File

@ -310,19 +310,19 @@ class ImageModel with ChangeNotifier {
} }
double get maxScale { double get maxScale {
if (_image == null) return 1.0; if (_image == null) return 1.5;
final size = MediaQueryData.fromWindow(ui.window).size; final size = MediaQueryData.fromWindow(ui.window).size;
final xscale = size.width / _image!.width; final xscale = size.width / _image!.width;
final yscale = size.height / _image!.height; final yscale = size.height / _image!.height;
return max(1.0, max(xscale, yscale)); return max(1.5, max(xscale, yscale));
} }
double get minScale { double get minScale {
if (_image == null) return 1.0; if (_image == null) return 1.5;
final size = MediaQueryData.fromWindow(ui.window).size; final size = MediaQueryData.fromWindow(ui.window).size;
final xscale = size.width / _image!.width; final xscale = size.width / _image!.width;
final yscale = size.height / _image!.height; final yscale = size.height / _image!.height;
return min(xscale, yscale); return min(xscale, yscale) / 1.5;
} }
} }
@ -724,13 +724,17 @@ class FFI {
static void inputKey(String name, {bool? down, bool? press}) { static void inputKey(String name, {bool? down, bool? press}) {
if (!ffiModel.keyboard()) return; if (!ffiModel.keyboard()) return;
setByName( final Map<String, String> out = Map();
'input_key', out['name'] = name;
json.encode(modify({ // default: down = false
'name': name, if (down == true) {
'down': (down ?? false).toString(), out['down'] = "true";
'press': (press ?? true).toString() }
}))); // default: press = true
if (press != false) {
out['press'] = "true";
}
setByName('input_key', json.encode(modify(out)));
} }
static void moveMouse(double x, double y) { static void moveMouse(double x, double y) {

View File

@ -343,9 +343,14 @@ class _RemotePageState extends State<RemotePage> {
onKey: (data, e) { onKey: (data, e) {
final key = e.logicalKey; final key = e.logicalKey;
if (e is RawKeyDownEvent) { if (e is RawKeyDownEvent) {
if (e.repeat) { if (e.repeat &&
!e.isAltPressed &&
!e.isControlPressed &&
!e.isShiftPressed &&
!e.isMetaPressed) {
sendRawKey(e, press: true); sendRawKey(e, press: true);
} else { } else {
sendRawKey(e, down: true);
if (e.isAltPressed && !FFI.alt) { if (e.isAltPressed && !FFI.alt) {
FFI.alt = true; FFI.alt = true;
} else if (e.isControlPressed && !FFI.ctrl) { } else if (e.isControlPressed && !FFI.ctrl) {
@ -355,7 +360,6 @@ class _RemotePageState extends State<RemotePage> {
} else if (e.isMetaPressed && !FFI.command) { } else if (e.isMetaPressed && !FFI.command) {
FFI.command = true; FFI.command = true;
} }
sendRawKey(e, down: true);
} }
} }
// [!_showEdit] workaround for soft-keyboard's control_key like Backspace / Enter // [!_showEdit] workaround for soft-keyboard's control_key like Backspace / Enter
@ -481,6 +485,7 @@ class _RemotePageState extends State<RemotePage> {
/// DoubleFiner -> right click /// DoubleFiner -> right click
/// HoldDrag -> left drag /// HoldDrag -> left drag
Offset _cacheLongPressPosition = Offset(0, 0);
Widget getBodyForMobileWithGesture() { Widget getBodyForMobileWithGesture() {
final touchMode = FFI.ffiModel.touchMode; final touchMode = FFI.ffiModel.touchMode;
return getMixinGestureDetector( return getMixinGestureDetector(
@ -504,10 +509,14 @@ class _RemotePageState extends State<RemotePage> {
}, },
onLongPressDown: (d) { onLongPressDown: (d) {
if (touchMode) { if (touchMode) {
FFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy); _cacheLongPressPosition = d.localPosition;
} }
}, },
onLongPress: () { onLongPress: () {
if (touchMode) {
FFI.cursorModel
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
}
FFI.tap(MouseButtons.right); FFI.tap(MouseButtons.right);
}, },
onDoubleFinerTap: (d) { onDoubleFinerTap: (d) {
@ -534,6 +543,15 @@ class _RemotePageState extends State<RemotePage> {
if (touchMode) { if (touchMode) {
FFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy); FFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
FFI.sendMouse('down', MouseButtons.left); FFI.sendMouse('down', MouseButtons.left);
} else {
final cursorX = FFI.cursorModel.x;
final cursorY = FFI.cursorModel.y;
final visible =
FFI.cursorModel.getVisibleRect().inflate(1); // extend edges
final size = MediaQueryData.fromWindow(ui.window).size;
if (!visible.contains(Offset(cursorX, cursorY))) {
FFI.cursorModel.move(size.width / 2, size.height / 2);
}
} }
}, },
onOneFingerPanUpdate: (d) { onOneFingerPanUpdate: (d) {

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
enum CustomTouchGestureState { enum GestureState {
none, none,
oneFingerPan, oneFingerPan,
twoFingerScale, twoFingerScale,
@ -35,64 +35,41 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
GestureDragUpdateCallback? onThreeFingerVerticalDragUpdate; GestureDragUpdateCallback? onThreeFingerVerticalDragUpdate;
GestureDragEndCallback? onThreeFingerVerticalDragEnd; GestureDragEndCallback? onThreeFingerVerticalDragEnd;
var _currentState = CustomTouchGestureState.none; var _currentState = GestureState.none;
Timer? _startEventDebounceTimer; Timer? _debounceTimer;
void _init() { void _init() {
debugPrint("CustomTouchGestureRecognizer init"); debugPrint("CustomTouchGestureRecognizer init");
onStart = (d) { // onStart = (d) {};
_startEventDebounceTimer?.cancel(); onUpdate = (d) {
if (d.pointerCount == 1) { _debounceTimer?.cancel();
_currentState = CustomTouchGestureState.oneFingerPan; if (d.pointerCount == 1 && _currentState != GestureState.oneFingerPan) {
if (onOneFingerPanStart != null) { onOneFingerStartDebounce(d);
onOneFingerPanStart!(DragStartDetails( } else if (d.pointerCount == 2 &&
localPosition: d.localFocalPoint, globalPosition: d.focalPoint)); _currentState != GestureState.twoFingerScale) {
} onTwoFingerStartDebounce(d);
debugPrint("start oneFingerPan"); } else if (d.pointerCount == 3 &&
} else if (d.pointerCount == 2) { _currentState != GestureState.threeFingerVerticalDrag) {
if (_currentState == CustomTouchGestureState.threeFingerVerticalDrag) { _currentState = GestureState.threeFingerVerticalDrag;
// 3 -> 2 debounce
_startEventDebounceTimer = Timer(Duration(milliseconds: 200), () {
_currentState = CustomTouchGestureState.twoFingerScale;
if (onTwoFingerScaleStart != null) {
onTwoFingerScaleStart!(ScaleStartDetails(
localFocalPoint: d.localFocalPoint,
focalPoint: d.focalPoint));
}
debugPrint("debounce start twoFingerScale success");
});
}
_currentState = CustomTouchGestureState.twoFingerScale;
// startWatchTimer();
if (onTwoFingerScaleStart != null) {
onTwoFingerScaleStart!(ScaleStartDetails(
localFocalPoint: d.localFocalPoint, focalPoint: d.focalPoint));
}
debugPrint("start twoFingerScale");
} else if (d.pointerCount == 3) {
_currentState = CustomTouchGestureState.threeFingerVerticalDrag;
if (onThreeFingerVerticalDragStart != null) { if (onThreeFingerVerticalDragStart != null) {
onThreeFingerVerticalDragStart!( onThreeFingerVerticalDragStart!(
DragStartDetails(globalPosition: d.localFocalPoint)); DragStartDetails(globalPosition: d.localFocalPoint));
} }
debugPrint("start threeFingerScale"); debugPrint("start threeFingerScale");
// _reset();
} }
}; if (_currentState != GestureState.none) {
onUpdate = (d) {
if (_currentState != CustomTouchGestureState.none) {
switch (_currentState) { switch (_currentState) {
case CustomTouchGestureState.oneFingerPan: case GestureState.oneFingerPan:
if (onOneFingerPanUpdate != null) { if (onOneFingerPanUpdate != null) {
onOneFingerPanUpdate!(_getDragUpdateDetails(d)); onOneFingerPanUpdate!(_getDragUpdateDetails(d));
} }
break; break;
case CustomTouchGestureState.twoFingerScale: case GestureState.twoFingerScale:
if (onTwoFingerScaleUpdate != null) { if (onTwoFingerScaleUpdate != null) {
onTwoFingerScaleUpdate!(d); onTwoFingerScaleUpdate!(d);
} }
break; break;
case CustomTouchGestureState.threeFingerVerticalDrag: case GestureState.threeFingerVerticalDrag:
if (onThreeFingerVerticalDragUpdate != null) { if (onThreeFingerVerticalDragUpdate != null) {
onThreeFingerVerticalDragUpdate!(_getDragUpdateDetails(d)); onThreeFingerVerticalDragUpdate!(_getDragUpdateDetails(d));
} }
@ -105,21 +82,22 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
}; };
onEnd = (d) { onEnd = (d) {
debugPrint("ScaleGestureRecognizer onEnd"); debugPrint("ScaleGestureRecognizer onEnd");
_debounceTimer?.cancel();
// end // end
switch (_currentState) { switch (_currentState) {
case CustomTouchGestureState.oneFingerPan: case GestureState.oneFingerPan:
debugPrint("TwoFingerState.pan onEnd"); debugPrint("TwoFingerState.pan onEnd");
if (onOneFingerPanEnd != null) { if (onOneFingerPanEnd != null) {
onOneFingerPanEnd!(_getDragEndDetails(d)); onOneFingerPanEnd!(_getDragEndDetails(d));
} }
break; break;
case CustomTouchGestureState.twoFingerScale: case GestureState.twoFingerScale:
debugPrint("TwoFingerState.scale onEnd"); debugPrint("TwoFingerState.scale onEnd");
if (onTwoFingerScaleEnd != null) { if (onTwoFingerScaleEnd != null) {
onTwoFingerScaleEnd!(d); onTwoFingerScaleEnd!(d);
} }
break; break;
case CustomTouchGestureState.threeFingerVerticalDrag: case GestureState.threeFingerVerticalDrag:
debugPrint("ThreeFingerState.vertical onEnd"); debugPrint("ThreeFingerState.vertical onEnd");
if (onThreeFingerVerticalDragEnd != null) { if (onThreeFingerVerticalDragEnd != null) {
onThreeFingerVerticalDragEnd!(_getDragEndDetails(d)); onThreeFingerVerticalDragEnd!(_getDragEndDetails(d));
@ -128,10 +106,50 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
default: default:
break; break;
} }
_currentState = CustomTouchGestureState.none; _debounceTimer = Timer(Duration(milliseconds: 200), () {
_currentState = GestureState.none;
});
}; };
} }
void onOneFingerStartDebounce(ScaleUpdateDetails d) {
final start = (ScaleUpdateDetails d) {
_currentState = GestureState.oneFingerPan;
if (onOneFingerPanStart != null) {
onOneFingerPanStart!(DragStartDetails(
localPosition: d.localFocalPoint, globalPosition: d.focalPoint));
}
};
if (_currentState != GestureState.none) {
_debounceTimer = Timer(Duration(milliseconds: 200), () {
start(d);
debugPrint("debounce start oneFingerPan");
});
} else {
start(d);
debugPrint("start oneFingerPan");
}
}
void onTwoFingerStartDebounce(ScaleUpdateDetails d) {
final start = (ScaleUpdateDetails d) {
_currentState = GestureState.twoFingerScale;
if (onTwoFingerScaleStart != null) {
onTwoFingerScaleStart!(ScaleStartDetails(
localFocalPoint: d.localFocalPoint, focalPoint: d.focalPoint));
}
};
if (_currentState == GestureState.threeFingerVerticalDrag) {
_debounceTimer = Timer(Duration(milliseconds: 200), () {
start(d);
debugPrint("debounce start twoFingerScale");
});
} else {
start(d);
debugPrint("start twoFingerScale");
}
}
DragUpdateDetails _getDragUpdateDetails(ScaleUpdateDetails d) => DragUpdateDetails _getDragUpdateDetails(ScaleUpdateDetails d) =>
DragUpdateDetails( DragUpdateDetails(
globalPosition: d.focalPoint, globalPosition: d.focalPoint,

View File

@ -47,7 +47,7 @@ case "$1" in
;; ;;
2) 2)
# for upgrade # for upgrade
service rustdesk stop || true systemctl stop rustdesk || true
;; ;;
esac esac
@ -61,10 +61,26 @@ systemctl start rustdesk
update-desktop-database update-desktop-database
%preun %preun
case "$1" in
0)
# for uninstall
systemctl stop rustdesk || true systemctl stop rustdesk || true
systemctl disable rustdesk || true systemctl disable rustdesk || true
rm /etc/systemd/system/rustdesk.service || true rm /etc/systemd/system/rustdesk.service || true
;;
1)
# for upgrade
;;
esac
%postun %postun
case "$1" in
0)
# for uninstall
rm /usr/share/applications/rustdesk.desktop || true rm /usr/share/applications/rustdesk.desktop || true
update-desktop-database update-desktop-database
;;
1)
# for upgrade
;;
esac

View File

@ -48,7 +48,7 @@ case "$1" in
;; ;;
2) 2)
# for upgrade # for upgrade
service rustdesk stop || true systemctl stop rustdesk || true
;; ;;
esac esac
@ -62,10 +62,26 @@ systemctl start rustdesk
update-desktop-database update-desktop-database
%preun %preun
case "$1" in
0)
# for uninstall
systemctl stop rustdesk || true systemctl stop rustdesk || true
systemctl disable rustdesk || true systemctl disable rustdesk || true
rm /etc/systemd/system/rustdesk.service || true rm /etc/systemd/system/rustdesk.service || true
;;
1)
# for upgrade
;;
esac
%postun %postun
case "$1" in
0)
# for uninstall
rm /usr/share/applications/rustdesk.desktop || true rm /usr/share/applications/rustdesk.desktop || true
update-desktop-database update-desktop-database
;;
1)
# for upgrade
;;
esac

View File

@ -1,21 +1,43 @@
use serde_json::{json, value::Value};
use std::ops::Deref; use std::ops::Deref;
mod cn; mod cn;
mod cs; mod cs;
mod da; mod da;
mod sk;
mod de; mod de;
mod en; mod en;
mod es;
mod eo; mod eo;
mod es;
mod fr; mod fr;
mod id; mod id;
mod it; mod it;
mod ptbr; mod ptbr;
mod ru; mod ru;
mod sk;
mod tr; mod tr;
mod tw; mod tw;
lazy_static::lazy_static! {
pub static ref LANGS: Value =
json!(vec![
("en", "English"),
("it", "Italiano"),
("fr", "Français"),
("de", "Deutsch"),
("cn", "简体中文"),
("tw", "繁體中文"),
("pt", "Português"),
("es", "Español"),
("ru", "Русский"),
("sk", "Slovenčina"),
("id", "Indonesia"),
("cs", "Čeština"),
("da", "Dansk"),
("eo", "Esperanto"),
("tr", "Türkçe"),
]);
}
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn translate(name: String) -> String { pub fn translate(name: String) -> String {
let locale = sys_locale::get_locale().unwrap_or_default().to_lowercase(); let locale = sys_locale::get_locale().unwrap_or_default().to_lowercase();

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "退出"), ("Turned off", "退出"),
("In privacy mode", "进入隐私模式"), ("In privacy mode", "进入隐私模式"),
("Out privacy mode", "退出隐私模式"), ("Out privacy mode", "退出隐私模式"),
("Language", "语言"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Vypnutý"), ("Turned off", "Vypnutý"),
("In privacy mode", "v režimu soukromí"), ("In privacy mode", "v režimu soukromí"),
("Out privacy mode", "mimo režim soukromí"), ("Out privacy mode", "mimo režim soukromí"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Slukket"), ("Turned off", "Slukket"),
("In privacy mode", "I databeskyttelsestilstand"), ("In privacy mode", "I databeskyttelsestilstand"),
("Out privacy mode", "Databeskyttelsestilstand fra"), ("Out privacy mode", "Databeskyttelsestilstand fra"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Ausgeschaltet"), ("Turned off", "Ausgeschaltet"),
("In privacy mode", "im Datenschutzmodus"), ("In privacy mode", "im Datenschutzmodus"),
("Out privacy mode", "Datenschutzmodus aus"), ("Out privacy mode", "Datenschutzmodus aus"),
("Language", "Sprache"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", ""), ("Turned off", ""),
("In privacy mode", ""), ("In privacy mode", ""),
("Out privacy mode", ""), ("Out privacy mode", ""),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Apagado"), ("Turned off", "Apagado"),
("In privacy mode", "En modo de privacidad"), ("In privacy mode", "En modo de privacidad"),
("Out privacy mode", "Fuera del modo de privacidad"), ("Out privacy mode", "Fuera del modo de privacidad"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Éteindre"), ("Turned off", "Éteindre"),
("In privacy mode", "en mode privé"), ("In privacy mode", "en mode privé"),
("Out privacy mode", "hors mode de confidentialité"), ("Out privacy mode", "hors mode de confidentialité"),
("Language", "Langue"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -158,7 +158,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Allow using clipboard", "Izinkan menggunakan papan klip"), ("Allow using clipboard", "Izinkan menggunakan papan klip"),
("Allow hearing sound", "Izinkan mendengarkan suara"), ("Allow hearing sound", "Izinkan mendengarkan suara"),
("Allow file copy and paste", "Izinkan penyalinan dan tempel file"), ("Allow file copy and paste", "Izinkan penyalinan dan tempel file"),
("File transfer", "Transfer file"),
("Connected", "Terkoneksi"), ("Connected", "Terkoneksi"),
("Direct and encrypted connection", "Koneksi langsung dan terenkripsi"), ("Direct and encrypted connection", "Koneksi langsung dan terenkripsi"),
("Relayed and encrypted connection", "Koneksi relai dan terenkripsi"), ("Relayed and encrypted connection", "Koneksi relai dan terenkripsi"),
@ -280,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Matikan"), ("Turned off", "Matikan"),
("In privacy mode", "Dalam mode privasi"), ("In privacy mode", "Dalam mode privasi"),
("Out privacy mode", "Keluar dari mode privasi"), ("Out privacy mode", "Keluar dari mode privasi"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Spegni"), ("Turned off", "Spegni"),
("In privacy mode", "In modalità privacy"), ("In privacy mode", "In modalità privacy"),
("Out privacy mode", "Fuori modalità privacy"), ("Out privacy mode", "Fuori modalità privacy"),
("Language", "Linguaggio"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Desligado"), ("Turned off", "Desligado"),
("In privacy mode", "No modo de privacidade"), ("In privacy mode", "No modo de privacidade"),
("Out privacy mode", "Fora do modo de privacidade"), ("Out privacy mode", "Fora do modo de privacidade"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -263,9 +263,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("android_version_audio_tip", "Текущая версия Android не поддерживает захват звука, обновите ее до Android 10 или выше."), ("android_version_audio_tip", "Текущая версия Android не поддерживает захват звука, обновите ее до Android 10 или выше."),
("android_start_service_tip", "Нажмите [Запуск промежуточного сервера] или ОТКРЫТЬ разрешение [Захват экрана], чтобы запустить службу демонстрации экрана."), ("android_start_service_tip", "Нажмите [Запуск промежуточного сервера] или ОТКРЫТЬ разрешение [Захват экрана], чтобы запустить службу демонстрации экрана."),
("Account", "Аккаунт"), ("Account", "Аккаунт"),
("Quit", "Выйти"),
("Overwrite", "Перезаписать"), ("Overwrite", "Перезаписать"),
("This file exists, skip or overwrite this file?", "Этот файл существует, пропустить или перезаписать этот файл?"), ("This file exists, skip or overwrite this file?", "Этот файл существует, пропустить или перезаписать этот файл?"),
("Quit", "Выйти"),
("doc_mac_permission", "https://rustdesk.com/docs/ru/manual/mac/#включение-разрешений"), ("doc_mac_permission", "https://rustdesk.com/docs/ru/manual/mac/#включение-разрешений"),
("Help", "Помощь"), ("Help", "Помощь"),
("Failed", "Неуспешный"), ("Failed", "Неуспешный"),
@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Выключен"), ("Turned off", "Выключен"),
("In privacy mode", "В режиме конфиденциальности"), ("In privacy mode", "В режиме конфиденциальности"),
("Out privacy mode", "Выход из режима конфиденциальности"), ("Out privacy mode", "Выход из режима конфиденциальности"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Vypnutý"), ("Turned off", "Vypnutý"),
("In privacy mode", "V režime súkromia"), ("In privacy mode", "V režime súkromia"),
("Out privacy mode", "Mimo režimu súkromia"), ("Out privacy mode", "Mimo režimu súkromia"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -264,7 +264,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("android_start_service_tip", ""), ("android_start_service_tip", ""),
("Account", ""), ("Account", ""),
("Overwrite", ""), ("Overwrite", ""),
("This file exists, skip or overwrite this file?", "") ("This file exists, skip or overwrite this file?", ""),
("Quit", ""), ("Quit", ""),
("doc_mac_permission", ""), ("doc_mac_permission", ""),
("Help", ""), ("Help", ""),
@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", ""), ("Turned off", ""),
("In privacy mode", ""), ("In privacy mode", ""),
("Out privacy mode", ""), ("Out privacy mode", ""),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -279,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "Kapalı"), ("Turned off", "Kapalı"),
("In privacy mode", "Gizlilik modunda"), ("In privacy mode", "Gizlilik modunda"),
("Out privacy mode", "Gizlilik modu dışında"), ("Out privacy mode", "Gizlilik modu dışında"),
("Language", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -262,13 +262,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("android_stop_service_tip", "關閉服務將自動關閉所有已建立的連接。"), ("android_stop_service_tip", "關閉服務將自動關閉所有已建立的連接。"),
("android_version_audio_tip", "目前的 Android 版本不支持音訊錄製,請升級至 Android 10 或以上版本。"), ("android_version_audio_tip", "目前的 Android 版本不支持音訊錄製,請升級至 Android 10 或以上版本。"),
("android_start_service_tip", "點擊 「啟動服務」 或啟用 「畫面錄製」 權限以開啟手機畫面共享服務。"), ("android_start_service_tip", "點擊 「啟動服務」 或啟用 「畫面錄製」 權限以開啟手機畫面共享服務。"),
("Account", "帳號"), ("Account", "帳戶"),
("Quit", "退出"),
("Overwrite", "覆寫"), ("Overwrite", "覆寫"),
("This file exists, skip or overwrite this file?", "此檔案/資料夾已存在,要跳過或是覆寫此檔案嗎?"), ("This file exists, skip or overwrite this file?", "此檔案/資料夾已存在,要跳過或是覆寫此檔案嗎?"),
("Quit", "退出"),
("doc_mac_permission", "https://rustdesk.com/docs/zh-tw/manual/mac/#啟用權限"), ("doc_mac_permission", "https://rustdesk.com/docs/zh-tw/manual/mac/#啟用權限"),
("Help", "幫助"), ("Help", "幫助"),
("Account", "帳戶"),
("Failed", "失敗"), ("Failed", "失敗"),
("Succeeded", "成功"), ("Succeeded", "成功"),
("Someone turns on privacy mode, exit", "其他用戶開啟隱私模式,退出"), ("Someone turns on privacy mode, exit", "其他用戶開啟隱私模式,退出"),
@ -280,5 +279,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Turned off", "退出"), ("Turned off", "退出"),
("In privacy mode", "開啟隱私模式"), ("In privacy mode", "開啟隱私模式"),
("Out privacy mode", "退出隱私模式"), ("Out privacy mode", "退出隱私模式"),
("Language", "語言"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -1059,6 +1059,7 @@ sc start {app_name}
sc stop {app_name} sc stop {app_name}
sc delete {app_name} sc delete {app_name}
{after_install} {after_install}
{sleep}
", ",
uninstall_str=uninstall_str, uninstall_str=uninstall_str,
path=path, path=path,
@ -1081,6 +1082,11 @@ sc delete {app_name}
config_path=Config::file().to_str().unwrap_or(""), config_path=Config::file().to_str().unwrap_or(""),
lic=register_licence(), lic=register_licence(),
after_install=get_after_install(&exe), after_install=get_after_install(&exe),
sleep=if debug {
"timeout 300"
} else {
""
}
); );
run_cmds(cmds, debug, "install")?; run_cmds(cmds, debug, "install")?;
std::thread::sleep(std::time::Duration::from_millis(2000)); std::thread::sleep(std::time::Duration::from_millis(2000));

View File

@ -3,9 +3,9 @@ mod cm;
mod inline; mod inline;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
mod macos; mod macos;
pub mod remote;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub mod win_privacy; pub mod win_privacy;
pub mod remote;
use crate::common::SOFTWARE_UPDATE_URL; use crate::common::SOFTWARE_UPDATE_URL;
use crate::ipc; use crate::ipc;
use hbb_common::{ use hbb_common::{
@ -753,6 +753,10 @@ impl UI {
self.get_option_("custom-rendezvous-server"), self.get_option_("custom-rendezvous-server"),
) )
} }
fn get_langs(&self) -> String {
crate::lang::LANGS.to_string()
}
} }
impl sciter::EventHandler for UI { impl sciter::EventHandler for UI {
@ -829,6 +833,7 @@ impl sciter::EventHandler for UI {
fn discover(); fn discover();
fn get_lan_peers(); fn get_lan_peers();
fn get_uuid(); fn get_uuid();
fn get_langs();
} }
} }

View File

@ -163,8 +163,43 @@ class AudioInputs: Reactor.Component {
} }
this.toggleMenuState(); this.toggleMenuState();
} }
};
class Languages: Reactor.Component {
function render() {
var langs = JSON.parse(handler.get_langs());
var me = this;
self.timer(1ms, function() { me.toggleMenuState() });
return <li>{translate('Language')}
<menu #languages key={langs.length}>
<li id="default"><span>{svg_checkmark}</span>Default</li>
<div .separator />
{langs.map(function(lang) {
return <li id={lang[0]}><span>{svg_checkmark}</span>{lang[1]}</li>;
})}
</menu>
</li>;
} }
function toggleMenuState() {
var cur = handler.get_local_option("lang") || "default";
for (var el in this.$$(menu#languages>li)) {
var selected = cur == el.id;
el.attributes.toggleClass("selected", selected);
}
}
event click $(menu#languages>li) (_, me) {
var v = me.id;
if (v == "default") v = "";
handler.set_local_option("lang", v);
app.update();
this.toggleMenuState();
}
}
function getUserName() { function getUserName() {
try { try {
return JSON.parse(handler.get_local_option("user_info")).name; return JSON.parse(handler.get_local_option("user_info")).name;
@ -222,7 +257,7 @@ class MyIdMenu: Reactor.Component {
{handler.is_ok_change_id() && key_confirmed ? <li #change-id>{translate('Change ID')}</li> : ""} {handler.is_ok_change_id() && key_confirmed ? <li #change-id>{translate('Change ID')}</li> : ""}
<div .separator /> <div .separator />
<li #allow-darktheme><span>{svg_checkmark}</span>{translate('Dark Theme')}</li> <li #allow-darktheme><span>{svg_checkmark}</span>{translate('Dark Theme')}</li>
<div .separator /> <Languages />
<li #about>{translate('About')} {" "}{handler.get_app_name()}</li> <li #about>{translate('About')} {" "}{handler.get_app_name()}</li>
</menu> </menu>
</popup>; </popup>;

View File

@ -1956,11 +1956,11 @@ impl Remote {
let mut config: PeerConfig = self.handler.load_config(); let mut config: PeerConfig = self.handler.load_config();
let mut transfer_metas = TransferSerde::default(); let mut transfer_metas = TransferSerde::default();
for job in self.read_jobs.iter() { for job in self.read_jobs.iter() {
let json_str = serde_json::to_string(&job.gen_meta()).unwrap(); let json_str = serde_json::to_string(&job.gen_meta()).unwrap_or_default();
transfer_metas.read_jobs.push(json_str); transfer_metas.read_jobs.push(json_str);
} }
for job in self.write_jobs.iter() { for job in self.write_jobs.iter() {
let json_str = serde_json::to_string(&job.gen_meta()).unwrap(); let json_str = serde_json::to_string(&job.gen_meta()).unwrap_or_default();
transfer_metas.write_jobs.push(json_str); transfer_metas.write_jobs.push(json_str);
} }
log::info!("meta: {:?}", transfer_metas); log::info!("meta: {:?}", transfer_metas);