mirror of
https://github.com/rustdesk/rustdesk
synced 2026-04-21 13:27:19 +00:00
Compare commits
60 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
803ac8cc4e | ||
|
|
4a50bc6fc2 | ||
|
|
e8a1b7fe21 | ||
|
|
ac124c0680 | ||
|
|
91aff3ffd1 | ||
|
|
642c281ad0 | ||
|
|
1e9c4d04f1 | ||
|
|
9f817714fe | ||
|
|
091f2c6135 | ||
|
|
91de51290d | ||
|
|
68fa0466c8 | ||
|
|
28e303576c | ||
|
|
2d41b3e80d | ||
|
|
ffd2d26c1a | ||
|
|
a8dc6fc632 | ||
|
|
771cb4ebd7 | ||
|
|
2f694c0eb2 | ||
|
|
8dea347a21 | ||
|
|
0cf3e8ed40 | ||
|
|
9d3bc7d9e6 | ||
|
|
e0427bdc77 | ||
|
|
9cf1338dc4 | ||
|
|
4e30ee8d1c | ||
|
|
cca6a5fe12 | ||
|
|
9e4b7fca4d | ||
|
|
d135c58ead | ||
|
|
de194417d4 | ||
|
|
d01ce3173f | ||
|
|
010a54d1c9 | ||
|
|
f557fc94fa | ||
|
|
f02cd9c0f6 | ||
|
|
170516572e | ||
|
|
285e29d2dc | ||
|
|
aab34b2338 | ||
|
|
ad1e5330e9 | ||
|
|
ca4647ddd6 | ||
|
|
7004acae46 | ||
|
|
899dd46f5b | ||
|
|
dba5fea66f | ||
|
|
c457b0e7d3 | ||
|
|
c0da4a6645 | ||
|
|
9d8df6a226 | ||
|
|
02da7132e7 | ||
|
|
e3b6e4eaf0 | ||
|
|
0388d00ad3 | ||
|
|
1e2d2c5146 | ||
|
|
96797742f2 | ||
|
|
682e347be0 | ||
|
|
b3f43f55c1 | ||
|
|
016a0b1141 | ||
|
|
fd7bcf54bd | ||
|
|
db3f5fe816 | ||
|
|
0d3016fcd8 | ||
|
|
1abc897c45 | ||
|
|
ab64a32f30 | ||
|
|
52b66e71d1 | ||
|
|
41ab5bbdd8 | ||
|
|
732b250815 | ||
|
|
157dbdc543 | ||
|
|
6ba23683d5 |
120 changed files with 3680 additions and 1295 deletions
2
.github/workflows/flutter-build.yml
vendored
2
.github/workflows/flutter-build.yml
vendored
|
|
@ -40,7 +40,7 @@ env:
|
|||
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
||||
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
|
||||
VERSION: "1.4.6"
|
||||
NDK_VERSION: "r27c"
|
||||
NDK_VERSION: "r28c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
||||
|
|
|
|||
15
.github/workflows/winget.yml
vendored
15
.github/workflows/winget.yml
vendored
|
|
@ -1,15 +0,0 @@
|
|||
name: Publish to WinGet
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: vedantmgoyal9/winget-releaser@main
|
||||
with:
|
||||
identifier: RustDesk.RustDesk
|
||||
version: "1.4.6"
|
||||
release-tag: "1.4.6"
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
||||
106
AGENTS.md
Normal file
106
AGENTS.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# RustDesk Guide
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Build Commands
|
||||
- `cargo run` - Build and run the desktop application (requires libsciter library)
|
||||
- `python3 build.py --flutter` - Build Flutter version (desktop)
|
||||
- `python3 build.py --flutter --release` - Build Flutter version in release mode
|
||||
- `python3 build.py --hwcodec` - Build with hardware codec support
|
||||
- `python3 build.py --vram` - Build with VRAM feature (Windows only)
|
||||
- `cargo build --release` - Build Rust binary in release mode
|
||||
- `cargo build --features hwcodec` - Build with specific features
|
||||
|
||||
### Flutter Mobile Commands
|
||||
- `cd flutter && flutter build android` - Build Android APK
|
||||
- `cd flutter && flutter build ios` - Build iOS app
|
||||
- `cd flutter && flutter run` - Run Flutter app in development mode
|
||||
- `cd flutter && flutter test` - Run Flutter tests
|
||||
|
||||
### Testing
|
||||
- `cargo test` - Run Rust tests
|
||||
- `cd flutter && flutter test` - Run Flutter tests
|
||||
|
||||
### Platform-Specific Build Scripts
|
||||
- `flutter/build_android.sh` - Android build script
|
||||
- `flutter/build_ios.sh` - iOS build script
|
||||
- `flutter/build_fdroid.sh` - F-Droid build script
|
||||
|
||||
## Project Architecture
|
||||
|
||||
### Directory Structure
|
||||
- **`src/`** - Main Rust application code
|
||||
- `src/ui/` - Legacy Sciter UI (deprecated, use Flutter instead)
|
||||
- `src/server/` - Audio/clipboard/input/video services and network connections
|
||||
- `src/client.rs` - Peer connection handling
|
||||
- `src/platform/` - Platform-specific code
|
||||
- **`flutter/`** - Flutter UI code for desktop and mobile
|
||||
- **`libs/`** - Core libraries
|
||||
- `libs/hbb_common/` - Video codec, config, network wrapper, protobuf, file transfer utilities
|
||||
- `libs/scrap/` - Screen capture functionality
|
||||
- `libs/enigo/` - Platform-specific keyboard/mouse control
|
||||
- `libs/clipboard/` - Cross-platform clipboard implementation
|
||||
|
||||
### Key Components
|
||||
- **Remote Desktop Protocol**: Custom protocol implemented in `src/rendezvous_mediator.rs` for communicating with rustdesk-server
|
||||
- **Screen Capture**: Platform-specific screen capture in `libs/scrap/`
|
||||
- **Input Handling**: Cross-platform input simulation in `libs/enigo/`
|
||||
- **Audio/Video Services**: Real-time audio/video streaming in `src/server/`
|
||||
- **File Transfer**: Secure file transfer implementation in `libs/hbb_common/`
|
||||
|
||||
### UI Architecture
|
||||
- **Legacy UI**: Sciter-based (deprecated) - files in `src/ui/`
|
||||
- **Modern UI**: Flutter-based - files in `flutter/`
|
||||
- Desktop: `flutter/lib/desktop/`
|
||||
- Mobile: `flutter/lib/mobile/`
|
||||
- Shared: `flutter/lib/common/` and `flutter/lib/models/`
|
||||
|
||||
## Important Build Notes
|
||||
|
||||
### Dependencies
|
||||
- Requires vcpkg for C++ dependencies: `libvpx`, `libyuv`, `opus`, `aom`
|
||||
- Set `VCPKG_ROOT` environment variable
|
||||
- Download appropriate Sciter library for legacy UI support
|
||||
|
||||
### Ignore Patterns
|
||||
When working with files, ignore these directories:
|
||||
- `target/` - Rust build artifacts
|
||||
- `flutter/build/` - Flutter build output
|
||||
- `flutter/.dart_tool/` - Flutter tooling files
|
||||
|
||||
### Cross-Platform Considerations
|
||||
- Windows builds require additional DLLs and virtual display drivers
|
||||
- macOS builds need proper signing and notarization for distribution
|
||||
- Linux builds support multiple package formats (deb, rpm, AppImage)
|
||||
- Mobile builds require platform-specific toolchains (Android SDK, Xcode)
|
||||
|
||||
### Feature Flags
|
||||
- `hwcodec` - Hardware video encoding/decoding
|
||||
- `vram` - VRAM optimization (Windows only)
|
||||
- `flutter` - Enable Flutter UI
|
||||
- `unix-file-copy-paste` - Unix file clipboard support
|
||||
- `screencapturekit` - macOS ScreenCaptureKit (macOS only)
|
||||
|
||||
### Config
|
||||
All configurations or options are under `libs/hbb_common/src/config.rs` file, 4 types:
|
||||
- Settings
|
||||
- Local
|
||||
- Display
|
||||
- Built-in
|
||||
|
||||
## Rust Rules
|
||||
|
||||
- In Rust code, do not introduce `unwrap()` or `expect()`.
|
||||
- Allowed exceptions:
|
||||
- Tests may use `unwrap()` or `expect()` when it keeps the test focused and readable.
|
||||
- Lock acquisition may use `unwrap()` only when the locking API makes that the practical option and the failure mode is poison handling rather than normal control flow.
|
||||
- Outside those exceptions, propagate errors, handle them explicitly, or use safer fallbacks instead of `unwrap()` and `expect()`.
|
||||
|
||||
## Editing Hygiene
|
||||
|
||||
- Do not introduce formatting-only changes.
|
||||
- Do not run repository-wide formatters or reflow unrelated code unless the
|
||||
user explicitly asks for formatting.
|
||||
- Keep diffs limited to semantic changes required for the task.
|
||||
92
CLAUDE.md
92
CLAUDE.md
|
|
@ -1,91 +1 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Build Commands
|
||||
- `cargo run` - Build and run the desktop application (requires libsciter library)
|
||||
- `python3 build.py --flutter` - Build Flutter version (desktop)
|
||||
- `python3 build.py --flutter --release` - Build Flutter version in release mode
|
||||
- `python3 build.py --hwcodec` - Build with hardware codec support
|
||||
- `python3 build.py --vram` - Build with VRAM feature (Windows only)
|
||||
- `cargo build --release` - Build Rust binary in release mode
|
||||
- `cargo build --features hwcodec` - Build with specific features
|
||||
|
||||
### Flutter Mobile Commands
|
||||
- `cd flutter && flutter build android` - Build Android APK
|
||||
- `cd flutter && flutter build ios` - Build iOS app
|
||||
- `cd flutter && flutter run` - Run Flutter app in development mode
|
||||
- `cd flutter && flutter test` - Run Flutter tests
|
||||
|
||||
### Testing
|
||||
- `cargo test` - Run Rust tests
|
||||
- `cd flutter && flutter test` - Run Flutter tests
|
||||
|
||||
### Platform-Specific Build Scripts
|
||||
- `flutter/build_android.sh` - Android build script
|
||||
- `flutter/build_ios.sh` - iOS build script
|
||||
- `flutter/build_fdroid.sh` - F-Droid build script
|
||||
|
||||
## Project Architecture
|
||||
|
||||
### Directory Structure
|
||||
- **`src/`** - Main Rust application code
|
||||
- `src/ui/` - Legacy Sciter UI (deprecated, use Flutter instead)
|
||||
- `src/server/` - Audio/clipboard/input/video services and network connections
|
||||
- `src/client.rs` - Peer connection handling
|
||||
- `src/platform/` - Platform-specific code
|
||||
- **`flutter/`** - Flutter UI code for desktop and mobile
|
||||
- **`libs/`** - Core libraries
|
||||
- `libs/hbb_common/` - Video codec, config, network wrapper, protobuf, file transfer utilities
|
||||
- `libs/scrap/` - Screen capture functionality
|
||||
- `libs/enigo/` - Platform-specific keyboard/mouse control
|
||||
- `libs/clipboard/` - Cross-platform clipboard implementation
|
||||
|
||||
### Key Components
|
||||
- **Remote Desktop Protocol**: Custom protocol implemented in `src/rendezvous_mediator.rs` for communicating with rustdesk-server
|
||||
- **Screen Capture**: Platform-specific screen capture in `libs/scrap/`
|
||||
- **Input Handling**: Cross-platform input simulation in `libs/enigo/`
|
||||
- **Audio/Video Services**: Real-time audio/video streaming in `src/server/`
|
||||
- **File Transfer**: Secure file transfer implementation in `libs/hbb_common/`
|
||||
|
||||
### UI Architecture
|
||||
- **Legacy UI**: Sciter-based (deprecated) - files in `src/ui/`
|
||||
- **Modern UI**: Flutter-based - files in `flutter/`
|
||||
- Desktop: `flutter/lib/desktop/`
|
||||
- Mobile: `flutter/lib/mobile/`
|
||||
- Shared: `flutter/lib/common/` and `flutter/lib/models/`
|
||||
|
||||
## Important Build Notes
|
||||
|
||||
### Dependencies
|
||||
- Requires vcpkg for C++ dependencies: `libvpx`, `libyuv`, `opus`, `aom`
|
||||
- Set `VCPKG_ROOT` environment variable
|
||||
- Download appropriate Sciter library for legacy UI support
|
||||
|
||||
### Ignore Patterns
|
||||
When working with files, ignore these directories:
|
||||
- `target/` - Rust build artifacts
|
||||
- `flutter/build/` - Flutter build output
|
||||
- `flutter/.dart_tool/` - Flutter tooling files
|
||||
|
||||
### Cross-Platform Considerations
|
||||
- Windows builds require additional DLLs and virtual display drivers
|
||||
- macOS builds need proper signing and notarization for distribution
|
||||
- Linux builds support multiple package formats (deb, rpm, AppImage)
|
||||
- Mobile builds require platform-specific toolchains (Android SDK, Xcode)
|
||||
|
||||
### Feature Flags
|
||||
- `hwcodec` - Hardware video encoding/decoding
|
||||
- `vram` - VRAM optimization (Windows only)
|
||||
- `flutter` - Enable Flutter UI
|
||||
- `unix-file-copy-paste` - Unix file clipboard support
|
||||
- `screencapturekit` - macOS ScreenCaptureKit (macOS only)
|
||||
|
||||
### Config
|
||||
All configurations or options are under `libs/hbb_common/src/config.rs` file, 4 types:
|
||||
- Settings
|
||||
- Local
|
||||
- Display
|
||||
- Built-in
|
||||
AGENTS.md
|
||||
|
|
|
|||
354
Cargo.lock
generated
354
Cargo.lock
generated
|
|
@ -33,6 +33,12 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
|
|
@ -293,8 +299,8 @@ dependencies = [
|
|||
"image 0.25.1",
|
||||
"log",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"serde 1.0.228",
|
||||
|
|
@ -637,7 +643,7 @@ dependencies = [
|
|||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.4",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
|
@ -860,6 +866,15 @@ dependencies = [
|
|||
"objc2 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
||||
dependencies = [
|
||||
"objc2 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.1"
|
||||
|
|
@ -1182,7 +1197,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"num-traits 0.2.19",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1290,8 +1305,8 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"libc",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
|
|
@ -2216,6 +2231,15 @@ dependencies = [
|
|||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
|
|
@ -2233,7 +2257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"redox_users 0.4.5",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
|
|
@ -2245,10 +2269,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"redox_users 0.4.5",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
|
|
@ -2256,7 +2292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"redox_users 0.4.5",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
|
|
@ -2266,6 +2302,16 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
||||
|
||||
[[package]]
|
||||
name = "dispatch2"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"objc2 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
|
|
@ -2715,7 +2761,7 @@ dependencies = [
|
|||
"flume",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.4",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
|
|
@ -2801,12 +2847,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.30"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4041,7 +4087,7 @@ dependencies = [
|
|||
"gif",
|
||||
"jpeg-decoder",
|
||||
"num-traits 0.2.19",
|
||||
"png",
|
||||
"png 0.17.13",
|
||||
"qoi",
|
||||
"tiff",
|
||||
]
|
||||
|
|
@ -4055,7 +4101,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"byteorder",
|
||||
"num-traits 0.2.19",
|
||||
"png",
|
||||
"png 0.17.13",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
|
|
@ -4766,6 +4812,16 @@ dependencies = [
|
|||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.11"
|
||||
|
|
@ -4816,21 +4872,23 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "muda"
|
||||
version = "0.13.5"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b959f97c97044e4c96e32e1db292a7d594449546a3c6b77ae613dc3a5b5145"
|
||||
checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a"
|
||||
dependencies = [
|
||||
"cocoa 0.25.0",
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
"gtk",
|
||||
"keyboard-types",
|
||||
"libxdo",
|
||||
"objc",
|
||||
"objc2 0.6.4",
|
||||
"objc2-app-kit 0.3.2",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.2",
|
||||
"once_cell",
|
||||
"png",
|
||||
"thiserror 1.0.61",
|
||||
"windows-sys 0.52.0",
|
||||
"png 0.17.13",
|
||||
"thiserror 2.0.17",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5374,7 +5432,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
|
||||
dependencies = [
|
||||
"objc-sys 0.3.5",
|
||||
"objc2-encode 4.0.3",
|
||||
"objc2-encode 4.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
||||
dependencies = [
|
||||
"objc2-encode 4.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5389,10 +5456,22 @@ dependencies = [
|
|||
"objc2 0.5.2",
|
||||
"objc2-core-data",
|
||||
"objc2-core-image",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-quartz-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-app-kit"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"objc2 0.6.4",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-cloud-kit"
|
||||
version = "0.2.2"
|
||||
|
|
@ -5403,7 +5482,7 @@ dependencies = [
|
|||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5414,7 +5493,7 @@ checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
|
|||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5426,7 +5505,28 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"dispatch2",
|
||||
"objc2 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-graphics"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5437,7 +5537,7 @@ checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
|
|||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-metal",
|
||||
]
|
||||
|
||||
|
|
@ -5450,7 +5550,7 @@ dependencies = [
|
|||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-contacts",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5464,9 +5564,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "4.0.3"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8"
|
||||
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
|
|
@ -5481,6 +5581,18 @@ dependencies = [
|
|||
"objc2 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2 0.6.2",
|
||||
"objc2 0.6.4",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-link-presentation"
|
||||
version = "0.2.2"
|
||||
|
|
@ -5489,8 +5601,8 @@ checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
|||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5502,7 +5614,7 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5514,7 +5626,7 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-metal",
|
||||
]
|
||||
|
||||
|
|
@ -5525,7 +5637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
|
||||
dependencies = [
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5541,7 +5653,7 @@ dependencies = [
|
|||
"objc2-core-data",
|
||||
"objc2-core-image",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-link-presentation",
|
||||
"objc2-quartz-core",
|
||||
"objc2-symbols",
|
||||
|
|
@ -5557,7 +5669,7 @@ checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
|
|||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5570,7 +5682,7 @@ dependencies = [
|
|||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6178,7 +6290,20 @@ dependencies = [
|
|||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6863,6 +6988,17 @@ dependencies = [
|
|||
"thiserror 1.0.61",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
|
|
@ -7981,8 +8117,8 @@ dependencies = [
|
|||
"log",
|
||||
"memmap2",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-quartz-core",
|
||||
"raw-window-handle 0.6.2",
|
||||
"redox_syscall 0.5.2",
|
||||
|
|
@ -8312,7 +8448,7 @@ dependencies = [
|
|||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"png",
|
||||
"png 0.17.13",
|
||||
"raw-window-handle 0.6.2",
|
||||
"scopeguard",
|
||||
"tao-macros",
|
||||
|
|
@ -8566,7 +8702,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"cfg-if 1.0.0",
|
||||
"log",
|
||||
"png",
|
||||
"png 0.17.13",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
|
|
@ -8939,21 +9075,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.14.3"
|
||||
source = "git+https://github.com/tauri-apps/tray-icon#d4078696edba67b0ab42cef67e6a421a0332c96f"
|
||||
version = "0.21.3"
|
||||
source = "git+https://github.com/tauri-apps/tray-icon#0a5835b0e6828e37a1f781de9c2d671ae7a939e6"
|
||||
dependencies = [
|
||||
"core-graphics 0.23.2",
|
||||
"crossbeam-channel",
|
||||
"dirs 5.0.1",
|
||||
"dirs 6.0.0",
|
||||
"libappindicator",
|
||||
"muda",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2 0.6.4",
|
||||
"objc2-app-kit 0.3.2",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
"objc2-foundation 0.3.2",
|
||||
"once_cell",
|
||||
"png",
|
||||
"thiserror 1.0.61",
|
||||
"windows-sys 0.52.0",
|
||||
"png 0.18.1",
|
||||
"thiserror 2.0.17",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -10058,7 +10195,7 @@ dependencies = [
|
|||
"windows-collections",
|
||||
"windows-core 0.61.0",
|
||||
"windows-future",
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
"windows-numerics",
|
||||
]
|
||||
|
||||
|
|
@ -10107,7 +10244,7 @@ checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
|||
dependencies = [
|
||||
"windows-implement 0.60.0",
|
||||
"windows-interface 0.59.1",
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
"windows-result 0.3.2",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
|
@ -10119,7 +10256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -10172,6 +10309,12 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.2.0"
|
||||
|
|
@ -10179,7 +10322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -10197,7 +10340,7 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -10217,7 +10360,7 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -10226,7 +10369,7 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -10256,6 +10399,24 @@ dependencies = [
|
|||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
|
|
@ -10295,13 +10456,30 @@ dependencies = [
|
|||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
"windows_i686_gnullvm 0.53.1",
|
||||
"windows_i686_msvc 0.53.1",
|
||||
"windows_x86_64_gnu 0.53.1",
|
||||
"windows_x86_64_gnullvm 0.53.1",
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-version"
|
||||
version = "0.1.1"
|
||||
|
|
@ -10338,6 +10516,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.32.0"
|
||||
|
|
@ -10368,6 +10552,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.32.0"
|
||||
|
|
@ -10398,12 +10588,24 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.32.0"
|
||||
|
|
@ -10434,6 +10636,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.32.0"
|
||||
|
|
@ -10464,6 +10672,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
|
|
@ -10482,6 +10696,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.32.0"
|
||||
|
|
@ -10512,6 +10732,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.30.9"
|
||||
|
|
@ -10536,8 +10762,8 @@ dependencies = [
|
|||
"memmap2",
|
||||
"ndk 0.9.0",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-ui-kit",
|
||||
"orbclient",
|
||||
"percent-encoding",
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ piet-coregraphics = "0.6"
|
|||
foreign-types = "0.3"
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
||||
tray-icon = { git = "https://github.com/tauri-apps/tray-icon" }
|
||||
tray-icon = { git = "https://github.com/tauri-apps/tray-icon", version = "0.21.3" }
|
||||
tao = { git = "https://github.com/rustdesk-org/tao", branch = "dev" }
|
||||
image = "0.24"
|
||||
|
||||
|
|
@ -245,3 +245,6 @@ panic = 'abort'
|
|||
strip = true
|
||||
#opt-level = 'z' # only have smaller size after strip
|
||||
rpath = true
|
||||
|
||||
[profile.dev]
|
||||
debug = 1
|
||||
|
|
|
|||
1
GEMINI.md
Normal file
1
GEMINI.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
AGENTS.md
|
||||
|
|
@ -167,7 +167,7 @@ target/release/rustdesk
|
|||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс на Sciter (устаревшее)
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио, буфера обмена, ввода, видео и сетевых подключений
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: одноранговое соединение
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: связь с [сервером Rustdesk](https://github.com/rustdesk/rustdesk-server), ожидает удаленного прямого (через TCP hole punching) или ретранслируемого соединения
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: связь с [сервером RustDesk](https://github.com/rustdesk/rustdesk-server), ожидает удаленного прямого (через TCP hole punching) или ретранслируемого соединения
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
|
||||
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: код Flutter для ПК-версии и мобильных устройств
|
||||
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript для Web-клиента Flutter
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<li> Supports VP8 / VP9 / AV1 software codecs, and H264 / H265 hardware codecs. </li>
|
||||
<li> Own your data, easily set up self-hosting solution on your infrastructure. </li>
|
||||
<li> P2P connection with end-to-end encryption based on NaCl. </li>
|
||||
<li> No administrative privileges or installation needed for Windows, elevate priviledge locally or from remote on demand. </li>
|
||||
<li> No administrative privileges or installation needed for Windows, elevate privilege locally or from remote on demand. </li>
|
||||
<li> We like to keep things simple and will strive to make simpler where possible. </li>
|
||||
</ul>
|
||||
<p>
|
||||
|
|
@ -56,4 +56,4 @@
|
|||
<control>pointing</control>
|
||||
</supports>
|
||||
<content_rating type="oars-1.1"/>
|
||||
</component>
|
||||
</component>
|
||||
|
|
|
|||
|
|
@ -311,7 +311,10 @@ class FloatingWindowService : Service(), View.OnTouchListener {
|
|||
popupMenu.menu.add(0, idSyncClipboard, 0, translate("Update client clipboard"))
|
||||
}
|
||||
val idStopService = 2
|
||||
popupMenu.menu.add(0, idStopService, 0, translate("Stop service"))
|
||||
val hideStopService = FFI.getBuildinOption("hide-stop-service") == "Y"
|
||||
if (!hideStopService) {
|
||||
popupMenu.menu.add(0, idStopService, 0, translate("Stop service"))
|
||||
}
|
||||
popupMenu.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
idShowRustDesk -> {
|
||||
|
|
@ -389,4 +392,3 @@ class FloatingWindowService : Service(), View.OnTouchListener {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ object FFI {
|
|||
external fun setFrameRawEnable(name: String, value: Boolean)
|
||||
external fun setCodecInfo(info: String)
|
||||
external fun getLocalOption(key: String): String
|
||||
external fun getBuildinOption(key: String): String
|
||||
external fun onClipboardUpdate(clips: ByteBuffer)
|
||||
external fun isServiceClipboardEnabled(): Boolean
|
||||
}
|
||||
|
|
|
|||
1
flutter/assets/auth-microsoft.svg
Normal file
1
flutter/assets/auth-microsoft.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"><rect x="4" y="4" width="19" height="19" fill="#f25022"/><rect x="25" y="4" width="19" height="19" fill="#7fba00"/><rect x="4" y="25" width="19" height="19" fill="#00a4ef"/><rect x="25" y="25" width="19" height="19" fill="#ffb900"/></svg>
|
||||
|
After Width: | Height: | Size: 321 B |
|
|
@ -7,7 +7,7 @@
|
|||
# 2024, Vasyl Gello <vasek.gello@gmail.com>
|
||||
#
|
||||
|
||||
# The script is invoked by F-Droid builder system ste-by-step.
|
||||
# The script is invoked by F-Droid builder system step-by-step.
|
||||
#
|
||||
# It accepts the following arguments:
|
||||
#
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
# - Android architecture to build APK for: armeabi-v7a arm64-v8av x86 x86_64
|
||||
# - The build step to execute:
|
||||
#
|
||||
# + sudo-deps: as root, install needed Debian packages into builder VM
|
||||
# + prebuild: patch sources and do other stuff before the build
|
||||
# + build: perform actual build of APK file
|
||||
#
|
||||
|
|
@ -184,13 +183,9 @@ prebuild)
|
|||
fi
|
||||
|
||||
# Map NDK version to revision
|
||||
|
||||
NDK_VERSION="$(wget \
|
||||
-qO- \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
'https://api.github.com/repos/android/ndk/releases' |
|
||||
jq -r ".[] | select(.tag_name == \"${NDK_VERSION}\") | .body | match(\"ndkVersion \\\"(.*)\\\"\").captures[0].string")"
|
||||
NDK_VERSION="$(curl https://gitlab.com/fdroid/android-sdk-transparency-log/-/raw/master/signed/checksums.json |
|
||||
jq -r ".\"https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-linux.zip\"[0].\"source.properties\"" |
|
||||
sed -n -E 's/.*Pkg.Revision = ([0-9.]+).*/\1/p')"
|
||||
|
||||
if [ -z "${NDK_VERSION}" ]; then
|
||||
echo "ERROR: Can not map Android NDK codename to revision!" >&2
|
||||
|
|
@ -316,6 +311,18 @@ prebuild)
|
|||
# `FLUTTER_BRIDGE_VERSION` an restore the pubspec later
|
||||
|
||||
if [ "${FLUTTER_VERSION}" != "${FLUTTER_BRIDGE_VERSION}" ]; then
|
||||
# Find first libclang.so and set BRIDGE_LLVM_PATH
|
||||
|
||||
BRIDGE_LLVM_PATH="$(find /usr/lib/ -name libclang.so | head -n1)"
|
||||
|
||||
if [ -z "${BRIDGE_LLVM_PATH}" ]; then
|
||||
echo 'ERROR: Can not find libclang.so for bridge generator!' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BRIDGE_LLVM_PATH="$(dirname "${BRIDGE_LLVM_PATH}")"
|
||||
BRIDGE_LLVM_PATH="$(dirname "${BRIDGE_LLVM_PATH}")"
|
||||
|
||||
# Install Flutter bridge version
|
||||
|
||||
prepare_flutter "${FLUTTER_BRIDGE_VERSION}" "${HOME}/flutter"
|
||||
|
|
@ -344,7 +351,8 @@ prebuild)
|
|||
|
||||
flutter_rust_bridge_codegen \
|
||||
--rust-input ./src/flutter_ffi.rs \
|
||||
--dart-output ./flutter/lib/generated_bridge.dart
|
||||
--dart-output ./flutter/lib/generated_bridge.dart \
|
||||
--llvm-path "${BRIDGE_LLVM_PATH}"
|
||||
|
||||
# Add bridge files to save-list
|
||||
|
||||
|
|
@ -355,13 +363,15 @@ prebuild)
|
|||
git checkout '*'
|
||||
git clean -dffx
|
||||
git reset
|
||||
|
||||
unset BRIDGE_LLVM_PATH
|
||||
fi
|
||||
|
||||
# Install Flutter version for RustDesk library build
|
||||
|
||||
prepare_flutter "${FLUTTER_VERSION}" "${HOME}/flutter"
|
||||
|
||||
# gms is not in thoes files now, but we still keep the following line for future reference(maybe).
|
||||
# gms is not in these files now, but we still keep the following line for future reference(maybe).
|
||||
|
||||
sed \
|
||||
-i \
|
||||
|
|
@ -414,13 +424,9 @@ build)
|
|||
.github/workflows/flutter-build.yml)"
|
||||
|
||||
# Map NDK version to revision
|
||||
|
||||
NDK_VERSION="$(wget \
|
||||
-qO- \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
'https://api.github.com/repos/android/ndk/releases' |
|
||||
jq -r ".[] | select(.tag_name == \"${NDK_VERSION}\") | .body | match(\"ndkVersion \\\"(.*)\\\"\").captures[0].string")"
|
||||
NDK_VERSION="$(curl https://gitlab.com/fdroid/android-sdk-transparency-log/-/raw/master/signed/checksums.json |
|
||||
jq -r ".\"https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-linux.zip\"[0].\"source.properties\"" |
|
||||
sed -n -E 's/.*Pkg.Revision = ([0-9.]+).*/\1/p')"
|
||||
|
||||
if [ -z "${NDK_VERSION}" ]; then
|
||||
echo "ERROR: Can not map Android NDK codename to revision!" >&2
|
||||
|
|
|
|||
|
|
@ -2365,6 +2365,19 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
|
|||
id = uri.path.substring("/new/".length);
|
||||
} else if (uri.authority == "config") {
|
||||
if (isAndroid || isIOS) {
|
||||
final allowDeepLinkServerSettings =
|
||||
bind.mainGetBuildinOption(key: kOptionAllowDeepLinkServerSettings) ==
|
||||
'Y';
|
||||
if (!allowDeepLinkServerSettings) {
|
||||
debugPrint(
|
||||
"Ignore rustdesk://config because $kOptionAllowDeepLinkServerSettings is not enabled.");
|
||||
// Keep the user-facing error generic; detailed rejection reason is in debug logs.
|
||||
// Delay toast to avoid missing overlay during cold-start deeplink handling.
|
||||
Timer(Duration(seconds: 1), () {
|
||||
showToast(translate('Failed'));
|
||||
});
|
||||
return null;
|
||||
}
|
||||
final config = uri.path.substring("/".length);
|
||||
// add a timer to make showToast work
|
||||
Timer(Duration(seconds: 1), () {
|
||||
|
|
@ -2374,11 +2387,24 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
|
|||
return null;
|
||||
} else if (uri.authority == "password") {
|
||||
if (isAndroid || isIOS) {
|
||||
final allowDeepLinkPassword =
|
||||
bind.mainGetBuildinOption(key: kOptionAllowDeepLinkPassword) == 'Y';
|
||||
if (!allowDeepLinkPassword) {
|
||||
debugPrint(
|
||||
"Ignore rustdesk://password because $kOptionAllowDeepLinkPassword is not enabled.");
|
||||
// Keep the user-facing error generic; detailed rejection reason is in debug logs.
|
||||
// Delay toast to avoid missing overlay during cold-start deeplink handling.
|
||||
Timer(Duration(seconds: 1), () {
|
||||
showToast(translate('Failed'));
|
||||
});
|
||||
return null;
|
||||
}
|
||||
final password = uri.path.substring("/".length);
|
||||
if (password.isNotEmpty) {
|
||||
Timer(Duration(seconds: 1), () async {
|
||||
await bind.mainSetPermanentPassword(password: password);
|
||||
showToast(translate('Successful'));
|
||||
final ok =
|
||||
await bind.mainSetPermanentPasswordWithResult(password: password);
|
||||
showToast(translate(ok ? 'Successful' : 'Failed'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -4118,3 +4144,43 @@ String mouseButtonsToPeer(int buttons) {
|
|||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// Build an avatar widget from an avatar URL or data URI string.
|
||||
/// Returns [fallback] if avatar is empty or cannot be decoded.
|
||||
/// [borderRadius] defaults to [size]/2 (circle).
|
||||
Widget? buildAvatarWidget({
|
||||
required String avatar,
|
||||
required double size,
|
||||
double? borderRadius,
|
||||
Widget? fallback,
|
||||
}) {
|
||||
final trimmed = avatar.trim();
|
||||
if (trimmed.isEmpty) return fallback;
|
||||
|
||||
ImageProvider? imageProvider;
|
||||
if (trimmed.startsWith('data:image/')) {
|
||||
final comma = trimmed.indexOf(',');
|
||||
if (comma > 0) {
|
||||
try {
|
||||
imageProvider = MemoryImage(base64Decode(trimmed.substring(comma + 1)));
|
||||
} catch (_) {}
|
||||
}
|
||||
} else if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
|
||||
imageProvider = NetworkImage(trimmed);
|
||||
}
|
||||
|
||||
if (imageProvider == null) return fallback;
|
||||
|
||||
final radius = borderRadius ?? size / 2;
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
child: Image(
|
||||
image: imageProvider,
|
||||
width: size,
|
||||
height: size,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) =>
|
||||
fallback ?? SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ enum UserStatus { kDisabled, kNormal, kUnverified }
|
|||
class UserPayload {
|
||||
String name = '';
|
||||
String displayName = '';
|
||||
String avatar = '';
|
||||
String email = '';
|
||||
String note = '';
|
||||
String? verifier;
|
||||
|
|
@ -35,6 +36,7 @@ class UserPayload {
|
|||
UserPayload.fromJson(Map<String, dynamic> json)
|
||||
: name = json['name'] ?? '',
|
||||
displayName = json['display_name'] ?? '',
|
||||
avatar = json['avatar'] ?? '',
|
||||
email = json['email'] ?? '',
|
||||
note = json['note'] ?? '',
|
||||
verifier = json['verifier'],
|
||||
|
|
@ -49,6 +51,7 @@ class UserPayload {
|
|||
final Map<String, dynamic> map = {
|
||||
'name': name,
|
||||
'display_name': displayName,
|
||||
'avatar': avatar,
|
||||
'status': status == UserStatus.kDisabled
|
||||
? 0
|
||||
: status == UserStatus.kUnverified
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ class _AddressBookState extends State<AddressBook> {
|
|||
const LinearProgressIndicator(),
|
||||
buildErrorBanner(context,
|
||||
loading: gFFI.abModel.currentAbLoading,
|
||||
err: gFFI.abModel.currentAbPullError,
|
||||
err: gFFI.abModel.abPullError,
|
||||
retry: null,
|
||||
close: () => gFFI.abModel.currentAbPullError.value = ''),
|
||||
close: gFFI.abModel.clearPullErrors),
|
||||
buildErrorBanner(context,
|
||||
loading: gFFI.abModel.currentAbLoading,
|
||||
err: gFFI.abModel.currentAbPushError,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ const kOpSvgList = [
|
|||
'okta',
|
||||
'facebook',
|
||||
'azure',
|
||||
'auth0'
|
||||
'auth0',
|
||||
'microsoft'
|
||||
];
|
||||
|
||||
class _IconOP extends StatelessWidget {
|
||||
|
|
@ -224,21 +225,59 @@ class _WidgetOPState extends State<WidgetOP> {
|
|||
return Offstage(
|
||||
offstage:
|
||||
_failedMsg.isEmpty && widget.curOP.value != widget.config.op,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: '$_stateMsg ',
|
||||
style:
|
||||
DefaultTextStyle.of(context).style.copyWith(fontSize: 12),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: _failedMsg,
|
||||
style: DefaultTextStyle.of(context).style.copyWith(
|
||||
fontSize: 14,
|
||||
color: Colors.red,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (_stateMsg.isNotEmpty && _failedMsg.isEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: SelectableText(
|
||||
translate(_stateMsg),
|
||||
style: DefaultTextStyle.of(context)
|
||||
.style
|
||||
.copyWith(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_failedMsg.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Builder(builder: (context) {
|
||||
final errorColor =
|
||||
Theme.of(context).colorScheme.error;
|
||||
final bgColor = Theme.of(context)
|
||||
.colorScheme
|
||||
.errorContainer
|
||||
.withOpacity(0.3);
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0, vertical: 6.0),
|
||||
decoration: BoxDecoration(
|
||||
color: bgColor,
|
||||
borderRadius: BorderRadius.circular(4.0),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.error_outline,
|
||||
color: errorColor, size: 16),
|
||||
const SizedBox(width: 6),
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
translate(_failedMsg),
|
||||
style: DefaultTextStyle.of(context)
|
||||
.style
|
||||
.copyWith(
|
||||
fontSize: 13,
|
||||
color: errorColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class RawKeyFocusScope extends StatelessWidget {
|
|||
// https://github.com/flutter/flutter/issues/154053
|
||||
final useRawKeyEvents = isLinux && !isWeb;
|
||||
// FIXME: On Windows, `AltGr` will generate `Alt` and `Control` key events,
|
||||
// while `Alt` and `Control` are seperated key events for en-US input method.
|
||||
// while `Alt` and `Control` are separated key events for en-US input method.
|
||||
return FocusScope(
|
||||
autofocus: true,
|
||||
child: Focus(
|
||||
|
|
|
|||
|
|
@ -275,7 +275,6 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
|||
isDesktop &&
|
||||
ffiModel.keyboard &&
|
||||
pi.platform != kPeerPlatformAndroid &&
|
||||
pi.platform != kPeerPlatformMacOS &&
|
||||
versionCmp(pi.version, '1.2.0') >= 0 &&
|
||||
bind.peerGetSessionsCount(id: id, connType: ffi.connType.index) == 1) {
|
||||
v.add(TTextMenu(
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ const String kOptionEnableFlutterHttpOnRust = "enable-flutter-http-on-rust";
|
|||
const String kOptionHideServerSetting = "hide-server-settings";
|
||||
const String kOptionHideProxySetting = "hide-proxy-settings";
|
||||
const String kOptionHideWebSocketSetting = "hide-websocket-settings";
|
||||
const String kOptionHideStopService = "hide-stop-service";
|
||||
const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings";
|
||||
const String kOptionHideSecuritySetting = "hide-security-settings";
|
||||
const String kOptionHideNetworkSetting = "hide-network-settings";
|
||||
|
|
@ -186,6 +187,9 @@ const String kOptionDisableChangeId = "disable-change-id";
|
|||
const String kOptionDisableUnlockPin = "disable-unlock-pin";
|
||||
const kHideUsernameOnCard = "hide-username-on-card";
|
||||
const String kOptionHideHelpCards = "hide-help-cards";
|
||||
const String kOptionAllowDeepLinkPassword = "allow-deep-link-password";
|
||||
const String kOptionAllowDeepLinkServerSettings =
|
||||
"allow-deep-link-server-settings";
|
||||
|
||||
const String kOptionToggleViewOnly = "view-only";
|
||||
const String kOptionToggleShowMyCursor = "show-my-cursor";
|
||||
|
|
|
|||
|
|
@ -908,12 +908,17 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
|||
}
|
||||
|
||||
void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
||||
final pw = await bind.mainGetPermanentPassword();
|
||||
final p0 = TextEditingController(text: pw);
|
||||
final p1 = TextEditingController(text: pw);
|
||||
final p0 = TextEditingController(text: "");
|
||||
final p1 = TextEditingController(text: "");
|
||||
var errMsg0 = "";
|
||||
var errMsg1 = "";
|
||||
final RxString rxPass = pw.trim().obs;
|
||||
final localPasswordSet =
|
||||
(await bind.mainGetCommon(key: "local-permanent-password-set")) == "true";
|
||||
final permanentPasswordSet =
|
||||
(await bind.mainGetCommon(key: "permanent-password-set")) == "true";
|
||||
final presetPassword = permanentPasswordSet && !localPasswordSet;
|
||||
var canSubmit = false;
|
||||
final RxString rxPass = "".obs;
|
||||
final rules = [
|
||||
DigitValidationRule(),
|
||||
UppercaseValidationRule(),
|
||||
|
|
@ -922,9 +927,21 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
MinCharactersValidationRule(8),
|
||||
];
|
||||
final maxLength = bind.mainMaxEncryptLen();
|
||||
final statusTip = localPasswordSet
|
||||
? translate('password-hidden-tip')
|
||||
: (presetPassword ? translate('preset-password-in-use-tip') : '');
|
||||
final showStatusTipOnMobile =
|
||||
statusTip.isNotEmpty && !isDesktop && !isWebDesktop;
|
||||
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() {
|
||||
updateCanSubmit() {
|
||||
canSubmit = p0.text.trim().isNotEmpty || p1.text.trim().isNotEmpty;
|
||||
}
|
||||
|
||||
submit() async {
|
||||
if (!canSubmit) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
errMsg0 = "";
|
||||
errMsg1 = "";
|
||||
|
|
@ -947,7 +964,13 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
});
|
||||
return;
|
||||
}
|
||||
bind.mainSetPermanentPassword(password: pass);
|
||||
final ok = await bind.mainSetPermanentPasswordWithResult(password: pass);
|
||||
if (!ok) {
|
||||
setState(() {
|
||||
errMsg0 = '${translate('Prompt')}: ${translate("Failed")}';
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (pass.isNotEmpty) {
|
||||
notEmptyCallback?.call();
|
||||
}
|
||||
|
|
@ -955,14 +978,20 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Set Password")),
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.key, color: MyTheme.accent),
|
||||
Text(translate("Set Password")).paddingOnly(left: 10),
|
||||
],
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 500),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8.0,
|
||||
SizedBox(
|
||||
height: showStatusTipOnMobile ? 0.0 : 6.0,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -978,6 +1007,7 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
rxPass.value = value.trim();
|
||||
setState(() {
|
||||
errMsg0 = '';
|
||||
updateCanSubmit();
|
||||
});
|
||||
},
|
||||
maxLength: maxLength,
|
||||
|
|
@ -989,9 +1019,9 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
children: [
|
||||
Expanded(child: PasswordStrengthIndicator(password: rxPass)),
|
||||
],
|
||||
).marginSymmetric(vertical: 8),
|
||||
const SizedBox(
|
||||
height: 8.0,
|
||||
).marginOnly(top: 2, bottom: showStatusTipOnMobile ? 2 : 8),
|
||||
SizedBox(
|
||||
height: showStatusTipOnMobile ? 0.0 : 8.0,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -1005,6 +1035,7 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
onChanged: (value) {
|
||||
setState(() {
|
||||
errMsg1 = '';
|
||||
updateCanSubmit();
|
||||
});
|
||||
},
|
||||
maxLength: maxLength,
|
||||
|
|
@ -1012,11 +1043,23 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8.0,
|
||||
if (statusTip.isNotEmpty)
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.info, color: Colors.amber, size: 18)
|
||||
.marginOnly(right: 6),
|
||||
Expanded(
|
||||
child: Text(
|
||||
statusTip,
|
||||
style: const TextStyle(fontSize: 13, height: 1.1),
|
||||
))
|
||||
],
|
||||
).marginOnly(top: 6, bottom: 2),
|
||||
SizedBox(
|
||||
height: showStatusTipOnMobile ? 0.0 : 8.0,
|
||||
),
|
||||
Obx(() => Wrap(
|
||||
runSpacing: 8,
|
||||
runSpacing: showStatusTipOnMobile ? 2.0 : 8.0,
|
||||
spacing: 4,
|
||||
children: rules.map((e) {
|
||||
var checked = e.validate(rxPass.value.trim());
|
||||
|
|
@ -1036,11 +1079,67 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
|
|||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
dialogButton("Cancel", onPressed: close, isOutline: true),
|
||||
dialogButton("OK", onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
actions: (() {
|
||||
final cancelButton = dialogButton(
|
||||
"Cancel",
|
||||
icon: Icon(Icons.close_rounded),
|
||||
onPressed: close,
|
||||
isOutline: true,
|
||||
);
|
||||
final removeButton = dialogButton(
|
||||
"Remove",
|
||||
icon: Icon(Icons.delete_outline_rounded),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
errMsg0 = "";
|
||||
errMsg1 = "";
|
||||
});
|
||||
final ok =
|
||||
await bind.mainSetPermanentPasswordWithResult(password: "");
|
||||
if (!ok) {
|
||||
setState(() {
|
||||
errMsg0 = '${translate('Prompt')}: ${translate("Failed")}';
|
||||
});
|
||||
return;
|
||||
}
|
||||
close();
|
||||
},
|
||||
buttonStyle: ButtonStyle(
|
||||
backgroundColor: MaterialStatePropertyAll(Colors.red)),
|
||||
);
|
||||
final okButton = dialogButton(
|
||||
"OK",
|
||||
icon: Icon(Icons.done_rounded),
|
||||
onPressed: canSubmit ? submit : null,
|
||||
);
|
||||
if (!isDesktop && !isWebDesktop && localPasswordSet) {
|
||||
return [
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
cancelButton,
|
||||
const SizedBox(width: 4),
|
||||
removeButton,
|
||||
const SizedBox(width: 4),
|
||||
okButton,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
return [
|
||||
cancelButton,
|
||||
if (localPasswordSet) removeButton,
|
||||
okButton,
|
||||
];
|
||||
})(),
|
||||
onSubmit: canSubmit ? submit : null,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -458,18 +458,27 @@ class _GeneralState extends State<_General> {
|
|||
return const Offstage();
|
||||
}
|
||||
|
||||
return _Card(title: 'Service', children: [
|
||||
Obx(() => _Button(serviceStop.value ? 'Start' : 'Stop', () {
|
||||
() async {
|
||||
serviceBtnEnabled.value = false;
|
||||
await start_service(serviceStop.value);
|
||||
// enable the button after 1 second
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
serviceBtnEnabled.value = true;
|
||||
});
|
||||
}();
|
||||
}, enabled: serviceBtnEnabled.value))
|
||||
]);
|
||||
final hideStopService =
|
||||
bind.mainGetBuildinOption(key: kOptionHideStopService) == 'Y';
|
||||
|
||||
return Obx(() {
|
||||
if (hideStopService && !serviceStop.value) {
|
||||
return const Offstage();
|
||||
}
|
||||
|
||||
return _Card(title: 'Service', children: [
|
||||
_Button(serviceStop.value ? 'Start' : 'Stop', () {
|
||||
() async {
|
||||
serviceBtnEnabled.value = false;
|
||||
await start_service(serviceStop.value);
|
||||
// enable the button after 1 second
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
serviceBtnEnabled.value = true;
|
||||
});
|
||||
}();
|
||||
}, enabled: serviceBtnEnabled.value)
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
Widget other() {
|
||||
|
|
@ -1100,8 +1109,9 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
|||
if (value ==
|
||||
passwordValues[passwordKeys
|
||||
.indexOf(kUsePermanentPassword)] &&
|
||||
(await bind.mainGetPermanentPassword())
|
||||
.isEmpty) {
|
||||
(await bind.mainGetCommon(
|
||||
key: "permanent-password-set")) !=
|
||||
"true") {
|
||||
if (isChangePermanentPasswordDisabled()) {
|
||||
await callback();
|
||||
return;
|
||||
|
|
@ -2026,28 +2036,65 @@ class _AccountState extends State<_Account> {
|
|||
}
|
||||
|
||||
Widget useInfo() {
|
||||
text(String key, String value) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SelectionArea(child: Text('${translate(key)}: $value'))
|
||||
.marginSymmetric(vertical: 4),
|
||||
);
|
||||
}
|
||||
|
||||
return Obx(() => Offstage(
|
||||
offstage: gFFI.userModel.userName.value.isEmpty,
|
||||
child: Column(
|
||||
children: [
|
||||
if (gFFI.userModel.displayName.value.trim().isNotEmpty &&
|
||||
gFFI.userModel.displayName.value.trim() !=
|
||||
gFFI.userModel.userName.value.trim())
|
||||
text('Display Name', gFFI.userModel.displayName.value.trim()),
|
||||
text('Username', gFFI.userModel.userName.value),
|
||||
// text('Group', gFFI.groupModel.groupName.value),
|
||||
],
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Builder(builder: (context) {
|
||||
final avatarWidget = _buildUserAvatar();
|
||||
return Row(
|
||||
children: [
|
||||
if (avatarWidget != null) avatarWidget,
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
gFFI.userModel.displayNameOrUserName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
SelectionArea(
|
||||
child: Text(
|
||||
'@${gFFI.userModel.userName.value}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color:
|
||||
Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
)).marginOnly(left: 18, top: 16);
|
||||
}
|
||||
|
||||
Widget? _buildUserAvatar() {
|
||||
// Resolve relative avatar path at display time
|
||||
final avatar =
|
||||
bind.mainResolveAvatarUrl(avatar: gFFI.userModel.avatar.value);
|
||||
return buildAvatarWidget(
|
||||
avatar: avatar,
|
||||
size: 44,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Checkbox extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -462,23 +462,7 @@ class _CmHeaderState extends State<_CmHeader>
|
|||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 70,
|
||||
height: 70,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: str2color(client.name),
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
child: Text(
|
||||
client.name[0],
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontSize: 55,
|
||||
),
|
||||
),
|
||||
).marginOnly(right: 10.0),
|
||||
_buildClientAvatar().marginOnly(right: 10.0),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
|
@ -582,6 +566,36 @@ class _CmHeaderState extends State<_CmHeader>
|
|||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
Widget _buildClientAvatar() {
|
||||
return buildAvatarWidget(
|
||||
avatar: client.avatar,
|
||||
size: 70,
|
||||
borderRadius: 15,
|
||||
fallback: _buildInitialAvatar(),
|
||||
) ??
|
||||
_buildInitialAvatar();
|
||||
}
|
||||
|
||||
Widget _buildInitialAvatar() {
|
||||
return Container(
|
||||
width: 70,
|
||||
height: 70,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: str2color(client.name),
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
child: Text(
|
||||
client.name.isNotEmpty ? client.name[0] : '?',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontSize: 55,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PrivilegeBoard extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
|
@ -65,9 +64,7 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
bool _showGestureHelp = false;
|
||||
String _value = '';
|
||||
Orientation? _currentOrientation;
|
||||
double _viewInsetsBottom = 0;
|
||||
final _uniqueKey = UniqueKey();
|
||||
Timer? _timerDidChangeMetrics;
|
||||
Timer? _iosKeyboardWorkaroundTimer;
|
||||
|
||||
final _blockableOverlayState = BlockableOverlayState();
|
||||
|
|
@ -140,7 +137,6 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
_physicalFocusNode.dispose();
|
||||
await gFFI.close();
|
||||
_timer?.cancel();
|
||||
_timerDidChangeMetrics?.cancel();
|
||||
_iosKeyboardWorkaroundTimer?.cancel();
|
||||
gFFI.dialogManager.dismissAll();
|
||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
|
|
@ -167,26 +163,6 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
gFFI.invokeMethod("try_sync_clipboard");
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
// If the soft keyboard is visible and the canvas has been changed(panned or scaled)
|
||||
// Don't try reset the view style and focus the cursor.
|
||||
if (gFFI.cursorModel.lastKeyboardIsVisible &&
|
||||
gFFI.canvasModel.isMobileCanvasChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
final newBottom = MediaQueryData.fromView(ui.window).viewInsets.bottom;
|
||||
_timerDidChangeMetrics?.cancel();
|
||||
_timerDidChangeMetrics = Timer(Duration(milliseconds: 100), () async {
|
||||
// We need this comparation because poping up the floating action will also trigger `didChangeMetrics()`.
|
||||
if (newBottom != _viewInsetsBottom) {
|
||||
gFFI.canvasModel.mobileFocusCanvasCursor();
|
||||
_viewInsetsBottom = newBottom;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// to-do: It should be better to use transparent color instead of the bgColor.
|
||||
// But for now, the transparent color will cause the canvas to be white.
|
||||
// I'm sure that the white color is caused by the Overlay widget in BlockableOverlay.
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ class _DropDownAction extends StatelessWidget {
|
|||
}
|
||||
|
||||
if (value == kUsePermanentPassword &&
|
||||
(await bind.mainGetPermanentPassword()).isEmpty) {
|
||||
(await bind.mainGetCommon(key: "permanent-password-set")) !=
|
||||
"true") {
|
||||
if (isChangePermanentPasswordDisabled()) {
|
||||
callback();
|
||||
return;
|
||||
|
|
@ -582,10 +583,13 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
|||
Widget build(BuildContext context) {
|
||||
final serverModel = Provider.of<ServerModel>(context);
|
||||
final hasAudioPermission = androidVersion >= 30;
|
||||
final hideStopService =
|
||||
isAndroid &&
|
||||
bind.mainGetBuildinOption(key: kOptionHideStopService) == 'Y';
|
||||
return PaddingCard(
|
||||
title: translate("Permissions"),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
serverModel.mediaOk
|
||||
serverModel.mediaOk && !hideStopService
|
||||
? ElevatedButton.icon(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
|
|
@ -595,14 +599,15 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
|||
label: Text(translate("Stop service")))
|
||||
.marginOnly(bottom: 8)
|
||||
: SizedBox.shrink(),
|
||||
PermissionRow(
|
||||
translate("Screen Capture"),
|
||||
serverModel.mediaOk,
|
||||
!serverModel.mediaOk &&
|
||||
gFFI.userModel.userName.value.isEmpty &&
|
||||
bind.mainGetLocalOption(key: "show-scam-warning") != "N"
|
||||
? () => showScamWarning(context, serverModel)
|
||||
: serverModel.toggleService),
|
||||
if (!hideStopService || !serverModel.mediaOk)
|
||||
PermissionRow(
|
||||
translate("Screen Capture"),
|
||||
serverModel.mediaOk,
|
||||
!serverModel.mediaOk &&
|
||||
gFFI.userModel.userName.value.isEmpty &&
|
||||
bind.mainGetLocalOption(key: "show-scam-warning") != "N"
|
||||
? () => showScamWarning(context, serverModel)
|
||||
: serverModel.toggleService),
|
||||
PermissionRow(translate("Input Control"), serverModel.inputOk,
|
||||
serverModel.toggleInput),
|
||||
PermissionRow(translate("Transfer file"), serverModel.fileOk,
|
||||
|
|
@ -841,13 +846,7 @@ class ClientInfo extends StatelessWidget {
|
|||
flex: -1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: str2color(
|
||||
client.name,
|
||||
Theme.of(context).brightness == Brightness.light
|
||||
? 255
|
||||
: 150),
|
||||
child: Text(client.name[0])))),
|
||||
child: _buildAvatar(context))),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -860,6 +859,20 @@ class ClientInfo extends StatelessWidget {
|
|||
),
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildAvatar(BuildContext context) {
|
||||
final fallback = CircleAvatar(
|
||||
backgroundColor: str2color(client.name,
|
||||
Theme.of(context).brightness == Brightness.light ? 255 : 150),
|
||||
child: Text(client.name.isNotEmpty ? client.name[0] : '?'),
|
||||
);
|
||||
return buildAvatarWidget(
|
||||
avatar: client.avatar,
|
||||
size: 40,
|
||||
fallback: fallback,
|
||||
) ??
|
||||
fallback;
|
||||
}
|
||||
}
|
||||
|
||||
void androidChannelInit() {
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||
onToggle: (bool v) async {
|
||||
await mainSetLocalBoolOption(kOptionEnableShowTerminalExtraKeys, v);
|
||||
final newValue =
|
||||
mainGetLocalBoolOptionSync(kOptionEnableShowTerminalExtraKeys);
|
||||
mainGetLocalBoolOptionSync(kOptionEnableShowTerminalExtraKeys);
|
||||
setState(() {
|
||||
_showTerminalExtraKeys = newValue;
|
||||
});
|
||||
|
|
@ -689,7 +689,17 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||
title: Obx(() => Text(gFFI.userModel.userName.value.isEmpty
|
||||
? translate('Login')
|
||||
: '${translate('Logout')} (${gFFI.userModel.accountLabelWithHandle})')),
|
||||
leading: Icon(Icons.person),
|
||||
leading: Obx(() {
|
||||
final avatar = bind.mainResolveAvatarUrl(
|
||||
avatar: gFFI.userModel.avatar.value);
|
||||
return buildAvatarWidget(
|
||||
avatar: avatar,
|
||||
size: 28,
|
||||
borderRadius: null,
|
||||
fallback: Icon(Icons.person),
|
||||
) ??
|
||||
Icon(Icons.person);
|
||||
}),
|
||||
onPressed: (context) {
|
||||
if (gFFI.userModel.userName.value.isEmpty) {
|
||||
loginDialog();
|
||||
|
|
@ -829,10 +839,12 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||
),
|
||||
if (!incomingOnly)
|
||||
SettingsTile.switchTile(
|
||||
title: Text(translate('keep-awake-during-outgoing-sessions-label')),
|
||||
title:
|
||||
Text(translate('keep-awake-during-outgoing-sessions-label')),
|
||||
initialValue: _preventSleepWhileConnected,
|
||||
onToggle: (v) async {
|
||||
await mainSetLocalBoolOption(kOptionKeepAwakeDuringOutgoingSessions, v);
|
||||
await mainSetLocalBoolOption(
|
||||
kOptionKeepAwakeDuringOutgoingSessions, v);
|
||||
setState(() {
|
||||
_preventSleepWhileConnected = v;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,100 +12,6 @@ void _showSuccess() {
|
|||
showToast(translate("Successful"));
|
||||
}
|
||||
|
||||
void _showError() {
|
||||
showToast(translate("Error"));
|
||||
}
|
||||
|
||||
void setPermanentPasswordDialog(OverlayDialogManager dialogManager) async {
|
||||
final pw = await bind.mainGetPermanentPassword();
|
||||
final p0 = TextEditingController(text: pw);
|
||||
final p1 = TextEditingController(text: pw);
|
||||
var validateLength = false;
|
||||
var validateSame = false;
|
||||
dialogManager.show((setState, close, context) {
|
||||
submit() async {
|
||||
close();
|
||||
dialogManager.showLoading(translate("Waiting"));
|
||||
if (await gFFI.serverModel.setPermanentPassword(p0.text)) {
|
||||
dialogManager.dismissAll();
|
||||
_showSuccess();
|
||||
} else {
|
||||
dialogManager.dismissAll();
|
||||
_showError();
|
||||
}
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.password_rounded, color: MyTheme.accent),
|
||||
Text(translate('Set your own password')).paddingOnly(left: 10),
|
||||
],
|
||||
),
|
||||
content: Form(
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
TextFormField(
|
||||
autofocus: true,
|
||||
obscureText: true,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
decoration: InputDecoration(
|
||||
labelText: translate('Password'),
|
||||
),
|
||||
controller: p0,
|
||||
validator: (v) {
|
||||
if (v == null) return null;
|
||||
final val = v.trim().length > 5;
|
||||
if (validateLength != val) {
|
||||
// use delay to make setState success
|
||||
Future.delayed(Duration(microseconds: 1),
|
||||
() => setState(() => validateLength = val));
|
||||
}
|
||||
return val
|
||||
? null
|
||||
: translate('Too short, at least 6 characters.');
|
||||
},
|
||||
).workaroundFreezeLinuxMint(),
|
||||
TextFormField(
|
||||
obscureText: true,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
decoration: InputDecoration(
|
||||
labelText: translate('Confirmation'),
|
||||
),
|
||||
controller: p1,
|
||||
validator: (v) {
|
||||
if (v == null) return null;
|
||||
final val = p0.text == v;
|
||||
if (validateSame != val) {
|
||||
Future.delayed(Duration(microseconds: 1),
|
||||
() => setState(() => validateSame = val));
|
||||
}
|
||||
return val
|
||||
? null
|
||||
: translate('The confirmation is not identical.');
|
||||
},
|
||||
).workaroundFreezeLinuxMint(),
|
||||
])),
|
||||
onCancel: close,
|
||||
onSubmit: (validateLength && validateSame) ? submit : null,
|
||||
actions: [
|
||||
dialogButton(
|
||||
'Cancel',
|
||||
icon: Icon(Icons.close_rounded),
|
||||
onPressed: close,
|
||||
isOutline: true,
|
||||
),
|
||||
dialogButton(
|
||||
'OK',
|
||||
icon: Icon(Icons.done_rounded),
|
||||
onPressed: (validateLength && validateSame) ? submit : null,
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void setTemporaryPasswordLengthDialog(
|
||||
OverlayDialogManager dialogManager) async {
|
||||
List<String> lengths = ['6', '8', '10'];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
||||
|
|
@ -53,7 +52,9 @@ class AbModel {
|
|||
|
||||
RxBool get currentAbLoading => current.abLoading;
|
||||
bool get currentAbEmpty => current.peers.isEmpty && current.tags.isEmpty;
|
||||
RxString get currentAbPullError => current.pullError;
|
||||
final _listPullError = ''.obs;
|
||||
RxString get abPullError =>
|
||||
_listPullError.value.isNotEmpty ? _listPullError : current.pullError;
|
||||
RxString get currentAbPushError => current.pushError;
|
||||
String? _personalAbGuid;
|
||||
RxBool legacyMode = false.obs;
|
||||
|
|
@ -68,6 +69,7 @@ class AbModel {
|
|||
var _syncFromRecentLock = false;
|
||||
var _timerCounter = 0;
|
||||
var _cacheLoadOnceFlag = false;
|
||||
var _pulledOnce = false;
|
||||
var listInitialized = false;
|
||||
var _maxPeerOneAb = 0;
|
||||
|
||||
|
|
@ -97,10 +99,17 @@ class AbModel {
|
|||
print("reset ab model");
|
||||
addressbooks.clear();
|
||||
_currentName.value = '';
|
||||
_listPullError.value = '';
|
||||
_pulledOnce = false;
|
||||
await bind.mainClearAb();
|
||||
listInitialized = false;
|
||||
}
|
||||
|
||||
void clearPullErrors() {
|
||||
_listPullError.value = '';
|
||||
current.pullError.value = '';
|
||||
}
|
||||
|
||||
// #region ab
|
||||
/// Pulls the address book data from the server.
|
||||
///
|
||||
|
|
@ -110,31 +119,41 @@ class AbModel {
|
|||
var _pulling = false;
|
||||
Future<void> pullAb(
|
||||
{required ForcePullAb? force, required bool quiet}) async {
|
||||
if (bind.isDisableAb()) return;
|
||||
if (!gFFI.userModel.isLogin) return;
|
||||
if (gFFI.userModel.networkError.isNotEmpty) return;
|
||||
if (_pulling) return;
|
||||
if (force == null && _pulledOnce) {
|
||||
return;
|
||||
}
|
||||
_pulling = true;
|
||||
if (!quiet) {
|
||||
_listPullError.value = '';
|
||||
current.pullError.value = '';
|
||||
}
|
||||
try {
|
||||
await _pullAb(force: force, quiet: quiet);
|
||||
_refreshTab();
|
||||
} catch (_) {}
|
||||
_pulling = false;
|
||||
_pulledOnce = true;
|
||||
}
|
||||
|
||||
Future<void> _pullAb(
|
||||
{required ForcePullAb? force, required bool quiet}) async {
|
||||
if (bind.isDisableAb()) return;
|
||||
if (!gFFI.userModel.isLogin) return;
|
||||
if (gFFI.userModel.networkError.isNotEmpty) return;
|
||||
if (force == null && listInitialized && current.initialized) return;
|
||||
debugPrint("pullAb, force: $force, quiet: $quiet");
|
||||
if (!listInitialized || force == ForcePullAb.listAndCurrent) {
|
||||
try {
|
||||
// Read personal guid every time to avoid upgrading the server without closing the main window
|
||||
_personalAbGuid = null;
|
||||
await _getPersonalAbGuid();
|
||||
// Determine legacy mode based on whether _personalAbGuid is null
|
||||
// `true`: continue init. `false`: stop, error already recorded.
|
||||
if (!await _getPersonalAbGuid(quiet: quiet)) {
|
||||
return;
|
||||
}
|
||||
legacyMode.value = _personalAbGuid == null;
|
||||
if (!legacyMode.value && _maxPeerOneAb == 0) {
|
||||
await _getAbSettings();
|
||||
await _getAbSettings(quiet: quiet);
|
||||
}
|
||||
if (_personalAbGuid != null) {
|
||||
debugPrint("pull ab list");
|
||||
|
|
@ -142,7 +161,7 @@ class AbModel {
|
|||
abProfiles.add(AbProfile(_personalAbGuid!, _personalAddressBookName,
|
||||
gFFI.userModel.userName.value, null, ShareRule.read.value, null));
|
||||
// get all address book name
|
||||
await _getSharedAbProfiles(abProfiles);
|
||||
await _getSharedAbProfiles(abProfiles, quiet: quiet);
|
||||
addressbooks.removeWhere((key, value) =>
|
||||
abProfiles.firstWhereOrNull((e) => e.name == key) == null);
|
||||
for (int i = 0; i < abProfiles.length; i++) {
|
||||
|
|
@ -182,6 +201,7 @@ class AbModel {
|
|||
}
|
||||
} catch (e) {
|
||||
debugPrint("pull ab list error: $e");
|
||||
_setListPullError(e, quiet: quiet);
|
||||
}
|
||||
} else if (listInitialized &&
|
||||
(!current.initialized || force == ForcePullAb.current)) {
|
||||
|
|
@ -197,14 +217,26 @@ class AbModel {
|
|||
}
|
||||
}
|
||||
|
||||
Future<bool> _getAbSettings() async {
|
||||
void _setListPullError(Object err, {required bool quiet, int? statusCode}) {
|
||||
if (!quiet) {
|
||||
_listPullError.value =
|
||||
'${translate('pull_ab_failed_tip')}: ${translate(err.toString())}';
|
||||
}
|
||||
if (statusCode == 401) {
|
||||
gFFI.userModel.reset(resetOther: true);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _getAbSettings({required bool quiet}) async {
|
||||
int? statusCode;
|
||||
try {
|
||||
final api = "${await bind.mainGetApiServer()}/api/ab/settings";
|
||||
var headers = getHttpHeaders();
|
||||
headers['Content-Type'] = "application/json";
|
||||
_setEmptyBody(headers);
|
||||
final resp = await http.post(Uri.parse(api), headers: headers);
|
||||
if (resp.statusCode == 404) {
|
||||
statusCode = resp.statusCode;
|
||||
if (statusCode == 404) {
|
||||
debugPrint("HTTP 404, api server doesn't support shared address book");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -213,46 +245,57 @@ class AbModel {
|
|||
if (json.containsKey('error')) {
|
||||
throw json['error'];
|
||||
}
|
||||
if (resp.statusCode != 200) {
|
||||
throw 'HTTP ${resp.statusCode}';
|
||||
if (statusCode != 200) {
|
||||
throw 'HTTP $statusCode';
|
||||
}
|
||||
_maxPeerOneAb = json['max_peer_one_ab'] ?? 0;
|
||||
return true;
|
||||
} catch (err) {
|
||||
debugPrint('get ab settings err: ${err.toString()}');
|
||||
_setListPullError(err, quiet: quiet, statusCode: statusCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> _getPersonalAbGuid() async {
|
||||
/// Loads `/api/ab/personal`.
|
||||
/// Returns `true` to continue init, `false` to stop after a real error.
|
||||
Future<bool> _getPersonalAbGuid({required bool quiet}) async {
|
||||
int? statusCode;
|
||||
try {
|
||||
final api = "${await bind.mainGetApiServer()}/api/ab/personal";
|
||||
var headers = getHttpHeaders();
|
||||
headers['Content-Type'] = "application/json";
|
||||
_setEmptyBody(headers);
|
||||
final resp = await http.post(Uri.parse(api), headers: headers);
|
||||
if (resp.statusCode == 404) {
|
||||
statusCode = resp.statusCode;
|
||||
if (statusCode == 404) {
|
||||
debugPrint("HTTP 404, current api server is legacy mode");
|
||||
return false;
|
||||
// Old server: keep `_personalAbGuid` null and continue in legacy mode.
|
||||
return true;
|
||||
}
|
||||
Map<String, dynamic> json =
|
||||
_jsonDecodeRespMap(decode_http_response(resp), resp.statusCode);
|
||||
if (json.containsKey('error')) {
|
||||
throw json['error'];
|
||||
}
|
||||
if (resp.statusCode != 200) {
|
||||
throw 'HTTP ${resp.statusCode}';
|
||||
if (statusCode != 200) {
|
||||
throw 'HTTP $statusCode';
|
||||
}
|
||||
_personalAbGuid = json['guid'];
|
||||
// New server: guid is available, continue in non-legacy mode.
|
||||
return true;
|
||||
} catch (err) {
|
||||
debugPrint('get personal ab err: ${err.toString()}');
|
||||
_setListPullError(err, quiet: quiet, statusCode: statusCode);
|
||||
}
|
||||
// Real error: stop the current pull.
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> _getSharedAbProfiles(List<AbProfile> profiles) async {
|
||||
Future<bool> _getSharedAbProfiles(List<AbProfile> profiles,
|
||||
{required bool quiet}) async {
|
||||
final api = "${await bind.mainGetApiServer()}/api/ab/shared/profiles";
|
||||
int? statusCode;
|
||||
try {
|
||||
var uri0 = Uri.parse(api);
|
||||
final pageSize = 100;
|
||||
|
|
@ -273,13 +316,19 @@ class AbModel {
|
|||
headers['Content-Type'] = "application/json";
|
||||
_setEmptyBody(headers);
|
||||
final resp = await http.post(uri, headers: headers);
|
||||
statusCode = resp.statusCode;
|
||||
if (statusCode == 404) {
|
||||
debugPrint(
|
||||
"HTTP 404, api server doesn't support shared address book");
|
||||
return false;
|
||||
}
|
||||
Map<String, dynamic> json =
|
||||
_jsonDecodeRespMap(decode_http_response(resp), resp.statusCode);
|
||||
if (json.containsKey('error')) {
|
||||
throw json['error'];
|
||||
}
|
||||
if (resp.statusCode != 200) {
|
||||
throw 'HTTP ${resp.statusCode}';
|
||||
if (statusCode != 200) {
|
||||
throw 'HTTP $statusCode';
|
||||
}
|
||||
if (json.containsKey('total')) {
|
||||
if (total == 0) total = json['total'];
|
||||
|
|
@ -302,6 +351,7 @@ class AbModel {
|
|||
return true;
|
||||
} catch (err) {
|
||||
debugPrint('_getSharedAbProfiles err: ${err.toString()}');
|
||||
_setListPullError(err, quiet: quiet, statusCode: statusCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,6 +343,7 @@ class GroupModel {
|
|||
}
|
||||
|
||||
reset() async {
|
||||
initialized = false;
|
||||
groupLoadError.value = '';
|
||||
deviceGroups.clear();
|
||||
users.clear();
|
||||
|
|
|
|||
|
|
@ -348,6 +348,12 @@ class InputModel {
|
|||
final _trackpadAdjustPeerLinux = 0.06;
|
||||
// This is an experience value.
|
||||
final _trackpadAdjustMacToWin = 2.50;
|
||||
// Ignore directional locking for very small deltas on both axes (including
|
||||
// tiny single-axis movement) to avoid over-filtering near zero.
|
||||
static const double _trackpadAxisNoiseThreshold = 0.2;
|
||||
// Lock to dominant axis only when one axis is clearly stronger.
|
||||
// 1.6 means the dominant axis must be >= 60% larger than the other.
|
||||
static const double _trackpadAxisLockRatio = 1.6;
|
||||
int _trackpadSpeed = kDefaultTrackpadSpeed;
|
||||
double _trackpadSpeedInner = kDefaultTrackpadSpeed / 100.0;
|
||||
var _trackpadScrollUnsent = Offset.zero;
|
||||
|
|
@ -1172,6 +1178,7 @@ class InputModel {
|
|||
if (isMacOS && peerPlatform == kPeerPlatformWindows) {
|
||||
delta *= _trackpadAdjustMacToWin;
|
||||
}
|
||||
delta = _filterTrackpadDeltaAxis(delta);
|
||||
_trackpadLastDelta = delta;
|
||||
|
||||
var x = delta.dx.toInt();
|
||||
|
|
@ -1204,6 +1211,24 @@ class InputModel {
|
|||
}
|
||||
}
|
||||
|
||||
Offset _filterTrackpadDeltaAxis(Offset delta) {
|
||||
final absDx = delta.dx.abs();
|
||||
final absDy = delta.dy.abs();
|
||||
// Keep diagonal intent when movement is tiny on both axes.
|
||||
if (absDx < _trackpadAxisNoiseThreshold &&
|
||||
absDy < _trackpadAxisNoiseThreshold) {
|
||||
return delta;
|
||||
}
|
||||
// Dominant-axis lock to reduce accidental cross-axis scrolling noise.
|
||||
if (absDy >= absDx * _trackpadAxisLockRatio) {
|
||||
return Offset(0, delta.dy);
|
||||
}
|
||||
if (absDx >= absDy * _trackpadAxisLockRatio) {
|
||||
return Offset(delta.dx, 0);
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
void _scheduleFling(double x, double y, int delay) {
|
||||
if (isViewCamera) return;
|
||||
if ((x == 0 && y == 0) || _stopFling) {
|
||||
|
|
|
|||
|
|
@ -1016,19 +1016,31 @@ class FfiModel with ChangeNotifier {
|
|||
showMsgBox(SessionID sessionId, String type, String title, String text,
|
||||
String link, bool hasRetry, OverlayDialogManager dialogManager,
|
||||
{bool? hasCancel}) async {
|
||||
final showNoteEdit = parent.target != null &&
|
||||
final noteAllowed = parent.target != null &&
|
||||
allowAskForNoteAtEndOfConnection(parent.target, false) &&
|
||||
(title == "Connection Error" || type == "restarting") &&
|
||||
!hasRetry;
|
||||
(title == "Connection Error" || type == "restarting");
|
||||
final showNoteEdit = noteAllowed && !hasRetry;
|
||||
if (showNoteEdit) {
|
||||
await showConnEndAuditDialogCloseCanceled(
|
||||
ffi: parent.target!, type: type, title: title, text: text);
|
||||
closeConnection();
|
||||
} else {
|
||||
VoidCallback? onSubmit;
|
||||
if (noteAllowed && hasRetry) {
|
||||
final ffi = parent.target!;
|
||||
onSubmit = () async {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
await showConnEndAuditDialogCloseCanceled(
|
||||
ffi: ffi, type: type, title: title, text: text);
|
||||
closeConnection();
|
||||
};
|
||||
}
|
||||
msgBox(sessionId, type, title, text, link, dialogManager,
|
||||
hasCancel: hasCancel,
|
||||
reconnect: hasRetry ? reconnect : null,
|
||||
reconnectTimeout: hasRetry ? _reconnects : null);
|
||||
reconnectTimeout: hasRetry ? _reconnects : null,
|
||||
onSubmit: onSubmit);
|
||||
}
|
||||
_timer?.cancel();
|
||||
if (hasRetry) {
|
||||
|
|
@ -2152,6 +2164,9 @@ class CanvasModel with ChangeNotifier {
|
|||
ViewStyle _lastViewStyle = ViewStyle.defaultViewStyle();
|
||||
|
||||
Timer? _timerMobileFocusCanvasCursor;
|
||||
Timer? _timerMobileRestoreCanvasOffset;
|
||||
Offset? _offsetBeforeMobileSoftKeyboard;
|
||||
double? _scaleBeforeMobileSoftKeyboard;
|
||||
|
||||
// `isMobileCanvasChanged` is used to avoid canvas reset when changing the input method
|
||||
// after showing the soft keyboard.
|
||||
|
|
@ -2639,6 +2654,9 @@ class CanvasModel with ChangeNotifier {
|
|||
_scale = 1.0;
|
||||
_lastViewStyle = ViewStyle.defaultViewStyle();
|
||||
_timerMobileFocusCanvasCursor?.cancel();
|
||||
_timerMobileRestoreCanvasOffset?.cancel();
|
||||
_offsetBeforeMobileSoftKeyboard = null;
|
||||
_scaleBeforeMobileSoftKeyboard = null;
|
||||
}
|
||||
|
||||
updateScrollPercent() {
|
||||
|
|
@ -2667,6 +2685,31 @@ class CanvasModel with ChangeNotifier {
|
|||
});
|
||||
}
|
||||
|
||||
void saveMobileOffsetBeforeSoftKeyboard() {
|
||||
_timerMobileRestoreCanvasOffset?.cancel();
|
||||
_offsetBeforeMobileSoftKeyboard = Offset(_x, _y);
|
||||
_scaleBeforeMobileSoftKeyboard = _scale;
|
||||
}
|
||||
|
||||
void restoreMobileOffsetAfterSoftKeyboard() {
|
||||
_timerMobileRestoreCanvasOffset?.cancel();
|
||||
_timerMobileFocusCanvasCursor?.cancel();
|
||||
final targetOffset = _offsetBeforeMobileSoftKeyboard;
|
||||
final targetScale = _scaleBeforeMobileSoftKeyboard;
|
||||
if (targetOffset == null || targetScale == null) {
|
||||
return;
|
||||
}
|
||||
_timerMobileRestoreCanvasOffset = Timer(Duration(milliseconds: 100), () {
|
||||
updateSize();
|
||||
_x = targetOffset.dx;
|
||||
_y = targetOffset.dy;
|
||||
_scale = targetScale;
|
||||
_offsetBeforeMobileSoftKeyboard = null;
|
||||
_scaleBeforeMobileSoftKeyboard = null;
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
// mobile only
|
||||
// Move the canvas to make the cursor visible(center) on the screen.
|
||||
void _moveToCenterCursor() {
|
||||
|
|
@ -2919,8 +2962,13 @@ class CursorModel with ChangeNotifier {
|
|||
_lastIsBlocked = true;
|
||||
}
|
||||
if (isMobile && _lastKeyboardIsVisible != keyboardIsVisible) {
|
||||
parent.target?.canvasModel.mobileFocusCanvasCursor();
|
||||
parent.target?.canvasModel.isMobileCanvasChanged = false;
|
||||
if (keyboardIsVisible) {
|
||||
parent.target?.canvasModel.saveMobileOffsetBeforeSoftKeyboard();
|
||||
parent.target?.canvasModel.mobileFocusCanvasCursor();
|
||||
parent.target?.canvasModel.isMobileCanvasChanged = false;
|
||||
} else {
|
||||
parent.target?.canvasModel.restoreMobileOffsetAfterSoftKeyboard();
|
||||
}
|
||||
}
|
||||
_lastKeyboardIsVisible = keyboardIsVisible;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -471,17 +471,6 @@ class ServerModel with ChangeNotifier {
|
|||
WakelockManager.disable(_wakelockKey);
|
||||
}
|
||||
|
||||
Future<bool> setPermanentPassword(String newPW) async {
|
||||
await bind.mainSetPermanentPassword(password: newPW);
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
final pw = await bind.mainGetPermanentPassword();
|
||||
if (newPW == pw) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fetchID() async {
|
||||
final id = await bind.mainGetMyId();
|
||||
if (id != _serverId.id) {
|
||||
|
|
@ -820,6 +809,7 @@ class Client {
|
|||
bool isTerminal = false;
|
||||
String portForward = "";
|
||||
String name = "";
|
||||
String avatar = "";
|
||||
String peerId = ""; // peer user's id,show at app
|
||||
bool keyboard = false;
|
||||
bool clipboard = false;
|
||||
|
|
@ -847,6 +837,7 @@ class Client {
|
|||
isTerminal = json['is_terminal'] ?? false;
|
||||
portForward = json['port_forward'];
|
||||
name = json['name'];
|
||||
avatar = json['avatar'] ?? '';
|
||||
peerId = json['peer_id'];
|
||||
keyboard = json['keyboard'];
|
||||
clipboard = json['clipboard'];
|
||||
|
|
@ -870,6 +861,7 @@ class Client {
|
|||
data['is_terminal'] = isTerminal;
|
||||
data['port_forward'] = portForward;
|
||||
data['name'] = name;
|
||||
data['avatar'] = avatar;
|
||||
data['peer_id'] = peerId;
|
||||
data['keyboard'] = keyboard;
|
||||
data['clipboard'] = clipboard;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ bool refreshingUser = false;
|
|||
class UserModel {
|
||||
final RxString userName = ''.obs;
|
||||
final RxString displayName = ''.obs;
|
||||
final RxString avatar = ''.obs;
|
||||
final RxBool isAdmin = false.obs;
|
||||
final RxString networkError = ''.obs;
|
||||
bool get isLogin => userName.isNotEmpty;
|
||||
|
|
@ -33,6 +34,7 @@ class UserModel {
|
|||
}
|
||||
return '$preferred (@$username)';
|
||||
}
|
||||
|
||||
WeakReference<FFI> parent;
|
||||
|
||||
UserModel(this.parent) {
|
||||
|
|
@ -114,6 +116,7 @@ class UserModel {
|
|||
if (userInfo != null) {
|
||||
userName.value = (userInfo['name'] ?? '').toString();
|
||||
displayName.value = (userInfo['display_name'] ?? '').toString();
|
||||
avatar.value = (userInfo['avatar'] ?? '').toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,11 +129,13 @@ class UserModel {
|
|||
}
|
||||
userName.value = '';
|
||||
displayName.value = '';
|
||||
avatar.value = '';
|
||||
}
|
||||
|
||||
_parseAndUpdateUser(UserPayload user) {
|
||||
userName.value = user.name;
|
||||
displayName.value = user.displayName;
|
||||
avatar.value = user.avatar;
|
||||
isAdmin.value = user.isAdmin;
|
||||
bind.mainSetLocalOption(key: 'user_info', value: jsonEncode(user));
|
||||
if (isWeb) {
|
||||
|
|
|
|||
|
|
@ -1159,10 +1159,6 @@ class RustdeskImpl {
|
|||
return Future.value('');
|
||||
}
|
||||
|
||||
Future<String> mainGetPermanentPassword({dynamic hint}) {
|
||||
return Future.value('');
|
||||
}
|
||||
|
||||
Future<String> mainGetFingerprint({dynamic hint}) {
|
||||
return Future.value('');
|
||||
}
|
||||
|
|
@ -1346,9 +1342,9 @@ class RustdeskImpl {
|
|||
throw UnimplementedError("mainUpdateTemporaryPassword");
|
||||
}
|
||||
|
||||
Future<void> mainSetPermanentPassword(
|
||||
Future<bool> mainSetPermanentPasswordWithResult(
|
||||
{required String password, dynamic hint}) {
|
||||
throw UnimplementedError("mainSetPermanentPassword");
|
||||
throw UnimplementedError("mainSetPermanentPasswordWithResult");
|
||||
}
|
||||
|
||||
Future<bool> mainCheckSuperUserPermission({dynamic hint}) {
|
||||
|
|
@ -2034,5 +2030,9 @@ class RustdeskImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
String mainResolveAvatarUrl({required String avatar, dynamic hint}) {
|
||||
return js.context.callMethod('getByName', ['resolve_avatar_url', avatar])?.toString() ?? avatar;
|
||||
}
|
||||
|
||||
void dispose() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
//!
|
||||
//! For now, we transfer all file names with windows separators, UTF-16 encoded.
|
||||
//! *Need a way to transfer file names with '\' safely*.
|
||||
//! Maybe we can use URL encoded file names and '/' seperators as a new standard, while keep the support to old schemes.
|
||||
//! Maybe we can use URL encoded file names and '/' separators as a new standard, while keep the support to old schemes.
|
||||
//!
|
||||
//! # Note
|
||||
//! - all files on FS should be read only, and mark the owner to be the current user
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ impl KeyboardControllable for Enigo {
|
|||
for pos in 0..mod_len {
|
||||
let rpos = mod_len - 1 - pos;
|
||||
if flag & (0x0001 << rpos) != 0 {
|
||||
self.key_up(modifiers[pos]);
|
||||
self.key_up(modifiers[rpos]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +298,18 @@ impl KeyboardControllable for Enigo {
|
|||
}
|
||||
|
||||
fn key_up(&mut self, key: Key) {
|
||||
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
||||
match key {
|
||||
Key::Layout(c) => {
|
||||
let code = self.get_layoutdependent_keycode(c);
|
||||
if code as u16 != 0xFFFF {
|
||||
let vk = code & 0x00FF;
|
||||
keybd_event(KEYEVENTF_KEYUP, vk, 0);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_key_state(&mut self, key: Key) -> bool {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5e07db7444284006c008b5b1204f0968bc47b1a9
|
||||
Subproject commit 87b11a795964b00deded250657a63626f2c1efa0
|
||||
|
|
@ -151,7 +151,7 @@ fn create_media_codec(name: &str, direction: MediaCodecDirection) -> Option<Medi
|
|||
log::error!("Failed to start decoder: {:?}", e);
|
||||
return None;
|
||||
};
|
||||
log::debug!("Init decoder successed!: {:?}", name);
|
||||
log::debug!("Init decoder succeeded!: {:?}", name);
|
||||
return Some(MediaCodecDecoder {
|
||||
decoder: codec,
|
||||
name: name.to_owned(),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ impl<'a> PixelProvider<'a> {
|
|||
}
|
||||
|
||||
pub trait Recorder {
|
||||
fn capture(&mut self, timeout_ms: u64) -> Result<PixelProvider, Box<dyn Error>>;
|
||||
fn capture(&mut self, timeout_ms: u64) -> Result<PixelProvider<'_>, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub trait BoxCloneCapturable {
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ impl PipeWireRecorder {
|
|||
}
|
||||
|
||||
impl Recorder for PipeWireRecorder {
|
||||
fn capture(&mut self, timeout_ms: u64) -> Result<PixelProvider, Box<dyn Error>> {
|
||||
fn capture(&mut self, timeout_ms: u64) -> Result<PixelProvider<'_>, Box<dyn Error>> {
|
||||
if let Some(sample) = self
|
||||
.appsink
|
||||
.try_pull_sample(gst::ClockTime::from_mseconds(timeout_ms))
|
||||
|
|
|
|||
|
|
@ -29,4 +29,4 @@ TODO
|
|||
|
||||
## X11
|
||||
|
||||
## OSX
|
||||
## macOS
|
||||
|
|
|
|||
82
res/audits.py
Normal file → Executable file
82
res/audits.py
Normal file → Executable file
|
|
@ -43,7 +43,7 @@ def get_connection_type_name(conn_type):
|
|||
"""Convert connection type number to readable name"""
|
||||
type_map = {
|
||||
0: "Remote Desktop",
|
||||
1: "File Transfer",
|
||||
1: "File Transfer",
|
||||
2: "Port Transfer",
|
||||
3: "View Camera",
|
||||
4: "Terminal"
|
||||
|
|
@ -55,7 +55,7 @@ def get_console_type_name(console_type):
|
|||
"""Convert console audit type number to readable name"""
|
||||
type_map = {
|
||||
0: "Group Management",
|
||||
1: "User Management",
|
||||
1: "User Management",
|
||||
2: "Device Management",
|
||||
3: "Address Book Management"
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ def get_console_operation_name(operation_code):
|
|||
operation_map = {
|
||||
0: "User Login",
|
||||
1: "Add Group",
|
||||
2: "Add User",
|
||||
2: "Add User",
|
||||
3: "Add Device",
|
||||
4: "Delete Groups",
|
||||
5: "Disconnect Device",
|
||||
|
|
@ -95,7 +95,7 @@ def get_console_operation_name(operation_code):
|
|||
def get_alarm_type_name(alarm_type):
|
||||
"""Convert alarm type number to readable name"""
|
||||
type_map = {
|
||||
0: "Access attempt outside the IP whiltelist",
|
||||
0: "Access attempt outside the IP whitelist",
|
||||
1: "Over 30 consecutive access attempts",
|
||||
2: "Multiple access attempts within one minute",
|
||||
3: "Over 30 consecutive login attempts",
|
||||
|
|
@ -109,24 +109,24 @@ def enhance_audit_data(data, audit_type):
|
|||
"""Enhance audit data with readable formats"""
|
||||
if not data:
|
||||
return data
|
||||
|
||||
|
||||
enhanced_data = []
|
||||
for item in data:
|
||||
enhanced_item = item.copy()
|
||||
|
||||
|
||||
# Convert timestamps - replace original values
|
||||
if 'created_at' in enhanced_item:
|
||||
enhanced_item['created_at'] = format_timestamp(enhanced_item['created_at'])
|
||||
if 'end_time' in enhanced_item:
|
||||
enhanced_item['end_time'] = format_timestamp(enhanced_item['end_time'])
|
||||
|
||||
|
||||
# Add type-specific enhancements - replace original values
|
||||
if audit_type == 'conn':
|
||||
if 'conn_type' in enhanced_item:
|
||||
enhanced_item['conn_type'] = get_connection_type_name(enhanced_item['conn_type'])
|
||||
else:
|
||||
enhanced_item['conn_type'] = "Not Logged In"
|
||||
|
||||
|
||||
elif audit_type == 'console':
|
||||
if 'typ' in enhanced_item:
|
||||
# Replace typ field with type and convert to readable name
|
||||
|
|
@ -136,14 +136,14 @@ def enhance_audit_data(data, audit_type):
|
|||
# Replace iop field with operation and convert to readable name
|
||||
enhanced_item['operation'] = get_console_operation_name(enhanced_item['iop'])
|
||||
del enhanced_item['iop']
|
||||
|
||||
|
||||
elif audit_type == 'alarm' and 'typ' in enhanced_item:
|
||||
# Replace typ field with type and convert to readable name
|
||||
enhanced_item['type'] = get_alarm_type_name(enhanced_item['typ'])
|
||||
del enhanced_item['typ']
|
||||
|
||||
|
||||
enhanced_data.append(enhanced_item)
|
||||
|
||||
|
||||
return enhanced_data
|
||||
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ def check_response(response):
|
|||
if response.status_code != 200:
|
||||
print(f"Error: HTTP {response.status_code} - {response.text}")
|
||||
exit(1)
|
||||
|
||||
|
||||
try:
|
||||
response_json = response.json()
|
||||
if "error" in response_json:
|
||||
|
|
@ -163,28 +163,28 @@ def check_response(response):
|
|||
return response.text or "Success"
|
||||
|
||||
|
||||
def view_audits_common(url, token, endpoint, filters=None, page_size=None, current=None,
|
||||
def view_audits_common(url, token, endpoint, filters=None, page_size=None, current=None,
|
||||
created_at=None, days_ago=None, non_wildcard_fields=None):
|
||||
"""Common function for viewing audits"""
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
|
||||
# Set default page size and current page
|
||||
if page_size is None:
|
||||
page_size = 10
|
||||
if current is None:
|
||||
current = 1
|
||||
|
||||
|
||||
params = {
|
||||
"pageSize": page_size,
|
||||
"current": current
|
||||
}
|
||||
|
||||
|
||||
# Add filter parameters if provided
|
||||
if filters:
|
||||
for key, value in filters.items():
|
||||
if value is not None:
|
||||
params[key] = value
|
||||
|
||||
|
||||
# Handle time filters
|
||||
if days_ago is not None:
|
||||
# Calculate datetime from days ago
|
||||
|
|
@ -205,10 +205,10 @@ def view_audits_common(url, token, endpoint, filters=None, page_size=None, curre
|
|||
# Apply wildcard patterns for string fields (excluding specific fields)
|
||||
if non_wildcard_fields is None:
|
||||
non_wildcard_fields = set()
|
||||
|
||||
|
||||
# Always exclude these fields from wildcard treatment
|
||||
non_wildcard_fields.update(["created_at", "pageSize", "current"])
|
||||
|
||||
|
||||
string_params = {}
|
||||
for k, v in params.items():
|
||||
if isinstance(v, str) and k not in non_wildcard_fields:
|
||||
|
|
@ -221,10 +221,10 @@ def view_audits_common(url, token, endpoint, filters=None, page_size=None, curre
|
|||
|
||||
response = requests.get(f"{url}/api/audits/{endpoint}", headers=headers, params=string_params)
|
||||
response_json = check_response(response)
|
||||
|
||||
|
||||
# Enhance the data with readable formats
|
||||
data = enhance_audit_data(response_json.get("data", []), endpoint)
|
||||
|
||||
|
||||
return {
|
||||
"data": data,
|
||||
"total": response_json.get("total", 0),
|
||||
|
|
@ -233,7 +233,7 @@ def view_audits_common(url, token, endpoint, filters=None, page_size=None, curre
|
|||
}
|
||||
|
||||
|
||||
def view_conn_audits(url, token, remote=None, conn_type=None,
|
||||
def view_conn_audits(url, token, remote=None, conn_type=None,
|
||||
page_size=None, current=None, created_at=None, days_ago=None):
|
||||
"""View connection audits"""
|
||||
filters = {
|
||||
|
|
@ -241,7 +241,7 @@ def view_conn_audits(url, token, remote=None, conn_type=None,
|
|||
"conn_type": conn_type
|
||||
}
|
||||
non_wildcard_fields = {"conn_type"}
|
||||
|
||||
|
||||
return view_audits_common(
|
||||
url, token, "conn", filters, page_size, current, created_at, days_ago, non_wildcard_fields
|
||||
)
|
||||
|
|
@ -254,7 +254,7 @@ def view_file_audits(url, token, remote=None,
|
|||
"remote": remote
|
||||
}
|
||||
non_wildcard_fields = set()
|
||||
|
||||
|
||||
return view_audits_common(
|
||||
url, token, "file", filters, page_size, current, created_at, days_ago, non_wildcard_fields
|
||||
)
|
||||
|
|
@ -267,7 +267,7 @@ def view_alarm_audits(url, token, device=None,
|
|||
"device": device
|
||||
}
|
||||
non_wildcard_fields = set()
|
||||
|
||||
|
||||
return view_audits_common(
|
||||
url, token, "alarm", filters, page_size, current, created_at, days_ago, non_wildcard_fields
|
||||
)
|
||||
|
|
@ -280,7 +280,7 @@ def view_console_audits(url, token, operator=None,
|
|||
"operator": operator
|
||||
}
|
||||
non_wildcard_fields = set()
|
||||
|
||||
|
||||
return view_audits_common(
|
||||
url, token, "console", filters, page_size, current, created_at, days_ago, non_wildcard_fields
|
||||
)
|
||||
|
|
@ -295,15 +295,15 @@ def main():
|
|||
)
|
||||
parser.add_argument("--url", required=True, help="URL of the API")
|
||||
parser.add_argument("--token", required=True, help="Bearer token for authentication")
|
||||
|
||||
|
||||
# Pagination parameters
|
||||
parser.add_argument("--page-size", type=int, default=10, help="Number of records per page (default: 10)")
|
||||
parser.add_argument("--current", type=int, default=1, help="Current page number (default: 1)")
|
||||
|
||||
|
||||
# Time filtering parameters
|
||||
parser.add_argument("--created-at", help="Filter by creation time in local time (format: 2025-09-16 14:15:57 or 2025-09-16 14:15:57.000)")
|
||||
parser.add_argument("--days-ago", type=int, help="Filter by days ago (e.g., 7 for last 7 days)")
|
||||
|
||||
|
||||
# Audit filters (simplified)
|
||||
parser.add_argument("--remote", help="Remote peer ID filter (for conn/file audits)")
|
||||
parser.add_argument("--device", help="Device ID filter (for alarm audits)")
|
||||
|
|
@ -319,9 +319,9 @@ def main():
|
|||
if args.command == "view-conn":
|
||||
# View connection audits
|
||||
result = view_conn_audits(
|
||||
args.url,
|
||||
args.token,
|
||||
args.remote,
|
||||
args.url,
|
||||
args.token,
|
||||
args.remote,
|
||||
args.conn_type,
|
||||
args.page_size,
|
||||
args.current,
|
||||
|
|
@ -329,12 +329,12 @@ def main():
|
|||
args.days_ago
|
||||
)
|
||||
print(json.dumps(result, indent=2))
|
||||
|
||||
|
||||
elif args.command == "view-file":
|
||||
# View file audits
|
||||
result = view_file_audits(
|
||||
args.url,
|
||||
args.token,
|
||||
args.url,
|
||||
args.token,
|
||||
args.remote,
|
||||
args.page_size,
|
||||
args.current,
|
||||
|
|
@ -342,12 +342,12 @@ def main():
|
|||
args.days_ago
|
||||
)
|
||||
print(json.dumps(result, indent=2))
|
||||
|
||||
|
||||
elif args.command == "view-alarm":
|
||||
# View alarm audits
|
||||
result = view_alarm_audits(
|
||||
args.url,
|
||||
args.token,
|
||||
args.url,
|
||||
args.token,
|
||||
args.device,
|
||||
args.page_size,
|
||||
args.current,
|
||||
|
|
@ -355,12 +355,12 @@ def main():
|
|||
args.days_ago
|
||||
)
|
||||
print(json.dumps(result, indent=2))
|
||||
|
||||
|
||||
elif args.command == "view-console":
|
||||
# View console audits
|
||||
result = view_console_audits(
|
||||
args.url,
|
||||
args.token,
|
||||
args.url,
|
||||
args.token,
|
||||
args.operator,
|
||||
args.page_size,
|
||||
args.current,
|
||||
|
|
|
|||
|
|
@ -616,10 +616,10 @@ UINT __stdcall TryStopDeleteService(__in MSIHANDLE hInstall)
|
|||
}
|
||||
|
||||
if (IsServiceRunningW(svcName)) {
|
||||
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is not stoped after 1000 ms.", svcName);
|
||||
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is not stopped after 1000 ms.", svcName);
|
||||
}
|
||||
else {
|
||||
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is stoped.", svcName);
|
||||
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is stopped.", svcName);
|
||||
}
|
||||
|
||||
if (MyDeleteServiceW(svcName)) {
|
||||
|
|
@ -645,7 +645,7 @@ UINT __stdcall TryStopDeleteService(__in MSIHANDLE hInstall)
|
|||
}
|
||||
|
||||
// It's really strange that we need sleep here.
|
||||
// But the upgrading may be stucked at "copying new files" because the file is in using.
|
||||
// But the upgrading may be stuck at "copying new files" because the file is in using.
|
||||
// Steps to reproduce: Install -> stop service in tray --> start service -> upgrade
|
||||
// Sleep(300);
|
||||
|
||||
|
|
@ -758,7 +758,7 @@ UINT __stdcall AddRegSoftwareSASGeneration(__in MSIHANDLE hInstall)
|
|||
}
|
||||
|
||||
// Why RegSetValueExW always return 998?
|
||||
//
|
||||
//
|
||||
result = RegCreateKeyExW(HKEY_LOCAL_MACHINE, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
WcaLog(LOGMSG_STANDARD, "Failed to create or open registry key: %d", result);
|
||||
|
|
@ -874,7 +874,7 @@ void TryCreateStartServiceByShell(LPWSTR svcName, LPWSTR svcBinary, LPWSTR szSvc
|
|||
i = 0;
|
||||
j = 0;
|
||||
// svcBinary is a string with double quotes, we need to escape it for shell arguments.
|
||||
// It is orignal used for `CreateServiceW`.
|
||||
// It is original used for `CreateServiceW`.
|
||||
// eg. "C:\Program Files\MyApp\MyApp.exe" --service -> \"C:\Program Files\MyApp\MyApp.exe\" --service
|
||||
while (true) {
|
||||
if (svcBinary[j] == L'"') {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use crate::{
|
|||
create_symmetric_key_msg, decode_id_pk, get_rs_pk, is_keyboard_mode_supported,
|
||||
kcp_stream::KcpStream,
|
||||
secure_tcp,
|
||||
ui_interface::{get_builtin_option, use_texture_render},
|
||||
ui_interface::{get_builtin_option, resolve_avatar_url, use_texture_render},
|
||||
ui_session_interface::{InvokeUiSession, Session},
|
||||
};
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
|
|
@ -119,10 +119,13 @@ pub const LOGIN_MSG_NO_PASSWORD_ACCESS: &str = "No Password Access";
|
|||
pub const LOGIN_MSG_OFFLINE: &str = "Offline";
|
||||
pub const LOGIN_SCREEN_WAYLAND: &str = "Wayland login screen is not supported";
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version.";
|
||||
pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "ubuntu-21-04-required";
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str =
|
||||
"Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.";
|
||||
"wayland-requires-higher-linux-version";
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const SCRAP_XDP_PORTAL_UNAVAILABLE: &str =
|
||||
"xdp-portal-unavailable";
|
||||
pub const SCRAP_X11_REQUIRED: &str = "x11 expected";
|
||||
pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
|
||||
|
||||
|
|
@ -2625,6 +2628,20 @@ impl LoginConfigHandler {
|
|||
} else {
|
||||
(my_id, self.id.clone())
|
||||
};
|
||||
let mut avatar = get_builtin_option(keys::OPTION_AVATAR);
|
||||
if avatar.is_empty() {
|
||||
avatar = serde_json::from_str::<serde_json::Value>(&LocalConfig::get_option(
|
||||
"user_info",
|
||||
))
|
||||
.ok()
|
||||
.and_then(|x| {
|
||||
x.get("avatar")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|x| x.trim().to_owned())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
}
|
||||
avatar = resolve_avatar_url(avatar);
|
||||
let mut display_name = get_builtin_option(keys::OPTION_DISPLAY_NAME);
|
||||
if display_name.is_empty() {
|
||||
display_name =
|
||||
|
|
@ -2684,6 +2701,7 @@ impl LoginConfigHandler {
|
|||
})
|
||||
.into(),
|
||||
hwid,
|
||||
avatar,
|
||||
..Default::default()
|
||||
};
|
||||
match self.conn_type {
|
||||
|
|
@ -3852,6 +3870,7 @@ pub fn check_if_retry(msgtype: &str, title: &str, text: &str, retry_for_relay: b
|
|||
&& !text.to_lowercase().contains("resolve")
|
||||
&& !text.to_lowercase().contains("mismatch")
|
||||
&& !text.to_lowercase().contains("manually")
|
||||
&& !text.to_lowercase().contains("restricted")
|
||||
&& !text.to_lowercase().contains("not allowed")))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -586,7 +586,6 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
file_num,
|
||||
include_hidden,
|
||||
is_remote,
|
||||
Vec::new(),
|
||||
od,
|
||||
));
|
||||
allow_err!(
|
||||
|
|
@ -659,7 +658,6 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
file_num,
|
||||
include_hidden,
|
||||
is_remote,
|
||||
Vec::new(),
|
||||
od,
|
||||
);
|
||||
job.is_last_job = true;
|
||||
|
|
@ -845,19 +843,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
}
|
||||
}
|
||||
Data::CancelJob(id) => {
|
||||
let mut msg_out = Message::new();
|
||||
let mut file_action = FileAction::new();
|
||||
file_action.set_cancel(FileTransferCancel {
|
||||
id: id,
|
||||
..Default::default()
|
||||
});
|
||||
msg_out.set_file_action(file_action);
|
||||
allow_err!(peer.send(&msg_out).await);
|
||||
if let Some(job) = fs::remove_job(id, &mut self.write_jobs) {
|
||||
job.remove_download_file();
|
||||
}
|
||||
let _ = fs::remove_job(id, &mut self.read_jobs);
|
||||
self.remove_jobs.remove(&id);
|
||||
self.cancel_transfer_job(id, peer).await;
|
||||
}
|
||||
Data::RemoveDir((id, path)) => {
|
||||
let mut msg_out = Message::new();
|
||||
|
|
@ -1053,6 +1039,22 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
}
|
||||
}
|
||||
|
||||
async fn cancel_transfer_job(&mut self, id: i32, peer: &mut Stream) {
|
||||
let mut msg_out = Message::new();
|
||||
let mut file_action = FileAction::new();
|
||||
file_action.set_cancel(FileTransferCancel {
|
||||
id,
|
||||
..Default::default()
|
||||
});
|
||||
msg_out.set_file_action(file_action);
|
||||
allow_err!(peer.send(&msg_out).await);
|
||||
if let Some(job) = fs::remove_job(id, &mut self.write_jobs) {
|
||||
job.remove_download_file();
|
||||
}
|
||||
let _ = fs::remove_job(id, &mut self.read_jobs);
|
||||
self.remove_jobs.remove(&id);
|
||||
}
|
||||
|
||||
pub async fn sync_jobs_status_to_local(&mut self) -> bool {
|
||||
if !self.is_connected {
|
||||
return false;
|
||||
|
|
@ -1470,14 +1472,43 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
fs::transform_windows_path(&mut entries);
|
||||
}
|
||||
}
|
||||
self.handler
|
||||
.update_folder_files(fd.id, &entries, fd.path, false, false);
|
||||
// We cannot call cancel_transfer_job/handle_job_status while holding
|
||||
// a mutable borrow from fs::get_job(&mut self.write_jobs), so defer
|
||||
// the error handling until after the borrow scope ends.
|
||||
let mut set_files_err = None;
|
||||
if let Some(job) = fs::get_job(fd.id, &mut self.write_jobs) {
|
||||
log::info!("job set_files: {:?}", entries);
|
||||
job.set_files(entries);
|
||||
job.set_finished_size_on_resume();
|
||||
if let Err(err) = job.set_files(entries) {
|
||||
set_files_err = Some(err.to_string());
|
||||
} else {
|
||||
job.set_finished_size_on_resume();
|
||||
self.handler.update_folder_files(
|
||||
fd.id,
|
||||
job.files(),
|
||||
fd.path,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
}
|
||||
} else if let Some(job) = self.remove_jobs.get_mut(&fd.id) {
|
||||
// Intentionally keep raw entries here:
|
||||
// - remote remove flow executes deletions on peer side;
|
||||
// - local remove flow is populated from local get_recursive_files().
|
||||
job.files = entries;
|
||||
self.handler
|
||||
.update_folder_files(fd.id, &job.files, fd.path, false, false);
|
||||
} else {
|
||||
self.handler
|
||||
.update_folder_files(fd.id, &entries, fd.path, false, false);
|
||||
}
|
||||
if let Some(err) = set_files_err {
|
||||
log::warn!(
|
||||
"Rejected unsafe file list from remote peer for job {}: {}",
|
||||
fd.id,
|
||||
err
|
||||
);
|
||||
self.cancel_transfer_job(fd.id, peer).await;
|
||||
self.handle_job_status(fd.id, -1, Some(err));
|
||||
}
|
||||
}
|
||||
Some(file_response::Union::Digest(digest)) => {
|
||||
|
|
|
|||
588
src/common.rs
588
src/common.rs
|
|
@ -39,7 +39,7 @@ use hbb_common::{
|
|||
|
||||
use crate::{
|
||||
hbbs_http::{create_http_client_async, get_url_for_tls},
|
||||
ui_interface::{get_option, is_installed, set_option},
|
||||
ui_interface::{get_api_server as ui_get_api_server, get_option, is_installed, set_option},
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
|
|
@ -1086,6 +1086,7 @@ fn get_api_server_(api: String, custom: String) -> String {
|
|||
|
||||
#[inline]
|
||||
pub fn is_public(url: &str) -> bool {
|
||||
let url = url.to_ascii_lowercase();
|
||||
url.contains("rustdesk.com/") || url.ends_with("rustdesk.com")
|
||||
}
|
||||
|
||||
|
|
@ -1123,22 +1124,286 @@ pub fn get_audit_server(api: String, custom: String, typ: String) -> String {
|
|||
format!("{}/api/audit/{}", url, typ)
|
||||
}
|
||||
|
||||
pub async fn post_request(url: String, body: String, header: &str) -> ResultType<String> {
|
||||
/// Check if we should use raw TCP proxy for API calls.
|
||||
/// Returns true if USE_RAW_TCP_FOR_API builtin option is "Y", WebSocket is off,
|
||||
/// and the target URL belongs to the configured non-public API host.
|
||||
#[inline]
|
||||
fn should_use_raw_tcp_for_api(url: &str) -> bool {
|
||||
get_builtin_option(keys::OPTION_USE_RAW_TCP_FOR_API) == "Y"
|
||||
&& !use_ws()
|
||||
&& is_tcp_proxy_api_target(url)
|
||||
}
|
||||
|
||||
/// Check if we can attempt raw TCP proxy fallback for this target URL.
|
||||
#[inline]
|
||||
fn can_fallback_to_raw_tcp(url: &str) -> bool {
|
||||
!use_ws() && is_tcp_proxy_api_target(url)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn should_use_tcp_proxy_for_api_url(url: &str, api_url: &str) -> bool {
|
||||
if api_url.is_empty() || is_public(api_url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let target_host = url::Url::parse(url)
|
||||
.ok()
|
||||
.and_then(|parsed| parsed.host_str().map(|host| host.to_ascii_lowercase()));
|
||||
let api_host = url::Url::parse(api_url)
|
||||
.ok()
|
||||
.and_then(|parsed| parsed.host_str().map(|host| host.to_ascii_lowercase()));
|
||||
|
||||
matches!((target_host, api_host), (Some(target), Some(api)) if target == api)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_tcp_proxy_api_target(url: &str) -> bool {
|
||||
should_use_tcp_proxy_for_api_url(url, &ui_get_api_server())
|
||||
}
|
||||
|
||||
fn tcp_proxy_log_target(url: &str) -> String {
|
||||
url::Url::parse(url)
|
||||
.ok()
|
||||
.map(|parsed| {
|
||||
let mut redacted = format!("{}://", parsed.scheme());
|
||||
let Some(host) = parsed.host() else {
|
||||
return "<invalid-url>".to_owned();
|
||||
};
|
||||
redacted.push_str(&host.to_string());
|
||||
if let Some(port) = parsed.port() {
|
||||
redacted.push(':');
|
||||
redacted.push_str(&port.to_string());
|
||||
}
|
||||
redacted.push_str(parsed.path());
|
||||
redacted
|
||||
})
|
||||
.unwrap_or_else(|| "<invalid-url>".to_owned())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_tcp_proxy_addr() -> String {
|
||||
check_port(Config::get_rendezvous_server(), RENDEZVOUS_PORT)
|
||||
}
|
||||
|
||||
/// Send an HTTP request via the rendezvous server's TCP proxy using protobuf.
|
||||
/// Connects with `connect_tcp` + `secure_tcp`, sends `HttpProxyRequest`,
|
||||
/// receives `HttpProxyResponse`.
|
||||
///
|
||||
/// The entire operation (connect + handshake + send + receive) is wrapped in
|
||||
/// an overall timeout of `CONNECT_TIMEOUT + READ_TIMEOUT` so that a stall at
|
||||
/// any stage cannot block the caller indefinitely.
|
||||
async fn tcp_proxy_request(
|
||||
method: &str,
|
||||
url: &str,
|
||||
body: &[u8],
|
||||
headers: Vec<HeaderEntry>,
|
||||
) -> ResultType<HttpProxyResponse> {
|
||||
let tcp_addr = get_tcp_proxy_addr();
|
||||
if tcp_addr.is_empty() {
|
||||
bail!("No rendezvous server configured for TCP proxy");
|
||||
}
|
||||
|
||||
let parsed = url::Url::parse(url)?;
|
||||
let path = if let Some(query) = parsed.query() {
|
||||
format!("{}?{}", parsed.path(), query)
|
||||
} else {
|
||||
parsed.path().to_string()
|
||||
};
|
||||
|
||||
log::debug!(
|
||||
"Sending {} {} via TCP proxy to {}",
|
||||
method,
|
||||
parsed.path(),
|
||||
tcp_addr
|
||||
);
|
||||
|
||||
let overall_timeout = CONNECT_TIMEOUT + READ_TIMEOUT;
|
||||
timeout(overall_timeout, async {
|
||||
let mut conn = socket_client::connect_tcp(&*tcp_addr, CONNECT_TIMEOUT).await?;
|
||||
let key = crate::get_key(true).await;
|
||||
secure_tcp_silent(&mut conn, &key).await?;
|
||||
|
||||
let mut req = HttpProxyRequest::new();
|
||||
req.method = method.to_uppercase();
|
||||
req.path = path;
|
||||
req.headers = headers.into();
|
||||
req.body = Bytes::from(body.to_vec());
|
||||
|
||||
let mut msg_out = RendezvousMessage::new();
|
||||
msg_out.set_http_proxy_request(req);
|
||||
conn.send(&msg_out).await?;
|
||||
|
||||
match conn.next().await {
|
||||
Some(Ok(bytes)) => {
|
||||
let msg_in = RendezvousMessage::parse_from_bytes(&bytes)?;
|
||||
match msg_in.union {
|
||||
Some(rendezvous_message::Union::HttpProxyResponse(resp)) => Ok(resp),
|
||||
_ => bail!("Unexpected response from TCP proxy"),
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => bail!("TCP proxy read error: {}", e),
|
||||
None => bail!("TCP proxy connection closed without response"),
|
||||
}
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
/// Build HeaderEntry list from "Key: Value" style header string (used by post_request).
|
||||
/// If the caller supplies a Content-Type header it overrides the default `application/json`.
|
||||
fn parse_simple_header(header: &str) -> Vec<HeaderEntry> {
|
||||
let mut entries = Vec::new();
|
||||
let mut has_content_type = false;
|
||||
if !header.is_empty() {
|
||||
let tmp: Vec<&str> = header.splitn(2, ": ").collect();
|
||||
if tmp.len() == 2 {
|
||||
if tmp[0].eq_ignore_ascii_case("Content-Type") {
|
||||
has_content_type = true;
|
||||
}
|
||||
entries.push(HeaderEntry {
|
||||
name: tmp[0].into(),
|
||||
value: tmp[1].into(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
if !has_content_type {
|
||||
entries.insert(
|
||||
0,
|
||||
HeaderEntry {
|
||||
name: "Content-Type".into(),
|
||||
value: "application/json".into(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
entries
|
||||
}
|
||||
|
||||
/// POST request via TCP proxy.
|
||||
async fn post_request_via_tcp_proxy(url: &str, body: &str, header: &str) -> ResultType<String> {
|
||||
let headers = parse_simple_header(header);
|
||||
let resp = tcp_proxy_request("POST", url, body.as_bytes(), headers).await?;
|
||||
if !resp.error.is_empty() {
|
||||
bail!("TCP proxy error: {}", resp.error);
|
||||
}
|
||||
Ok(String::from_utf8_lossy(&resp.body).to_string())
|
||||
}
|
||||
|
||||
fn http_proxy_response_to_json(resp: HttpProxyResponse) -> ResultType<String> {
|
||||
if !resp.error.is_empty() {
|
||||
bail!("TCP proxy error: {}", resp.error);
|
||||
}
|
||||
|
||||
let mut response_headers = Map::new();
|
||||
for entry in resp.headers.iter() {
|
||||
response_headers.insert(entry.name.to_lowercase(), json!(entry.value));
|
||||
}
|
||||
|
||||
let mut result = Map::new();
|
||||
result.insert("status_code".to_string(), json!(resp.status));
|
||||
result.insert("headers".to_string(), Value::Object(response_headers));
|
||||
result.insert(
|
||||
"body".to_string(),
|
||||
json!(String::from_utf8_lossy(&resp.body)),
|
||||
);
|
||||
|
||||
serde_json::to_string(&result).map_err(|e| anyhow!("Failed to serialize response: {}", e))
|
||||
}
|
||||
|
||||
fn parse_json_header_entries(header: &str) -> ResultType<Vec<HeaderEntry>> {
|
||||
let v: Value = serde_json::from_str(header)?;
|
||||
if let Value::Object(obj) = v {
|
||||
Ok(obj
|
||||
.iter()
|
||||
.map(|(key, value)| HeaderEntry {
|
||||
name: key.clone(),
|
||||
value: value.as_str().unwrap_or_default().into(),
|
||||
..Default::default()
|
||||
})
|
||||
.collect())
|
||||
} else {
|
||||
Err(anyhow!("HTTP header information parsing failed!"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns (status_code, body_text). Separating status so the wrapper can decide on fallback.
|
||||
async fn post_request_http(url: &str, body: &str, header: &str) -> ResultType<(u16, String)> {
|
||||
let proxy_conf = Config::get_socks();
|
||||
let tls_url = get_url_for_tls(&url, &proxy_conf);
|
||||
let tls_url = get_url_for_tls(url, &proxy_conf);
|
||||
let tls_type = get_cached_tls_type(tls_url);
|
||||
let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
||||
let response = post_request_(
|
||||
&url,
|
||||
url,
|
||||
tls_url,
|
||||
body.clone(),
|
||||
body.to_owned(),
|
||||
header,
|
||||
tls_type,
|
||||
danger_accept_invalid_cert,
|
||||
danger_accept_invalid_cert,
|
||||
)
|
||||
.await?;
|
||||
Ok(response.text().await?)
|
||||
let status = response.status().as_u16();
|
||||
let text = response.text().await?;
|
||||
Ok((status, text))
|
||||
}
|
||||
|
||||
/// Try `http_fn` first; on connection failure or 5xx, fall back to `tcp_fn`
|
||||
/// if the URL is eligible. 4xx responses are returned as-is.
|
||||
async fn with_tcp_proxy_fallback<HttpFut, TcpFut>(
|
||||
url: &str,
|
||||
method: &str,
|
||||
http_fn: HttpFut,
|
||||
tcp_fn: TcpFut,
|
||||
) -> ResultType<String>
|
||||
where
|
||||
HttpFut: Future<Output = ResultType<(u16, String)>>,
|
||||
TcpFut: Future<Output = ResultType<String>>,
|
||||
{
|
||||
if should_use_raw_tcp_for_api(url) {
|
||||
return tcp_fn.await;
|
||||
}
|
||||
|
||||
let http_result = http_fn.await;
|
||||
let should_fallback = match &http_result {
|
||||
Err(_) => true,
|
||||
Ok((status, _)) => *status >= 500,
|
||||
};
|
||||
|
||||
if should_fallback && can_fallback_to_raw_tcp(url) {
|
||||
log::warn!(
|
||||
"HTTP {} to {} failed or 5xx (result: {:?}), trying TCP proxy fallback",
|
||||
method,
|
||||
tcp_proxy_log_target(url),
|
||||
http_result
|
||||
.as_ref()
|
||||
.map(|(s, _)| *s)
|
||||
.map_err(|e| e.to_string()),
|
||||
);
|
||||
match tcp_fn.await {
|
||||
Ok(resp) => return Ok(resp),
|
||||
Err(tcp_err) => {
|
||||
log::warn!("TCP proxy fallback also failed: {:?}", tcp_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http_result.map(|(_status, text)| text)
|
||||
}
|
||||
|
||||
/// POST request with raw TCP proxy support.
|
||||
/// - If `USE_RAW_TCP_FOR_API` is "Y" and WS is off, goes directly through TCP proxy.
|
||||
/// - Otherwise tries HTTP first; on connection failure or 5xx status,
|
||||
/// falls back to TCP proxy if WS is off.
|
||||
/// - 4xx responses are returned as-is (server is reachable, business logic error).
|
||||
/// - If fallback also fails, returns the original HTTP result (text or error).
|
||||
pub async fn post_request(url: String, body: String, header: &str) -> ResultType<String> {
|
||||
with_tcp_proxy_fallback(
|
||||
&url,
|
||||
"POST",
|
||||
post_request_http(&url, &body, header),
|
||||
post_request_via_tcp_proxy(&url, &body, header),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
|
|
@ -1246,21 +1511,16 @@ async fn get_http_response_async(
|
|||
tls_type.unwrap_or(TlsType::Rustls),
|
||||
danger_accept_invalid_cert.unwrap_or(false),
|
||||
);
|
||||
let mut http_client = match method {
|
||||
let normalized_method = method.to_ascii_lowercase();
|
||||
let mut http_client = match normalized_method.as_str() {
|
||||
"get" => http_client.get(url),
|
||||
"post" => http_client.post(url),
|
||||
"put" => http_client.put(url),
|
||||
"delete" => http_client.delete(url),
|
||||
_ => return Err(anyhow!("The HTTP request method is not supported!")),
|
||||
};
|
||||
let v = serde_json::from_str(header)?;
|
||||
|
||||
if let Value::Object(obj) = v {
|
||||
for (key, value) in obj.iter() {
|
||||
http_client = http_client.header(key, value.as_str().unwrap_or_default());
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow!("HTTP header information parsing failed!"));
|
||||
for entry in parse_json_header_entries(header)? {
|
||||
http_client = http_client.header(entry.name, entry.value);
|
||||
}
|
||||
|
||||
if tls_type.is_some() && danger_accept_invalid_cert.is_some() {
|
||||
|
|
@ -1340,6 +1600,51 @@ async fn get_http_response_async(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns (status_code, json_string) so the caller can inspect the status
|
||||
/// without re-parsing the serialized JSON.
|
||||
async fn http_request_http(
|
||||
url: &str,
|
||||
method: &str,
|
||||
body: Option<String>,
|
||||
header: &str,
|
||||
) -> ResultType<(u16, String)> {
|
||||
let proxy_conf = Config::get_socks();
|
||||
let tls_url = get_url_for_tls(url, &proxy_conf);
|
||||
let tls_type = get_cached_tls_type(tls_url);
|
||||
let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
||||
let response = get_http_response_async(
|
||||
url,
|
||||
tls_url,
|
||||
method,
|
||||
body,
|
||||
header,
|
||||
tls_type,
|
||||
danger_accept_invalid_cert,
|
||||
danger_accept_invalid_cert,
|
||||
)
|
||||
.await?;
|
||||
// Serialize response headers
|
||||
let mut response_headers = Map::new();
|
||||
for (key, value) in response.headers() {
|
||||
response_headers.insert(key.to_string(), json!(value.to_str().unwrap_or("")));
|
||||
}
|
||||
|
||||
let status_code = response.status().as_u16();
|
||||
let response_body = response.text().await?;
|
||||
|
||||
// Construct the JSON object
|
||||
let mut result = Map::new();
|
||||
result.insert("status_code".to_string(), json!(status_code));
|
||||
result.insert("headers".to_string(), Value::Object(response_headers));
|
||||
result.insert("body".to_string(), json!(response_body));
|
||||
|
||||
// Convert map to JSON string
|
||||
let json_str = serde_json::to_string(&result)
|
||||
.map_err(|e| anyhow!("Failed to serialize response: {}", e))?;
|
||||
Ok((status_code, json_str))
|
||||
}
|
||||
|
||||
/// HTTP request with raw TCP proxy support.
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn http_request_sync(
|
||||
url: String,
|
||||
|
|
@ -1347,44 +1652,28 @@ pub async fn http_request_sync(
|
|||
body: Option<String>,
|
||||
header: String,
|
||||
) -> ResultType<String> {
|
||||
let proxy_conf = Config::get_socks();
|
||||
let tls_url = get_url_for_tls(&url, &proxy_conf);
|
||||
let tls_type = get_cached_tls_type(tls_url);
|
||||
let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
||||
let response = get_http_response_async(
|
||||
with_tcp_proxy_fallback(
|
||||
&url,
|
||||
tls_url,
|
||||
&method,
|
||||
body.clone(),
|
||||
&header,
|
||||
tls_type,
|
||||
danger_accept_invalid_cert,
|
||||
danger_accept_invalid_cert,
|
||||
http_request_http(&url, &method, body.clone(), &header),
|
||||
http_request_via_tcp_proxy(&url, &method, body.as_deref(), &header),
|
||||
)
|
||||
.await?;
|
||||
// Serialize response headers
|
||||
let mut response_headers = serde_json::map::Map::new();
|
||||
for (key, value) in response.headers() {
|
||||
response_headers.insert(
|
||||
key.to_string(),
|
||||
serde_json::json!(value.to_str().unwrap_or("")),
|
||||
);
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
let status_code = response.status().as_u16();
|
||||
let response_body = response.text().await?;
|
||||
/// General HTTP request via TCP proxy. Header is a JSON string (used by http_request_sync).
|
||||
/// Returns a JSON string with status_code, headers, body (same format as http_request_sync).
|
||||
async fn http_request_via_tcp_proxy(
|
||||
url: &str,
|
||||
method: &str,
|
||||
body: Option<&str>,
|
||||
header: &str,
|
||||
) -> ResultType<String> {
|
||||
let headers = parse_json_header_entries(header)?;
|
||||
let body_bytes = body.unwrap_or("").as_bytes();
|
||||
|
||||
// Construct the JSON object
|
||||
let mut result = serde_json::map::Map::new();
|
||||
result.insert("status_code".to_string(), serde_json::json!(status_code));
|
||||
result.insert(
|
||||
"headers".to_string(),
|
||||
serde_json::Value::Object(response_headers),
|
||||
);
|
||||
result.insert("body".to_string(), serde_json::json!(response_body));
|
||||
|
||||
// Convert map to JSON string
|
||||
serde_json::to_string(&result).map_err(|e| anyhow!("Failed to serialize response: {}", e))
|
||||
let resp = tcp_proxy_request(method, url, body_bytes, headers).await?;
|
||||
http_proxy_response_to_json(resp)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1647,7 +1936,7 @@ pub fn check_process(arg: &str, mut same_uid: bool) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
pub async fn secure_tcp(conn: &mut Stream, key: &str) -> ResultType<()> {
|
||||
async fn secure_tcp_impl(conn: &mut Stream, key: &str, log_on_success: bool) -> ResultType<()> {
|
||||
// Skip additional encryption when using WebSocket connections (wss://)
|
||||
// as WebSocket Secure (wss://) already provides transport layer encryption.
|
||||
// This doesn't affect the end-to-end encryption between clients,
|
||||
|
|
@ -1680,7 +1969,9 @@ pub async fn secure_tcp(conn: &mut Stream, key: &str) -> ResultType<()> {
|
|||
});
|
||||
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
|
||||
conn.set_key(key);
|
||||
log::info!("Connection secured");
|
||||
if log_on_success {
|
||||
log::info!("Connection secured");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -1691,6 +1982,14 @@ pub async fn secure_tcp(conn: &mut Stream, key: &str) -> ResultType<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn secure_tcp(conn: &mut Stream, key: &str) -> ResultType<()> {
|
||||
secure_tcp_impl(conn, key, true).await
|
||||
}
|
||||
|
||||
async fn secure_tcp_silent(conn: &mut Stream, key: &str) -> ResultType<()> {
|
||||
secure_tcp_impl(conn, key, false).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_pk(pk: &[u8]) -> Option<[u8; 32]> {
|
||||
if pk.len() == 32 {
|
||||
|
|
@ -2468,11 +2767,13 @@ mod tests {
|
|||
assert!(is_public("https://rustdesk.com/"));
|
||||
assert!(is_public("https://www.rustdesk.com/"));
|
||||
assert!(is_public("https://api.rustdesk.com/v1"));
|
||||
assert!(is_public("https://API.RUSTDESK.COM/v1"));
|
||||
assert!(is_public("https://rustdesk.com/path"));
|
||||
|
||||
// Test URLs ending with "rustdesk.com"
|
||||
assert!(is_public("rustdesk.com"));
|
||||
assert!(is_public("https://rustdesk.com"));
|
||||
assert!(is_public("https://RustDesk.com"));
|
||||
assert!(is_public("http://www.rustdesk.com"));
|
||||
assert!(is_public("https://api.rustdesk.com"));
|
||||
|
||||
|
|
@ -2485,6 +2786,193 @@ mod tests {
|
|||
assert!(!is_public("rustdesk.comhello.com"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_use_tcp_proxy_for_api_url() {
|
||||
assert!(should_use_tcp_proxy_for_api_url(
|
||||
"https://admin.example.com/api/login",
|
||||
"https://admin.example.com"
|
||||
));
|
||||
assert!(should_use_tcp_proxy_for_api_url(
|
||||
"https://admin.example.com:21114/api/login",
|
||||
"https://admin.example.com"
|
||||
));
|
||||
assert!(!should_use_tcp_proxy_for_api_url(
|
||||
"https://api.telegram.org/bot123/sendMessage",
|
||||
"https://admin.example.com"
|
||||
));
|
||||
assert!(!should_use_tcp_proxy_for_api_url(
|
||||
"https://admin.rustdesk.com/api/login",
|
||||
"https://admin.rustdesk.com"
|
||||
));
|
||||
assert!(!should_use_tcp_proxy_for_api_url(
|
||||
"https://admin.example.com/api/login",
|
||||
"not a url"
|
||||
));
|
||||
assert!(!should_use_tcp_proxy_for_api_url(
|
||||
"not a url",
|
||||
"https://admin.example.com"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_tcp_proxy_addr_normalizes_bare_ipv6_host() {
|
||||
struct RestoreCustomRendezvousServer(String);
|
||||
|
||||
impl Drop for RestoreCustomRendezvousServer {
|
||||
fn drop(&mut self) {
|
||||
Config::set_option(
|
||||
keys::OPTION_CUSTOM_RENDEZVOUS_SERVER.to_string(),
|
||||
self.0.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let _restore = RestoreCustomRendezvousServer(Config::get_option(
|
||||
keys::OPTION_CUSTOM_RENDEZVOUS_SERVER,
|
||||
));
|
||||
Config::set_option(
|
||||
keys::OPTION_CUSTOM_RENDEZVOUS_SERVER.to_string(),
|
||||
"1:2".to_string(),
|
||||
);
|
||||
|
||||
assert_eq!(get_tcp_proxy_addr(), format!("[1:2]:{RENDEZVOUS_PORT}"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_http_request_via_tcp_proxy_rejects_invalid_header_json() {
|
||||
let result = http_request_via_tcp_proxy("not a url", "get", None, "{").await;
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_http_request_via_tcp_proxy_rejects_non_object_header_json() {
|
||||
let err = http_request_via_tcp_proxy("not a url", "get", None, "[]")
|
||||
.await
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
assert!(err.contains("HTTP header information parsing failed!"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_json_header_entries_preserves_single_content_type() {
|
||||
let headers = parse_json_header_entries(
|
||||
r#"{"Content-Type":"text/plain","Authorization":"Bearer token"}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
headers
|
||||
.iter()
|
||||
.filter(|entry| entry.name.eq_ignore_ascii_case("Content-Type"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
headers
|
||||
.iter()
|
||||
.find(|entry| entry.name.eq_ignore_ascii_case("Content-Type"))
|
||||
.map(|entry| entry.value.as_str()),
|
||||
Some("text/plain")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_json_header_entries_does_not_add_default_content_type() {
|
||||
let headers = parse_json_header_entries(r#"{"Authorization":"Bearer token"}"#).unwrap();
|
||||
|
||||
assert!(!headers
|
||||
.iter()
|
||||
.any(|entry| entry.name.eq_ignore_ascii_case("Content-Type")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_simple_header_respects_custom_content_type() {
|
||||
let headers = parse_simple_header("Content-Type: text/plain");
|
||||
|
||||
assert_eq!(
|
||||
headers
|
||||
.iter()
|
||||
.filter(|entry| entry.name.eq_ignore_ascii_case("Content-Type"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
headers
|
||||
.iter()
|
||||
.find(|entry| entry.name.eq_ignore_ascii_case("Content-Type"))
|
||||
.map(|entry| entry.value.as_str()),
|
||||
Some("text/plain")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_simple_header_preserves_non_content_type_header() {
|
||||
let headers = parse_simple_header("Authorization: Bearer token");
|
||||
|
||||
assert!(headers.iter().any(|entry| {
|
||||
entry.name.eq_ignore_ascii_case("Authorization")
|
||||
&& entry.value.as_str() == "Bearer token"
|
||||
}));
|
||||
assert_eq!(
|
||||
headers
|
||||
.iter()
|
||||
.filter(|entry| entry.name.eq_ignore_ascii_case("Content-Type"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
headers
|
||||
.iter()
|
||||
.find(|entry| entry.name.eq_ignore_ascii_case("Content-Type"))
|
||||
.map(|entry| entry.value.as_str()),
|
||||
Some("application/json")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tcp_proxy_log_target_redacts_query_only() {
|
||||
assert_eq!(
|
||||
tcp_proxy_log_target("https://example.com/api/heartbeat?token=secret"),
|
||||
"https://example.com/api/heartbeat"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tcp_proxy_log_target_brackets_ipv6_host_with_port() {
|
||||
assert_eq!(
|
||||
tcp_proxy_log_target("https://[2001:db8::1]:21114/api/heartbeat?token=secret"),
|
||||
"https://[2001:db8::1]:21114/api/heartbeat"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_http_proxy_response_to_json() {
|
||||
let mut resp = HttpProxyResponse {
|
||||
status: 200,
|
||||
body: br#"{"ok":true}"#.to_vec().into(),
|
||||
..Default::default()
|
||||
};
|
||||
resp.headers.push(HeaderEntry {
|
||||
name: "Content-Type".into(),
|
||||
value: "application/json".into(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let json = http_proxy_response_to_json(resp).unwrap();
|
||||
let value: Value = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(value["status_code"], 200);
|
||||
assert_eq!(value["headers"]["content-type"], "application/json");
|
||||
assert_eq!(value["body"], r#"{"ok":true}"#);
|
||||
|
||||
let err = http_proxy_response_to_json(HttpProxyResponse {
|
||||
error: "dial failed".into(),
|
||||
..Default::default()
|
||||
})
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
assert!(err.contains("TCP proxy error: dial failed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_event_constants_and_mask_layout() {
|
||||
use super::input::*;
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||
}
|
||||
Ok(false) => "Update failed!".to_string(),
|
||||
Ok(true) => match platform::update_me(false) {
|
||||
Ok(_) => "Update successfully!".to_string(),
|
||||
Ok(_) => "Updated successfully!".to_string(),
|
||||
Err(err) => {
|
||||
log::error!("Failed with error: {err}");
|
||||
"Update failed!".to_string()
|
||||
|
|
@ -335,8 +335,8 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||
log::info!("Starting update process...");
|
||||
let _text = match platform::update_me() {
|
||||
Ok(_) => {
|
||||
println!("{}", translate("Update successfully!".to_string()));
|
||||
log::info!("Update successfully!");
|
||||
println!("{}", translate("Updated successfully!".to_string()));
|
||||
log::info!("Updated successfully!");
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Update failed with error: {}", err);
|
||||
|
|
|
|||
|
|
@ -1101,6 +1101,10 @@ pub fn main_get_api_server() -> String {
|
|||
get_api_server()
|
||||
}
|
||||
|
||||
pub fn main_resolve_avatar_url(avatar: String) -> SyncReturn<String> {
|
||||
SyncReturn(resolve_avatar_url(avatar))
|
||||
}
|
||||
|
||||
pub fn main_http_request(url: String, method: String, body: Option<String>, header: String) {
|
||||
http_request(url, method, body, header)
|
||||
}
|
||||
|
|
@ -1689,8 +1693,8 @@ pub fn main_get_temporary_password() -> String {
|
|||
ui_interface::temporary_password()
|
||||
}
|
||||
|
||||
pub fn main_get_permanent_password() -> String {
|
||||
ui_interface::permanent_password()
|
||||
pub fn main_set_permanent_password_with_result(password: String) -> bool {
|
||||
ui_interface::set_permanent_password_with_result(password)
|
||||
}
|
||||
|
||||
pub fn main_get_fingerprint() -> String {
|
||||
|
|
@ -2068,10 +2072,6 @@ pub fn main_update_temporary_password() {
|
|||
update_temporary_password();
|
||||
}
|
||||
|
||||
pub fn main_set_permanent_password(password: String) {
|
||||
set_permanent_password(password);
|
||||
}
|
||||
|
||||
pub fn main_check_super_user_permission() -> bool {
|
||||
check_super_user_permission()
|
||||
}
|
||||
|
|
@ -2419,16 +2419,23 @@ pub fn is_disable_installation() -> SyncReturn<bool> {
|
|||
}
|
||||
|
||||
pub fn is_preset_password() -> bool {
|
||||
config::HARD_SETTINGS
|
||||
let hard = config::HARD_SETTINGS
|
||||
.read()
|
||||
.unwrap()
|
||||
.get("password")
|
||||
.map_or(false, |p| {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
return p == &crate::ipc::get_permanent_password();
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
return p == &config::Config::get_permanent_password();
|
||||
})
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
if hard.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// On desktop, service owns the authoritative config; query it via IPC and return only a boolean.
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
return crate::ipc::is_permanent_password_preset();
|
||||
|
||||
// On mobile, we have no service IPC; verify against local storage.
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
return config::Config::matches_permanent_password_plain(&hard);
|
||||
}
|
||||
|
||||
// Don't call this function for desktop version.
|
||||
|
|
@ -2764,6 +2771,10 @@ pub fn main_get_common(key: String) -> String {
|
|||
return crate::platform::linux::has_gnome_shortcuts_inhibitor_permission().to_string();
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
return false.to_string();
|
||||
} else if key == "permanent-password-set" {
|
||||
return ui_interface::is_permanent_password_set().to_string();
|
||||
} else if key == "local-permanent-password-set" {
|
||||
return ui_interface::is_local_permanent_password_set().to_string();
|
||||
} else {
|
||||
if key.starts_with("download-data-") {
|
||||
let id = key.replace("download-data-", "");
|
||||
|
|
@ -2873,7 +2884,7 @@ pub fn main_set_common(_key: String, _value: String) {
|
|||
} else if _key == "update-me" {
|
||||
if let Some(new_version_file) = get_download_file_from_url(&_value) {
|
||||
log::debug!(
|
||||
"New version file is downloaed, update begin, {:?}",
|
||||
"New version file is downloaded, update begin, {:?}",
|
||||
new_version_file.to_str()
|
||||
);
|
||||
if let Some(f) = new_version_file.to_str() {
|
||||
|
|
@ -3045,6 +3056,22 @@ pub mod server_side {
|
|||
return env.new_string(res).unwrap_or_default().into_raw();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_ffi_FFI_getBuildinOption(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
key: JString,
|
||||
) -> jstring {
|
||||
let mut env = env;
|
||||
let res = if let Ok(key) = env.get_string(&key) {
|
||||
let key: String = key.into();
|
||||
super::get_builtin_option(&key)
|
||||
} else {
|
||||
"".into()
|
||||
};
|
||||
return env.new_string(res).unwrap_or_default().into_raw();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_ffi_FFI_isServiceClipboardEnabled(
|
||||
env: JNIEnv,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use reqwest::blocking::Response;
|
||||
use hbb_common::ResultType;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
|
@ -21,11 +21,9 @@ pub enum HbbHttpResponse<T> {
|
|||
Data(T),
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> TryFrom<Response> for HbbHttpResponse<T> {
|
||||
type Error = reqwest::Error;
|
||||
|
||||
fn try_from(resp: Response) -> Result<Self, <Self as TryFrom<Response>>::Error> {
|
||||
let map = resp.json::<Map<String, Value>>()?;
|
||||
impl<T: DeserializeOwned> HbbHttpResponse<T> {
|
||||
pub fn parse(body: &str) -> ResultType<Self> {
|
||||
let map = serde_json::from_str::<Map<String, Value>>(body)?;
|
||||
if let Some(error) = map.get("error") {
|
||||
if let Some(err) = error.as_str() {
|
||||
Ok(Self::Error(err.to_owned()))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use super::HbbHttpResponse;
|
||||
use crate::hbbs_http::create_http_client_with_url;
|
||||
use hbb_common::{config::LocalConfig, log, ResultType};
|
||||
use reqwest::blocking::Client;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use std::{
|
||||
|
|
@ -17,6 +16,7 @@ lazy_static::lazy_static! {
|
|||
|
||||
const QUERY_INTERVAL_SECS: f32 = 1.0;
|
||||
const QUERY_TIMEOUT_SECS: u64 = 60 * 3;
|
||||
|
||||
const REQUESTING_ACCOUNT_AUTH: &str = "Requesting account auth";
|
||||
const WAITING_ACCOUNT_AUTH: &str = "Waiting account auth";
|
||||
const LOGIN_ACCOUNT_AUTH: &str = "Login account auth";
|
||||
|
|
@ -82,6 +82,8 @@ pub struct UserPayload {
|
|||
#[serde(default)]
|
||||
pub display_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub avatar: Option<String>,
|
||||
#[serde(default)]
|
||||
pub email: Option<String>,
|
||||
#[serde(default)]
|
||||
pub note: Option<String>,
|
||||
|
|
@ -106,7 +108,7 @@ pub struct AuthBody {
|
|||
}
|
||||
|
||||
pub struct OidcSession {
|
||||
client: Option<Client>,
|
||||
warmed_api_server: Option<String>,
|
||||
state_msg: &'static str,
|
||||
failed_msg: String,
|
||||
code_url: Option<OidcAuthUrl>,
|
||||
|
|
@ -133,7 +135,7 @@ impl Default for UserStatus {
|
|||
impl OidcSession {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
client: None,
|
||||
warmed_api_server: None,
|
||||
state_msg: REQUESTING_ACCOUNT_AUTH,
|
||||
failed_msg: "".to_owned(),
|
||||
code_url: None,
|
||||
|
|
@ -146,12 +148,13 @@ impl OidcSession {
|
|||
|
||||
fn ensure_client(api_server: &str) {
|
||||
let mut write_guard = OIDC_SESSION.write().unwrap();
|
||||
if write_guard.client.is_none() {
|
||||
// This URL is used to detect the appropriate TLS implementation for the server.
|
||||
let login_option_url = format!("{}/api/login-options", &api_server);
|
||||
let client = create_http_client_with_url(&login_option_url);
|
||||
write_guard.client = Some(client);
|
||||
if write_guard.warmed_api_server.as_deref() == Some(api_server) {
|
||||
return;
|
||||
}
|
||||
// This URL is used to detect the appropriate TLS implementation for the server.
|
||||
let login_option_url = format!("{}/api/login-options", api_server);
|
||||
let _ = create_http_client_with_url(&login_option_url);
|
||||
write_guard.warmed_api_server = Some(api_server.to_owned());
|
||||
}
|
||||
|
||||
fn auth(
|
||||
|
|
@ -161,26 +164,15 @@ impl OidcSession {
|
|||
uuid: &str,
|
||||
) -> ResultType<HbbHttpResponse<OidcAuthUrl>> {
|
||||
Self::ensure_client(api_server);
|
||||
let resp = if let Some(client) = &OIDC_SESSION.read().unwrap().client {
|
||||
client
|
||||
.post(format!("{}/api/oidc/auth", api_server))
|
||||
.json(&serde_json::json!({
|
||||
"op": op,
|
||||
"id": id,
|
||||
"uuid": uuid,
|
||||
"deviceInfo": crate::ui_interface::get_login_device_info(),
|
||||
}))
|
||||
.send()?
|
||||
} else {
|
||||
hbb_common::bail!("http client not initialized");
|
||||
};
|
||||
let status = resp.status();
|
||||
match resp.try_into() {
|
||||
Ok(v) => Ok(v),
|
||||
Err(err) => {
|
||||
hbb_common::bail!("Http status: {}, err: {}", status, err);
|
||||
}
|
||||
}
|
||||
let body = serde_json::json!({
|
||||
"op": op,
|
||||
"id": id,
|
||||
"uuid": uuid,
|
||||
"deviceInfo": crate::ui_interface::get_login_device_info(),
|
||||
})
|
||||
.to_string();
|
||||
let resp = crate::post_request_sync(format!("{}/api/oidc/auth", api_server), body, "")?;
|
||||
HbbHttpResponse::parse(&resp)
|
||||
}
|
||||
|
||||
fn query(
|
||||
|
|
@ -194,11 +186,19 @@ impl OidcSession {
|
|||
&[("code", code), ("id", id), ("uuid", uuid)],
|
||||
)?;
|
||||
Self::ensure_client(api_server);
|
||||
if let Some(client) = &OIDC_SESSION.read().unwrap().client {
|
||||
Ok(client.get(url).send()?.try_into()?)
|
||||
} else {
|
||||
hbb_common::bail!("http client not initialized")
|
||||
#[derive(Deserialize)]
|
||||
struct HttpResponseBody {
|
||||
body: String,
|
||||
}
|
||||
|
||||
let resp = crate::http_request_sync(
|
||||
url.to_string(),
|
||||
"GET".to_owned(),
|
||||
None,
|
||||
"{}".to_owned(),
|
||||
)?;
|
||||
let resp = serde_json::from_str::<HttpResponseBody>(&resp)?;
|
||||
HbbHttpResponse::parse(&resp.body)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
|
|
@ -273,6 +273,7 @@ impl OidcSession {
|
|||
serde_json::json!({
|
||||
"name": auth_body.user.name,
|
||||
"display_name": auth_body.user.display_name,
|
||||
"avatar": auth_body.user.avatar,
|
||||
"status": auth_body.user.status
|
||||
})
|
||||
.to_string(),
|
||||
|
|
|
|||
|
|
@ -286,10 +286,14 @@ fn heartbeat_url() -> String {
|
|||
|
||||
fn handle_config_options(config_options: HashMap<String, String>) {
|
||||
let mut options = Config::get_options();
|
||||
let default_settings = config::DEFAULT_SETTINGS.read().unwrap().clone();
|
||||
config_options
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
if v.is_empty() {
|
||||
// Priority: user config > default advanced options.
|
||||
// Only when default advanced options are also empty, remove user option (fallback to built-in default);
|
||||
// otherwise insert an empty value so user config remains present.
|
||||
if v.is_empty() && default_settings.get(k).map_or("", |v| v).is_empty() {
|
||||
options.remove(k);
|
||||
} else {
|
||||
options.insert(k.to_string(), v.to_string());
|
||||
|
|
|
|||
138
src/ipc.rs
138
src/ipc.rs
|
|
@ -226,6 +226,7 @@ pub enum Data {
|
|||
is_terminal: bool,
|
||||
peer_id: String,
|
||||
name: String,
|
||||
avatar: String,
|
||||
authorized: bool,
|
||||
port_forward: String,
|
||||
keyboard: bool,
|
||||
|
|
@ -631,8 +632,29 @@ async fn handle(data: Data, stream: &mut Connection) {
|
|||
value = Some(Config::get_id());
|
||||
} else if name == "temporary-password" {
|
||||
value = Some(password::temporary_password());
|
||||
} else if name == "permanent-password" {
|
||||
value = Some(Config::get_permanent_password());
|
||||
} else if name == "permanent-password-storage-and-salt" {
|
||||
let (storage, salt) = Config::get_local_permanent_password_storage_and_salt();
|
||||
value = Some(storage + "\n" + &salt);
|
||||
} else if name == "permanent-password-set" {
|
||||
value = Some(if Config::has_permanent_password() {
|
||||
"Y".to_owned()
|
||||
} else {
|
||||
"N".to_owned()
|
||||
});
|
||||
} else if name == "permanent-password-is-preset" {
|
||||
let hard = config::HARD_SETTINGS
|
||||
.read()
|
||||
.unwrap()
|
||||
.get("password")
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let is_preset =
|
||||
!hard.is_empty() && Config::matches_permanent_password_plain(&hard);
|
||||
value = Some(if is_preset {
|
||||
"Y".to_owned()
|
||||
} else {
|
||||
"N".to_owned()
|
||||
});
|
||||
} else if name == "salt" {
|
||||
value = Some(Config::get_salt());
|
||||
} else if name == "rendezvous_server" {
|
||||
|
|
@ -668,13 +690,24 @@ async fn handle(data: Data, stream: &mut Connection) {
|
|||
allow_err!(stream.send(&Data::Config((name, value))).await);
|
||||
}
|
||||
Some(value) => {
|
||||
let mut updated = true;
|
||||
if name == "id" {
|
||||
Config::set_key_confirmed(false);
|
||||
Config::set_id(&value);
|
||||
} else if name == "temporary-password" {
|
||||
password::update_temporary_password();
|
||||
} else if name == "permanent-password" {
|
||||
Config::set_permanent_password(&value);
|
||||
if Config::is_disable_change_permanent_password() {
|
||||
log::warn!("Changing permanent password is disabled");
|
||||
updated = false;
|
||||
} else {
|
||||
Config::set_permanent_password(&value);
|
||||
}
|
||||
// Explicitly ACK/NACK permanent-password writes. This allows UIs/FFI to
|
||||
// distinguish "accepted by daemon" vs "IPC send succeeded" without
|
||||
// reading back any secret.
|
||||
let ack = if updated { "Y" } else { "N" }.to_owned();
|
||||
allow_err!(stream.send(&Data::Config((name.clone(), Some(ack)))).await);
|
||||
} else if name == "salt" {
|
||||
Config::set_salt(&value);
|
||||
} else if name == "voice-call-input" {
|
||||
|
|
@ -684,7 +717,9 @@ async fn handle(data: Data, stream: &mut Connection) {
|
|||
} else {
|
||||
return;
|
||||
}
|
||||
log::info!("{} updated", name);
|
||||
if updated {
|
||||
log::info!("{} updated", name);
|
||||
}
|
||||
}
|
||||
},
|
||||
Data::Options(value) => match value {
|
||||
|
|
@ -1142,13 +1177,57 @@ pub fn update_temporary_password() -> ResultType<()> {
|
|||
set_config("temporary-password", "".to_owned())
|
||||
}
|
||||
|
||||
pub fn get_permanent_password() -> String {
|
||||
if let Ok(Some(v)) = get_config("permanent-password") {
|
||||
Config::set_permanent_password(&v);
|
||||
v
|
||||
} else {
|
||||
Config::get_permanent_password()
|
||||
fn apply_permanent_password_storage_and_salt_payload(payload: Option<&str>) -> ResultType<()> {
|
||||
let Some(payload) = payload else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some((storage, salt)) = payload.split_once('\n') else {
|
||||
bail!("Invalid permanent-password-storage-and-salt payload");
|
||||
};
|
||||
|
||||
if storage.is_empty() {
|
||||
Config::set_permanent_password_storage_for_sync("", "")?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Config::set_permanent_password_storage_for_sync(storage, salt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync_permanent_password_storage_from_daemon() -> ResultType<()> {
|
||||
let v = get_config("permanent-password-storage-and-salt")?;
|
||||
apply_permanent_password_storage_and_salt_payload(v.as_deref())
|
||||
}
|
||||
|
||||
async fn sync_permanent_password_storage_from_daemon_async() -> ResultType<()> {
|
||||
let ms_timeout = 1_000;
|
||||
let v = get_config_async("permanent-password-storage-and-salt", ms_timeout).await?;
|
||||
apply_permanent_password_storage_and_salt_payload(v.as_deref())
|
||||
}
|
||||
|
||||
pub fn is_permanent_password_set() -> bool {
|
||||
match get_config("permanent-password-set") {
|
||||
Ok(Some(v)) => {
|
||||
let v = v.trim();
|
||||
return v == "Y";
|
||||
}
|
||||
Ok(None) => {
|
||||
// No response/value (timeout).
|
||||
}
|
||||
Err(_) => {
|
||||
// Connection error.
|
||||
}
|
||||
}
|
||||
log::warn!("Failed to query permanent password state from daemon");
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_permanent_password_preset() -> bool {
|
||||
if let Ok(Some(v)) = get_config("permanent-password-is-preset") {
|
||||
let v = v.trim();
|
||||
return v == "Y";
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn get_fingerprint() -> String {
|
||||
|
|
@ -1158,8 +1237,41 @@ pub fn get_fingerprint() -> String {
|
|||
}
|
||||
|
||||
pub fn set_permanent_password(v: String) -> ResultType<()> {
|
||||
Config::set_permanent_password(&v);
|
||||
set_config("permanent-password", v)
|
||||
if Config::is_disable_change_permanent_password() {
|
||||
bail!("Changing permanent password is disabled");
|
||||
}
|
||||
if set_permanent_password_with_ack(v)? {
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Changing permanent password was rejected by daemon");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn set_permanent_password_with_ack(v: String) -> ResultType<bool> {
|
||||
set_permanent_password_with_ack_async(v).await
|
||||
}
|
||||
|
||||
async fn set_permanent_password_with_ack_async(v: String) -> ResultType<bool> {
|
||||
// The daemon ACK/NACK is expected quickly since it applies the config in-process.
|
||||
let ms_timeout = 1_000;
|
||||
let mut c = connect(ms_timeout, "").await?;
|
||||
c.send_config("permanent-password", v).await?;
|
||||
if let Some(Data::Config((name2, Some(v)))) = c.next_timeout(ms_timeout).await? {
|
||||
if name2 == "permanent-password" {
|
||||
let v = v.trim();
|
||||
let ok = v == "Y";
|
||||
if ok {
|
||||
// Ensure the hashed permanent password storage is written to the user config file.
|
||||
// This sync must not affect the daemon ACK outcome.
|
||||
if let Err(err) = sync_permanent_password_storage_from_daemon_async().await {
|
||||
log::warn!("Failed to sync permanent password storage from daemon: {err}");
|
||||
}
|
||||
}
|
||||
return Ok(ok);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
|
|
@ -1583,6 +1695,6 @@ mod test {
|
|||
#[test]
|
||||
fn verify_ffi_enum_data_size() {
|
||||
println!("{}", std::mem::size_of::<Data>());
|
||||
assert!(std::mem::size_of::<Data>() <= 96);
|
||||
assert!(std::mem::size_of::<Data>() <= 120);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ mod es;
|
|||
mod et;
|
||||
mod eu;
|
||||
mod fa;
|
||||
mod gu;
|
||||
mod fr;
|
||||
mod he;
|
||||
mod hr;
|
||||
|
|
@ -95,6 +96,7 @@ pub const LANGS: &[(&str, &str)] = &[
|
|||
("ta", "தமிழ்"),
|
||||
("ge", "ქართული"),
|
||||
("fi", "Suomi"),
|
||||
("gu", "ગુજરાતી"),
|
||||
];
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
|
|
@ -173,6 +175,7 @@ pub fn translate_locale(name: String, locale: &str) -> String {
|
|||
"sc" => sc::T.deref(),
|
||||
"ta" => ta::T.deref(),
|
||||
"ge" => ge::T.deref(),
|
||||
"gu" => gu::T.deref(),
|
||||
_ => en::T.deref(),
|
||||
};
|
||||
let (name, placeholder_value) = extract_placeholder(&name);
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "اعدادات لوحة المفاتيح"),
|
||||
("Full Access", "وصول كامل"),
|
||||
("Screen Share", "مشاركة الشاشة"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland يتطلب نسخة ابونتو 21.04 او اعلى."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland يتطلب نسخة اعلى من توزيعة لينكس. الرجاء تجربة سطح مكتب X11 او غير نظام تشغيلك."),
|
||||
("ubuntu-21-04-required", "Wayland يتطلب نسخة ابونتو 21.04 او اعلى."),
|
||||
("wayland-requires-higher-linux-version", "Wayland يتطلب نسخة اعلى من توزيعة لينكس. الرجاء تجربة سطح مكتب X11 او غير نظام تشغيلك."),
|
||||
("xdp-portal-unavailable", "لاقط شاشة Wayland فشل. بوابة سطح مكتب XDG ربما توقفت عن العمل او حدث خطأ بها. جرب اعادة تشغليها عن طريق 'systemctl --user restart xdg-desktop-portal'."),
|
||||
("JumpLink", "رابط القفز"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "الرجاء اختيار شاشة لمشاركتها (تعمل على جانب القرين)."),
|
||||
("Show RustDesk", "عرض RustDesk"),
|
||||
|
|
@ -728,17 +729,19 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("server-oss-not-support-tip", "هذه الميزة غير مدعومة من قبل خادمك"),
|
||||
("input note here", "أدخل الملاحظة هنا"),
|
||||
("note-at-conn-end-tip", "سيتم عرض هذه الملاحظة عند نهاية الاتصال"),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Show terminal extra keys", "إظهار مفاتيح إضافية في الطرفية"),
|
||||
("Relative mouse mode", "وضع الماوس النسبي"),
|
||||
("rel-mouse-not-supported-peer-tip", "وضع الماوس النسبي غير مدعوم على الجهاز الآخر"),
|
||||
("rel-mouse-not-ready-tip", "وضع الماوس النسبي غير جاهز"),
|
||||
("rel-mouse-lock-failed-tip", "فشل قفل الماوس النسبي"),
|
||||
("rel-mouse-exit-{}-tip", "للخروج من وضع الماوس النسبي اضغط على {}"),
|
||||
("rel-mouse-permission-lost-tip", "تم فقدان إذن الماوس النسبي"),
|
||||
("Changelog", "سجل التغييرات"),
|
||||
("keep-awake-during-outgoing-sessions-label", "إبقاء الجهاز نشطًا أثناء الجلسات الصادرة"),
|
||||
("keep-awake-during-incoming-sessions-label", "إبقاء الجهاز نشطًا أثناء الجلسات الواردة"),
|
||||
("Continue with {}", "متابعة مع {}"),
|
||||
("Display Name", ""),
|
||||
("Display Name", "اسم العرض"),
|
||||
("password-hidden-tip", "كلمة المرور مخفية"),
|
||||
("preset-password-in-use-tip", "كلمة المرور المحددة مسبقًا قيد الاستخدام"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Налады клавіятуры"),
|
||||
("Full Access", "Поўны доступ"),
|
||||
("Screen Share", "Дэманстрацыя экрана"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland патрабуе Ubuntu версіі 21.04 або навейшай."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Для Wayland патрабуецца вышэйшая версія дыстрыбутыву Linux. Карыстайцеся працоўным сталом X11 або зменіце сваю АС."),
|
||||
("ubuntu-21-04-required", "Wayland патрабуе Ubuntu версіі 21.04 або навейшай."),
|
||||
("wayland-requires-higher-linux-version", "Для Wayland патрабуецца вышэйшая версія дыстрыбутыву Linux. Карыстайцеся працоўным сталом X11 або зменіце сваю АС."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Перайсці па спасылцы"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Выберыце экран для дэманстрацыі (кіруецца аддаленай стараной)."),
|
||||
("Show RustDesk", "Паказаць RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Працягнуць з {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Настройки на клавиатурата"),
|
||||
("Full Access", "Пълен достъп"),
|
||||
("Screen Share", "Споделяне на екрана"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland изисква Ubuntu 21.04 или по-нов"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland изисква по-нов Linux. Моля, опитайте с X11 или сменете операционната система."),
|
||||
("ubuntu-21-04-required", "Wayland изисква Ubuntu 21.04 или по-нов"),
|
||||
("wayland-requires-higher-linux-version", "Wayland изисква по-нов Linux. Моля, опитайте с X11 или сменете операционната система."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Препратка"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Моля, изберете екрана, който да бъде споделен (спрямо отдалечената страна)."),
|
||||
("Show RustDesk", "Покажи RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Продължи с {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Configuració del teclat"),
|
||||
("Full Access", "Accés complet"),
|
||||
("Screen Share", "Compartició de pantalla"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requereix Ubuntu 21.04 o superior"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requereix una versió superior de sistema Linux per a funcionar. Proveu iniciant un entorn d'escriptori amb x11 o actualitzeu el vostre sistema operatiu."),
|
||||
("ubuntu-21-04-required", "Wayland requereix Ubuntu 21.04 o superior"),
|
||||
("wayland-requires-higher-linux-version", "Wayland requereix una versió superior de sistema Linux per a funcionar. Proveu iniciant un entorn d'escriptori amb x11 o actualitzeu el vostre sistema operatiu."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Marcador"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Seleccioneu la pantalla que compartireu (quina serà visible al client)"),
|
||||
("Show RustDesk", "Mostra el RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Continua amb {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "键盘设置"),
|
||||
("Full Access", "完全访问"),
|
||||
("Screen Share", "仅共享屏幕"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland 需要 Ubuntu 21.04 或更高版本。"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 发行版。 请尝试 X11 桌面或更改您的操作系统。"),
|
||||
("ubuntu-21-04-required", "Wayland 需要 Ubuntu 21.04 或更高版本。"),
|
||||
("wayland-requires-higher-linux-version", "Wayland 需要更高版本的 linux 发行版。 请尝试 X11 桌面或更改您的操作系统。"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "查看"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "请选择要分享的画面(对端操作)。"),
|
||||
("Show RustDesk", "显示 RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "传入会话期间保持屏幕常亮"),
|
||||
("Continue with {}", "使用 {} 登录"),
|
||||
("Display Name", "显示名称"),
|
||||
("password-hidden-tip", "永久密码已设置(已隐藏)"),
|
||||
("preset-password-in-use-tip", "当前使用预设密码"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Nastavení klávesnice"),
|
||||
("Full Access", "Úplný přístup"),
|
||||
("Screen Share", "Sdílení obrazovky"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vyžaduje Ubuntu 21.04, nebo vyšší verzi."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vyžaduje vyšší verzi linuxové distribuce. Zkuste prosím X11 desktop, nebo změňte OS."),
|
||||
("ubuntu-21-04-required", "Wayland vyžaduje Ubuntu 21.04, nebo vyšší verzi."),
|
||||
("wayland-requires-higher-linux-version", "Wayland vyžaduje vyšší verzi linuxové distribuce. Zkuste prosím X11 desktop, nebo změňte OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Vyberte prosím obrazovku, kterou chcete sdílet (Ovládejte na straně protistrany)."),
|
||||
("Show RustDesk", "Zobrazit RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Pokračovat s {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Tastaturindstillinger"),
|
||||
("Full Access", "Fuld adgang"),
|
||||
("Screen Share", "Skærmdeling"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland kræver Ubuntu version 21.04 eller nyere."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland kræver en højere version af Linux distro. Prøv venligst X11 desktop eller skift dit OS."),
|
||||
("ubuntu-21-04-required", "Wayland kræver Ubuntu version 21.04 eller nyere."),
|
||||
("wayland-requires-higher-linux-version", "Wayland kræver en højere version af Linux distro. Prøv venligst X11 desktop eller skift dit OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Vælg venligst den skærm, der skal deles (Betjen på modtagersiden)."),
|
||||
("Show RustDesk", "Vis RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Fortsæt med {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,9 +377,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Tastatureinstellungen"),
|
||||
("Full Access", "Vollzugriff"),
|
||||
("Screen Share", "Bildschirmfreigabe"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland erfordert Ubuntu 21.04 oder eine höhere Version."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland erfordert eine höhere Version der Linux-Distribution. Bitte versuchen Sie den X11-Desktop oder ändern Sie Ihr Betriebssystem."),
|
||||
("JumpLink", "View"),
|
||||
("ubuntu-21-04-required", "Wayland erfordert Ubuntu 21.04 oder eine höhere Version."),
|
||||
("wayland-requires-higher-linux-version", "Wayland erfordert eine höhere Version der Linux-Distribution. Bitte versuchen Sie den X11-Desktop oder ändern Sie Ihr Betriebssystem."),
|
||||
("xdp-portal-unavailable", "Die Bildschirmaufnahme mit Wayland ist fehlgeschlagen. Das XDG-Desktop-Portal ist möglicherweise abgestürzt oder nicht verfügbar. Versuchen Sie, es mit `systemctl --user restart xdg-desktop-portal` neu zu starten."),
|
||||
("JumpLink", "Anzeigen"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Bitte wählen Sie den freizugebenden Bildschirm aus (Bedienung auf der Gegenseite)."),
|
||||
("Show RustDesk", "RustDesk anzeigen"),
|
||||
("This PC", "Dieser PC"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Bildschirm während eingehender Sitzungen aktiv halten"),
|
||||
("Continue with {}", "Fortfahren mit {}"),
|
||||
("Display Name", "Anzeigename"),
|
||||
("password-hidden-tip", "Ein permanentes Passwort wurde festgelegt (ausgeblendet)."),
|
||||
("preset-password-in-use-tip", "Das voreingestellte Passwort wird derzeit verwendet."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Ρυθμίσεις πληκτρολογίου"),
|
||||
("Full Access", "Πλήρης πρόσβαση"),
|
||||
("Screen Share", "Κοινή χρήση οθόνης"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Το Wayland απαιτεί Ubuntu 21.04 ή νεότερη έκδοση."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Το Wayland απαιτεί υψηλότερη έκδοση διανομής του linux. Δοκιμάστε την επιφάνεια εργασίας X11 ή αλλάξτε το λειτουργικό σας σύστημα."),
|
||||
("ubuntu-21-04-required", "Το Wayland απαιτεί Ubuntu 21.04 ή νεότερη έκδοση."),
|
||||
("wayland-requires-higher-linux-version", "Το Wayland απαιτεί υψηλότερη έκδοση διανομής του linux. Δοκιμάστε την επιφάνεια εργασίας X11 ή αλλάξτε το λειτουργικό σας σύστημα."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Σύνδεσμος μετάβασης"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Επιλέξτε την οθόνη που θέλετε να μοιραστείτε (Λειτουργία στην πλευρά του απομακρυσμένου σταθμού)."),
|
||||
("Show RustDesk", "Εμφάνιση του RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Διατήρηση ενεργής οθόνης κατά τη διάρκεια των εισερχόμενων συνεδριών"),
|
||||
("Continue with {}", "Συνέχεια με {}"),
|
||||
("Display Name", "Εμφανιζόμενο όνομα"),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,6 +120,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Keyboard settings"),
|
||||
("Full Access", "Full access"),
|
||||
("Screen Share", "Screen share"),
|
||||
("ubuntu-21-04-required", "Wayland requires Ubuntu 21.04 or higher version."),
|
||||
("wayland-requires-higher-linux-version", "Wayland requires higher version of linux distro. Please try X11 desktop or change your OS."),
|
||||
("xdp-portal-unavailable", "Wayland screen capture failed. The XDG Desktop Portal may have crashed or is unavailable. Try restarting it with `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Please select the screen to be shared(Operate on the peer side)."),
|
||||
("One-time Password", "One-time password"),
|
||||
|
|
@ -269,5 +272,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("rel-mouse-permission-lost-tip", "Keyboard permission was revoked. Relative Mouse Mode has been disabled."),
|
||||
("keep-awake-during-outgoing-sessions-label", "Keep screen awake during outgoing sessions"),
|
||||
("keep-awake-during-incoming-sessions-label", "Keep screen awake during incoming sessions"),
|
||||
("password-hidden-tip", "Permanent password is set (hidden)."),
|
||||
("preset-password-in-use-tip", "Preset password is currently in use."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", ""),
|
||||
("Full Access", ""),
|
||||
("Screen Share", ""),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland postulas Ubuntu 21.04 aŭ pli altan version."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland postulas pli altan version de linuksa distro. Bonvolu provi X11-labortablon aŭ ŝanĝi vian OS."),
|
||||
("ubuntu-21-04-required", "Wayland postulas Ubuntu 21.04 aŭ pli altan version."),
|
||||
("wayland-requires-higher-linux-version", "Wayland postulas pli altan version de linuksa distro. Bonvolu provi X11-labortablon aŭ ŝanĝi vian OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Bonvolu Elekti la ekranon por esti dividita (Funkciu ĉe la sama flanko)."),
|
||||
("Show RustDesk", ""),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", ""),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Ajustes de teclado"),
|
||||
("Full Access", "Acceso completo"),
|
||||
("Screen Share", "Compartir pantalla"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requiere Ubuntu 21.04 o una versión superior."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requiere una versión superior de la distribución de Linux. Pruebe el escritorio X11 o cambie su sistema operativo."),
|
||||
("ubuntu-21-04-required", "Wayland requiere Ubuntu 21.04 o una versión superior."),
|
||||
("wayland-requires-higher-linux-version", "Wayland requiere una versión superior de la distribución de Linux. Pruebe el escritorio X11 o cambie su sistema operativo."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Ver"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Seleccione la pantalla que se compartirá (Operar en el lado del par)."),
|
||||
("Show RustDesk", "Mostrar RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Continuar con {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Klaviatuurisätted"),
|
||||
("Full Access", "Täielik ligipääs"),
|
||||
("Screen Share", "Ekraanijagamine"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland nõuab Ubuntu 21.04 või uuemat versiooni."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland nõuab Linuxi distributsiooni uuemat versiooni. Palun proovi X11 töölaual või muuda oma operatsioonisüsteemi."),
|
||||
("ubuntu-21-04-required", "Wayland nõuab Ubuntu 21.04 või uuemat versiooni."),
|
||||
("wayland-requires-higher-linux-version", "Wayland nõuab Linuxi distributsiooni uuemat versiooni. Palun proovi X11 töölaual või muuda oma operatsioonisüsteemi."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Palun vali jagatav ekraan (tegutse partneri poolel)."),
|
||||
("Show RustDesk", "Kuva RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Jätka koos {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Teklatuaren ezarpenak"),
|
||||
("Full Access", "Sarbide osoa"),
|
||||
("Screen Share", "Pantailaren partekatzea"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland Ubuntu 21.04 edo bertsio berriagoa behar du."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland-ek linux banaketa berriago bat behar du. Saiatu X11 mahaigainarekin edo aldatu zure sistema eragilea."),
|
||||
("ubuntu-21-04-required", "Wayland Ubuntu 21.04 edo bertsio berriagoa behar du."),
|
||||
("wayland-requires-higher-linux-version", "Wayland-ek linux banaketa berriago bat behar du. Saiatu X11 mahaigainarekin edo aldatu zure sistema eragilea."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Ikusi"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Mesedez, hautatu partekatuko den pantaila (Kudeatu parekidearen aldean)"),
|
||||
("Show RustDesk", "Erakutsi RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "{} honekin jarraitu"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "تنظیمات صفحه کلید"),
|
||||
("Full Access", "دسترسی کامل"),
|
||||
("Screen Share", "اشتراک گذاری صفحه"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "نیازمند اوبونتو نسخه 21.04 یا بالاتر است Wayland"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "استفاده کنید و یا سیستم عامل خود را تغییر دهید X11 نیازمند نسخه بالاتری از توزیع لینوکس است. لطفا از دسکتاپ با سیستم"),
|
||||
("ubuntu-21-04-required", "نیازمند اوبونتو نسخه 21.04 یا بالاتر است Wayland"),
|
||||
("wayland-requires-higher-linux-version", "استفاده کنید و یا سیستم عامل خود را تغییر دهید X11 نیازمند نسخه بالاتری از توزیع لینوکس است. لطفا از دسکتاپ با سیستم"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "چشم انداز"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "لطفاً صفحهای را برای اشتراکگذاری انتخاب کنید (در سمت همتا به همتا کار کنید)."),
|
||||
("Show RustDesk", "RustDesk نمایش"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "ادامه با {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Näppäimistöasetukset"),
|
||||
("Full Access", "Täysi käyttöoikeus"),
|
||||
("Screen Share", "Näytönjako"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vaatii Ubuntu 21.04:n tai uudemman version."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vaatii uudemman Linux jakelun version. Kokeile X11 työpöytää tai vaihda käyttöjärjestelmää."),
|
||||
("ubuntu-21-04-required", "Wayland vaatii Ubuntu 21.04:n tai uudemman version."),
|
||||
("wayland-requires-higher-linux-version", "Wayland vaatii uudemman Linux jakelun version. Kokeile X11 työpöytää tai vaihda käyttöjärjestelmää."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Pikalinkki"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Valitse jaettava näyttö (toiminto etäpäässä)."),
|
||||
("Show RustDesk", "Näytä RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Jatka käyttäen {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Paramètres du clavier"),
|
||||
("Full Access", "Accès total"),
|
||||
("Screen Share", "Partage d’écran"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland nécessite Ubuntu 21.04 ou une version ultérieure."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland nécessite une version ultérieure de votre distribution Linux. Veuillez essayer le bureau X11 ou changer de système d’exploitation."),
|
||||
("ubuntu-21-04-required", "Wayland nécessite Ubuntu 21.04 ou une version ultérieure."),
|
||||
("wayland-requires-higher-linux-version", "Wayland nécessite une version ultérieure de votre distribution Linux. Veuillez essayer le bureau X11 ou changer de système d’exploitation."),
|
||||
("xdp-portal-unavailable", "Échec de la capture de l’écran Wayland. Le portail de bureau XDG a peut-être planté ou n’est pas disponible. Essayez de le redémarrer avec la commande `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Afficher"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Veuillez sélectionner l’écran à partager (côté appareil distant)."),
|
||||
("Show RustDesk", "Afficher RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Maintenir l’écran allumé lors des sessions entrantes"),
|
||||
("Continue with {}", "Continuer avec {}"),
|
||||
("Display Name", "Nom d’affichage"),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "კლავიატურის პარამეტრები"),
|
||||
("Full Access", "სრული წვდომა"),
|
||||
("Screen Share", "ეკრანის გაზიარება"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland საჭიროებს Ubuntu 21.04 ან უფრო ახალ ვერსიას."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland-ს სჭირდება Linux-ის დისტრიბუტივის უფრო ახალი ვერსია. გამოიყენეთ X11 სამუშაო მაგიდა ან შეცვალეთ ოპერაციული სისტემა."),
|
||||
("ubuntu-21-04-required", "Wayland საჭიროებს Ubuntu 21.04 ან უფრო ახალ ვერსიას."),
|
||||
("wayland-requires-higher-linux-version", "Wayland-ს სჭირდება Linux-ის დისტრიბუტივის უფრო ახალი ვერსია. გამოიყენეთ X11 სამუშაო მაგიდა ან შეცვალეთ ოპერაციული სისტემა."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "ნახვა"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "აირჩიეთ ეკრანი გასაზიარებლად (იმუშავეთ პარტნიორის მხარეს)."),
|
||||
("Show RustDesk", "RustDesk-ის ჩვენება"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "{}-ით გაგრძელება"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
746
src/lang/gu.rs
Normal file
746
src/lang/gu.rs
Normal file
|
|
@ -0,0 +1,746 @@
|
|||
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", "નેટવર્ક સાથે જોડાઈ રહ્યું છે..."),
|
||||
("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/રિલે સર્વર"),
|
||||
("Import server config", "સર્વર કોન્ફિગ ઈમ્પોર્ટ કરો"),
|
||||
("Export Server Config", "સર્વર કોન્ફિગ એક્સપોર્ટ કરો"),
|
||||
("Import server configuration successfully", "સર્વર કોન્ફિગરેશન સફળતાપૂર્વક ઈમ્પોર્ટ થયું"),
|
||||
("Export server configuration successfully", "સર્વર કોન્ફિગરેશન સફળતાપૂર્વક એક્સપોર્ટ થયું"),
|
||||
("Invalid server configuration", "અમાન્ય સર્વર કોન્ફિગરેશન"),
|
||||
("Clipboard is empty", "ક્લિપબોર્ડ ખાલી છે"),
|
||||
("Stop service", "સેવા બંધ કરો"),
|
||||
("Change ID", "ID બદલો"),
|
||||
("Your new ID", "તમારું નવું ID"),
|
||||
("length %min% to %max%", "લંબાઈ %min% થી %max% સુધી"),
|
||||
("starts with a letter", "અક્ષરથી શરૂ થાય છે"),
|
||||
("allowed characters", "માન્ય અક્ષરો"),
|
||||
("id_change_tip", "ID બદલ્યા પછી વર્તમાન કનેક્શન તૂટી જશે."),
|
||||
("Website", "વેબસાઇટ"),
|
||||
("About", "વિશે"),
|
||||
("Slogan_tip", "વધુ સારા અનુભવ માટે બનાવેલ રિમોટ ડેસ્કટોપ સોફ્ટવેર"),
|
||||
("Privacy Statement", "ગોપનીયતા નિવેદન"),
|
||||
("Mute", "મ્યૂટ કરો"),
|
||||
("Build Date", "બિલ્ડ તારીખ"),
|
||||
("Version", "સંસ્કરણ (Version)"),
|
||||
("Home", "હોમ"),
|
||||
("Audio Input", "ઓડિયો ઇનપુટ"),
|
||||
("Enhancements", "વધારાની સુવિધાઓ"),
|
||||
("Hardware Codec", "હાર્ડવેર કોડેક"),
|
||||
("Adaptive bitrate", "એડેપ્ટિવ બિટરેટ"),
|
||||
("ID Server", "ID સર્વર"),
|
||||
("Relay Server", "રિલે સર્વર"),
|
||||
("API Server", "API સર્વર"),
|
||||
("invalid_http", "અમાન્ય HTTP લિંક"),
|
||||
("Invalid IP", "અમાન્ય IP"),
|
||||
("Invalid format", "અમાન્ય ફોર્મેટ"),
|
||||
("server_not_support", "સર્વર દ્વારા સમર્થિત નથી"),
|
||||
("Not available", "ઉપલબ્ધ નથી"),
|
||||
("Too frequent", "ખૂબ વારંવાર"),
|
||||
("Cancel", "રદ કરો"),
|
||||
("Skip", "રહેવા દો (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", "કદ (Size)"),
|
||||
("Show Hidden Files", "છુપાયેલી ફાઇલો બતાવો"),
|
||||
("Receive", "મેળવો"),
|
||||
("Send", "મોકલો"),
|
||||
("Refresh File", "ફાઇલ રિફ્રેશ કરો"),
|
||||
("Local", "લોકલ"),
|
||||
("Remote", "રિમોટ"),
|
||||
("Remote Computer", "રિમોટ કોમ્પ્યુટર"),
|
||||
("Local Computer", "લોકલ કોમ્પ્યુટર"),
|
||||
("Confirm Delete", "કાઢી નાખવાની પુષ્ટિ કરો"),
|
||||
("Delete", "કાઢી નાખો"),
|
||||
("Properties", "ગુણધર્મો (Properties)"),
|
||||
("Multi Select", "બહુ-પસંદગી"),
|
||||
("Select All", "બધું પસંદ કરો"),
|
||||
("Unselect All", "બધું નાપસંદ કરો"),
|
||||
("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", "મૂળ (Original)"),
|
||||
("Shrink", "સંકોચો (Shrink)"),
|
||||
("Stretch", "ખેંચો (Stretch)"),
|
||||
("Scrollbar", "સ્ક્રોલબાર"),
|
||||
("ScrollAuto", "ઓટો સ્ક્રોલ"),
|
||||
("Good image quality", "સારી ઇમેજ ગુણવત્તા"),
|
||||
("Balanced", "સંતુલિત"),
|
||||
("Optimize reaction time", "પ્રતિક્રિયા સમય શ્રેષ્ઠ બનાવો"),
|
||||
("Custom", "કસ્ટમ"),
|
||||
("Show remote cursor", "રિમોટ કર્સર બતાવો"),
|
||||
("Show quality monitor", "ક્વોલિટી મોનિટર બતાવો"),
|
||||
("Disable clipboard", "ક્લિપબોર્ડ અક્ષમ કરો"),
|
||||
("Lock after session end", "સત્ર સમાપ્ત થયા પછી લોક કરો"),
|
||||
("Insert Ctrl + Alt + Del", "Ctrl + Alt + Del દાખલ કરો"),
|
||||
("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", "રિલે સર્વર સાથે જોડવામાં નિષ્ફળ"),
|
||||
("Failed to connect via rendezvous server", "Rendezvous સર્વર દ્વારા જોડવામાં નિષ્ફળ"),
|
||||
("Failed to connect via relay server", "રિલે સર્વર દ્વારા જોડવામાં નિષ્ફળ"),
|
||||
("Failed to make direct connection to remote desktop", "રિમોટ ડેસ્કટોપ સાથે સીધું જોડાણ કરવામાં નિષ્ફળ"),
|
||||
("Set Password", "પાસવર્ડ સેટ કરો"),
|
||||
("OS Password", "OS પાસવર્ડ"),
|
||||
("install_tip", "શ્રેષ્ઠ પ્રદર્શન માટે, કૃપા કરીને ઇન્સ્ટોલ કરો."),
|
||||
("Click to upgrade", "અપગ્રેડ કરવા માટે ક્લિક કરો"),
|
||||
("Configure", "કોન્ફિગર કરો"),
|
||||
("config_acc", "એક્સેસિબિલિટી કોન્ફિગર કરો"),
|
||||
("config_screen", "સ્ક્રીન કોન્ફિગર કરો"),
|
||||
("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", "લોકલ પોર્ટ"),
|
||||
("Local Address", "લોકલ સરનામું"),
|
||||
("Change Local Port", "લોકલ પોર્ટ બદલો"),
|
||||
("setup_server_tip", "ઝડપી કનેક્શન માટે તમારું પોતાનું સર્વર સેટ કરો"),
|
||||
("Too short, at least 6 characters.", "ખૂબ ટૂંકું, ઓછામાં ઓછા 6 અક્ષરો હોવા જોઈએ."),
|
||||
("The confirmation is not identical.", "પુષ્ટિકરણ સરખું નથી."),
|
||||
("Permissions", "પરવાનગીઓ"),
|
||||
("Accept", "સ્વીકારો"),
|
||||
("Dismiss", "ખારીજ કરો"),
|
||||
("Disconnect", "ડિસ્કનેક્ટ કરો"),
|
||||
("Enable 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", "જગ્યા (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", "ઇન્સ્ટોલ કર્યા વગર ચલાવો"),
|
||||
("Connect via relay", "રિલે દ્વારા કનેક્ટ કરો"),
|
||||
("Always connect via relay", "હંમેશા રિલે દ્વારા કનેક્ટ કરો"),
|
||||
("whitelist_tip", "માત્ર વ્હાઇટલિસ્ટ કરેલ IP જ મને એક્સેસ કરી શકે છે"),
|
||||
("Login", "લોગિન"),
|
||||
("Verify", "ચકાસો"),
|
||||
("Remember me", "મને યાદ રાખો"),
|
||||
("Trust this device", "આ ઉપકરણ પર વિશ્વાસ કરો"),
|
||||
("Verification code", "વેરિફિકેશન કોડ"),
|
||||
("verification_tip", "વેરિફિકેશન કોડ તમારા ઇમેઇલ પર મોકલવામાં આવ્યો છે"),
|
||||
("Logout", "લોગઆઉટ"),
|
||||
("Tags", "ટેગ્સ"),
|
||||
("Search ID", "ID શોધો"),
|
||||
("whitelist_sep", "અલ્પવિરામ, અર્ધવિરામ અથવા સ્પેસ દ્વારા અલગ કરો"),
|
||||
("Add ID", "ID ઉમેરો"),
|
||||
("Add Tag", "ટેગ ઉમેરો"),
|
||||
("Unselect all tags", "તમામ ટેગ નાપસંદ કરો"),
|
||||
("Network error", "નેટવર્ક ભૂલ"),
|
||||
("Username missed", "વપરાશકર્તા નામ બાકી છે"),
|
||||
("Password missed", "પાસવર્ડ બાકી છે"),
|
||||
("Wrong credentials", "ખોટી વિગતો"),
|
||||
("The verification code is incorrect or has expired", "વેરિફિકેશન કોડ ખોટો છે અથવા તેની મર્યાદા પૂરી થઈ ગઈ છે"),
|
||||
("Edit Tag", "ટેગ સુધારો"),
|
||||
("Forget Password", "પાસવર્ડ ભૂલી ગયા"),
|
||||
("Favorites", "પસંદગીના"),
|
||||
("Add to Favorites", "પસંદગીમાં ઉમેરો"),
|
||||
("Remove from Favorites", "પસંદગીમાંથી દૂર કરો"),
|
||||
("Empty", "ખાલી"),
|
||||
("Invalid folder name", "અમાન્ય ફોલ્ડર નામ"),
|
||||
("Socks5 Proxy", "Socks5 પ્રોક્સી"),
|
||||
("Socks5/Http(s) Proxy", "Socks5/Http(s) પ્રોક્સી"),
|
||||
("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", "સ્ક્રીન શેર કરો"),
|
||||
("Chat", "ચેટ"),
|
||||
("Total", "કુલ"),
|
||||
("items", "વસ્તુઓ"),
|
||||
("Selected", "પસંદ કરેલ"),
|
||||
("Screen Capture", "સ્ક્રીન કેપ્ચર"),
|
||||
("Input Control", "ઇનપુટ નિયંત્રણ"),
|
||||
("Audio Capture", "ઓડિયો કેપ્ચર"),
|
||||
("Do you accept?", "શું તમે સ્વીકારો છો?"),
|
||||
("Open System Setting", "સિસ્ટમ સેટિંગ ખોલો"),
|
||||
("How to get Android input permission?", "Android ઇનપુટ પરવાનગી કેવી રીતે મેળવવી?"),
|
||||
("android_input_permission_tip1", "ઇનપુટ પરવાનગી મેળવવા માટે એક્સેસિબિલિટી સેવા સક્ષમ કરો."),
|
||||
("android_input_permission_tip2", "કૃપા કરીને સેટિંગ્સમાં RustDesk શોધો અને તેને ચાલુ કરો."),
|
||||
("android_new_connection_tip", "નવો કંટ્રોલ વિનંતી પ્રાપ્ત થઈ છે."),
|
||||
("android_service_will_start_tip", "સ્ક્રીન કેપ્ચર ચાલુ કરવાથી સેવા આપમેળે શરૂ થશે."),
|
||||
("android_stop_service_tip", "સેવા બંધ કરવાથી તમામ કનેક્શન બંધ થઈ જશે."),
|
||||
("android_version_audio_tip", "ઓડિયો કેપ્ચર માત્ર Android 10 કે તેથી ઉપરના વર્ઝનમાં ઉપલબ્ધ છે."),
|
||||
("android_start_service_tip", "સ્ક્રીન શેરિંગ સેવા શરૂ કરવા ક્લિક કરો."),
|
||||
("android_permission_may_not_change_tip", "પરવાનગીઓ પછીથી બદલી શકાશે નહીં, કૃપા કરીને કાળજીપૂર્વક પસંદ કરો."),
|
||||
("Account", "ખાતું"),
|
||||
("Overwrite", "ઓવરરાઇટ કરો"),
|
||||
("This file exists, skip or overwrite this file?", "આ ફાઇલ અસ્તિત્વમાં છે, રહેવા દેવી છે કે ઓવરરાઇટ કરવી છે?"),
|
||||
("Quit", "બહાર નીકળો"),
|
||||
("Help", "મદદ"),
|
||||
("Failed", "નિષ્ફળ"),
|
||||
("Succeeded", "સફળ"),
|
||||
("Someone turns on privacy mode, exit", "કોઈએ પ્રાઇવસી મોડ ચાલુ કર્યો છે, બહાર નીકળો"),
|
||||
("Unsupported", "અસમર્થિત"),
|
||||
("Peer denied", "સામેથી નકારવામાં આવ્યું"),
|
||||
("Please install plugins", "કૃપા કરીને પ્લગઇન્સ ઇન્સ્ટોલ કરો"),
|
||||
("Peer exit", "સામેથી કોઈ બહાર નીકળી ગયું"),
|
||||
("Failed to turn off", "બંધ કરવામાં નિષ્ફળ"),
|
||||
("Turned off", "બંધ કરવામાં આવ્યું"),
|
||||
("Language", "ભાષા"),
|
||||
("Keep RustDesk background service", "RustDesk બેકગ્રાઉન્ડ સેવા ચાલુ રાખો"),
|
||||
("Ignore Battery Optimizations", "બેટરી ઓપ્ટિમાઇઝેશન અવગણો"),
|
||||
("android_open_battery_optimizations_tip", "ડિસ્કનેક્શન ટાળવા માટે બેટરી ઓપ્ટિમાઇઝેશન સેટિંગ ખોલો"),
|
||||
("Start on boot", "બૂટ પર શરૂ કરો"),
|
||||
("Start the screen sharing service on boot, requires special permissions", "બૂટ પર સ્ક્રીન શેરિંગ શરૂ કરો, ખાસ પરવાનગીની જરૂર છે"),
|
||||
("Connection not allowed", "કનેક્શનની પરવાનગી નથી"),
|
||||
("Legacy mode", "લેગસી મોડ"),
|
||||
("Map mode", "મેપ મોડ"),
|
||||
("Translate mode", "અનુવાદ મોડ"),
|
||||
("Use permanent password", "કાયમી પાસવર્ડનો ઉપયોગ કરો"),
|
||||
("Use both passwords", "બંને પાસવર્ડનો ઉપયોગ કરો"),
|
||||
("Set permanent password", "કાયમી પાસવર્ડ સેટ કરો"),
|
||||
("Enable remote restart", "રિમોટ રિસ્ટાર્ટ સક્ષમ કરો"),
|
||||
("Restart remote device", "રિમોટ ઉપકરણ રિસ્ટાર્ટ કરો"),
|
||||
("Are you sure you want to restart", "શું તમે ખરેખર રિસ્ટાર્ટ કરવા માંગો છો?"),
|
||||
("Restarting remote device", "રિમોટ ઉપકરણ રિસ્ટાર્ટ થઈ રહ્યું છે"),
|
||||
("remote_restarting_tip", "રિમોટ ઉપકરણ રિસ્ટાર્ટ થઈ રહ્યું છે, કૃપા કરીને રાહ જુઓ..."),
|
||||
("Copied", "કોપી થઈ ગયું"),
|
||||
("Exit Fullscreen", "ફુલસ્ક્રીનમાંથી બહાર નીકળો"),
|
||||
("Fullscreen", "ફુલસ્ક્રીન"),
|
||||
("Mobile Actions", "મોબાઇલ ક્રિયાઓ"),
|
||||
("Select Monitor", "મોનિટર પસંદ કરો"),
|
||||
("Control Actions", "નિયંત્રણ ક્રિયાઓ"),
|
||||
("Display Settings", "ડિસ્પ્લે સેટિંગ્સ"),
|
||||
("Ratio", "રેશિયો (Ratio)"),
|
||||
("Image Quality", "ઇમેજ ગુણવત્તા"),
|
||||
("Scroll Style", "સ્ક્રોલ શૈલી"),
|
||||
("Show Toolbar", "ટૂલબાર બતાવો"),
|
||||
("Hide Toolbar", "ટૂલબાર છુપાવો"),
|
||||
("Direct Connection", "સીધું કનેક્શન"),
|
||||
("Relay Connection", "રિલે કનેક્શન"),
|
||||
("Secure Connection", "સુરક્ષિત કનેક્શન"),
|
||||
("Insecure Connection", "અસુરક્ષિત કનેક્શન"),
|
||||
("Scale original", "મૂળ સ્કેલ"),
|
||||
("Scale adaptive", "એડેપ્ટિવ સ્કેલ"),
|
||||
("General", "સામાન્ય"),
|
||||
("Security", "સુરક્ષા"),
|
||||
("Theme", "થીમ"),
|
||||
("Dark Theme", "ડાર્ક થીમ"),
|
||||
("Light Theme", "લાઇટ થીમ"),
|
||||
("Dark", "ડાર્ક"),
|
||||
("Light", "લાઇટ"),
|
||||
("Follow System", "સિસ્ટમ મુજબ"),
|
||||
("Enable hardware codec", "હાર્ડવેર કોડેક સક્ષમ કરો"),
|
||||
("Unlock Security Settings", "સુરક્ષા સેટિંગ્સ અનલોક કરો"),
|
||||
("Enable audio", "ઓડિયો સક્ષમ કરો"),
|
||||
("Unlock Network Settings", "નેટવર્ક સેટિંગ્સ અનલોક કરો"),
|
||||
("Server", "સર્વર"),
|
||||
("Direct IP Access", "સીધું IP એક્સેસ"),
|
||||
("Proxy", "પ્રોક્સી"),
|
||||
("Apply", "લાગુ કરો"),
|
||||
("Disconnect all devices?", "તમામ ઉપકરણો ડિસ્કનેક્ટ કરવા છે?"),
|
||||
("Clear", "સાફ કરો"),
|
||||
("Audio Input Device", "ઓડિયો ઇનપુટ ઉપકરણ"),
|
||||
("Use IP Whitelisting", "IP વ્હાઇટલિસ્ટિંગનો ઉપયોગ કરો"),
|
||||
("Network", "નેટવર્ક"),
|
||||
("Pin Toolbar", "ટૂલબાર પિન કરો"),
|
||||
("Unpin Toolbar", "ટૂલબાર અનપિન કરો"),
|
||||
("Recording", "રેકોર્ડિંગ"),
|
||||
("Directory", "ડિરેક્ટરી"),
|
||||
("Automatically record incoming sessions", "આવતા સત્રો આપમેળે રેકોર્ડ કરો"),
|
||||
("Automatically record outgoing sessions", "જતા સત્રો આપમેળે રેકોર્ડ કરો"),
|
||||
("Change", "બદલો"),
|
||||
("Start session recording", "સત્ર રેકોર્ડિંગ શરૂ કરો"),
|
||||
("Stop session recording", "સત્ર રેકોર્ડિંગ બંધ કરો"),
|
||||
("Enable recording session", "સત્ર રેકોર્ડિંગ સક્ષમ કરો"),
|
||||
("Enable LAN discovery", "LAN ડિસ્કવરી સક્ષમ કરો"),
|
||||
("Deny LAN discovery", "LAN ડિસ્કવરી નકારો"),
|
||||
("Write a message", "સંદેશ લખો"),
|
||||
("Prompt", "પ્રોમ્પ્ટ"),
|
||||
("Please wait for confirmation of UAC...", "કૃપા કરીને UAC પુષ્ટિની રાહ જુઓ..."),
|
||||
("elevated_foreground_window_tip", "રિમોટની વર્તમાન વિન્ડોને વધારે પરવાનગીની જરૂર છે."),
|
||||
("Disconnected", "ડિસ્કનેક્ટ થઈ ગયું"),
|
||||
("Other", "અન્ય"),
|
||||
("Confirm before closing multiple tabs", "બહુવિધ ટેબ્સ બંધ કરતા પહેલા પુષ્ટિ કરો"),
|
||||
("Keyboard Settings", "કીબોર્ડ સેટિંગ્સ"),
|
||||
("Full Access", "પૂર્ણ એક્સેસ"),
|
||||
("Screen Share", "સ્ક્રીન શેર"),
|
||||
("ubuntu-21-04-required", "Ubuntu 21.04 કે તેથી ઉપર જરૂરી છે"),
|
||||
("wayland-requires-higher-linux-version", "Wayland માટે ઉચ્ચ Linux વર્ઝન જરૂરી છે"),
|
||||
("xdp-portal-unavailable", "XDP પોર્ટલ અનુપલબ્ધ છે"),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "કૃપા કરીને શેર કરવાની સ્ક્રીન પસંદ કરો (સામેના છેડે કાર્ય કરો)."),
|
||||
("Show RustDesk", "RustDesk બતાવો"),
|
||||
("This PC", "આ PC"),
|
||||
("or", "અથવા"),
|
||||
("Elevate", "એલિવેટ કરો"),
|
||||
("Zoom cursor", "ઝૂમ કર્સર"),
|
||||
("Accept sessions via password", "પાસવર્ડ દ્વારા સત્રો સ્વીકારો"),
|
||||
("Accept sessions via click", "ક્લિક દ્વારા સત્રો સ્વીકારો"),
|
||||
("Accept sessions via both", "બંને દ્વારા સત્રો સ્વીકારો"),
|
||||
("Please wait for the remote side to accept your session request...", "કૃપા કરીને સામેનો છેડો વિનંતી સ્વીકારે તેની રાહ જુઓ..."),
|
||||
("One-time Password", "વન-ટાઇમ પાસવર્ડ (OTP)"),
|
||||
("Use one-time password", "વન-ટાઇમ પાસવર્ડનો ઉપયોગ કરો"),
|
||||
("One-time password length", "OTP ની લંબાઈ"),
|
||||
("Request access to your device", "તમારા ઉપકરણના એક્સેસ માટે વિનંતી"),
|
||||
("Hide connection management window", "કનેક્શન મેનેજમેન્ટ વિન્ડો છુપાવો"),
|
||||
("hide_cm_tip", "જો પાસવર્ડ દ્વારા કનેક્શન હોય તો જ છુપાવો"),
|
||||
("wayland_experiment_tip", "Wayland સપોર્ટ હજુ પ્રાયોગિક ધોરણે છે"),
|
||||
("Right click to select tabs", "ટેબ્સ પસંદ કરવા રાઇટ ક્લિક કરો"),
|
||||
("Skipped", "રહેવા દીધું (Skipped)"),
|
||||
("Add to address book", "એડ્રેસ બુકમાં ઉમેરો"),
|
||||
("Group", "ગ્રુપ"),
|
||||
("Search", "શોધો"),
|
||||
("Closed manually by web console", "વેબ કન્સોલ દ્વારા મેન્યુઅલી બંધ કરવામાં આવ્યું"),
|
||||
("Local keyboard type", "લોકલ કીબોર્ડ પ્રકાર"),
|
||||
("Select local keyboard type", "લોકલ કીબોર્ડ પ્રકાર પસંદ કરો"),
|
||||
("software_render_tip", "જો સ્ક્રીન કાળી દેખાય, તો આ અજમાવો"),
|
||||
("Always use software rendering", "હંમેશા સોફ્ટવેર રેન્ડરિંગનો ઉપયોગ કરો"),
|
||||
("config_input", "ઇનપુટ કોન્ફિગર કરો"),
|
||||
("config_microphone", "માઇક્રોફોન કોન્ફિગર કરો"),
|
||||
("request_elevation_tip", "સામેથી ઉચ્ચ પરવાનગી (Elevation) માટે વિનંતી કરો"),
|
||||
("Wait", "રાહ જુઓ"),
|
||||
("Elevation Error", "એલિવેશન ભૂલ"),
|
||||
("Ask the remote user for authentication", "સામેના યુઝરને ઓથેન્ટિકેશન માટે પૂછો"),
|
||||
("Choose this if the remote account is administrator", "જો સામેનું ખાતું એડમિનિસ્ટ્રેટર હોય તો આ પસંદ કરો"),
|
||||
("Transmit the username and password of administrator", "એડમિનિસ્ટ્રેટરનું નામ અને પાસવર્ડ મોકલો"),
|
||||
("still_click_uac_tip", "રિમોટ યુઝરે હજુ પણ UAC વિન્ડોમાં 'હા' ક્લિક કરવું પડશે."),
|
||||
("Request Elevation", "એલિવેશન માટે વિનંતી કરો"),
|
||||
("wait_accept_uac_tip", "કૃપા કરીને સામેનો યુઝર UAC સ્વીકારે તેની રાહ જુઓ."),
|
||||
("Elevate successfully", "સફળતાપૂર્વક એલિવેટ થયું"),
|
||||
("uppercase", "મોટા અક્ષરો (Uppercase)"),
|
||||
("lowercase", "નાના અક્ષરો (Lowercase)"),
|
||||
("digit", "અંક (Digit)"),
|
||||
("special character", "ખાસ અક્ષર"),
|
||||
("length>=8", "લંબાઈ >= 8"),
|
||||
("Weak", "નબળું"),
|
||||
("Medium", "મધ્યમ"),
|
||||
("Strong", "મજબૂત"),
|
||||
("Switch Sides", "બાજુઓ બદલો"),
|
||||
("Please confirm if you want to share your desktop?", "શું તમે તમારું ડેસ્કટોપ શેર કરવા માંગો છો?"),
|
||||
("Display", "ડિસ્પ્લે"),
|
||||
("Default View Style", "ડિફોલ્ટ વ્યુ શૈલી"),
|
||||
("Default Scroll Style", "ડિફોલ્ટ સ્ક્રોલ શૈલી"),
|
||||
("Default Image Quality", "ડિફોલ્ટ ઇમેજ ગુણવત્તા"),
|
||||
("Default Codec", "ડિફોલ્ટ કોડેક"),
|
||||
("Bitrate", "બિટરેટ"),
|
||||
("FPS", "FPS"),
|
||||
("Auto", "ઓટો"),
|
||||
("Other Default Options", "અન્ય ડિફોલ્ટ વિકલ્પો"),
|
||||
("Voice call", "વોઇસ કોલ"),
|
||||
("Text chat", "ટેક્સ્ટ ચેટ"),
|
||||
("Stop voice call", "વોઇસ કોલ બંધ કરો"),
|
||||
("relay_hint_tip", "સીધું કનેક્શન શક્ય નથી; તમે રિલે દ્વારા પ્રયાસ કરી શકો છો."),
|
||||
("Reconnect", "ફરી કનેક્ટ કરો"),
|
||||
("Codec", "કોડેક"),
|
||||
("Resolution", "રિઝોલ્યુશન"),
|
||||
("No transfers in progress", "કોઈ ટ્રાન્સફર ચાલુ નથી"),
|
||||
("Set one-time password length", "OTP લંબાઈ સેટ કરો"),
|
||||
("RDP Settings", "RDP સેટિંગ્સ"),
|
||||
("Sort by", "ક્રમબદ્ધ કરો"),
|
||||
("New Connection", "નવું કનેક્શન"),
|
||||
("Restore", "રીસ્ટોર"),
|
||||
("Minimize", "મિનિમાઇઝ"),
|
||||
("Maximize", "મેક્સિમાઇઝ"),
|
||||
("Your Device", "તમારું ઉપકરણ"),
|
||||
("empty_recent_tip", "તાજેતરના સત્રો અહીં દેખાશે."),
|
||||
("empty_favorite_tip", "પસંદગીના ઉપકરણો અહીં દેખાશે."),
|
||||
("empty_lan_tip", "નેટવર્ક પરના ઉપકરણો અહીં દેખાશે."),
|
||||
("empty_address_book_tip", "તમારી એડ્રેસ બુક ખાલી છે."),
|
||||
("Empty Username", "ખાલી યુઝરનેમ"),
|
||||
("Empty Password", "ખાલી પાસવર્ડ"),
|
||||
("Me", "હું"),
|
||||
("identical_file_tip", "આ ફાઇલ પહેલેથી જ અસ્તિત્વમાં છે."),
|
||||
("show_monitors_tip", "ટૂલબારમાં મોનિટર બતાવો"),
|
||||
("View Mode", "વ્યુ મોડ"),
|
||||
("login_linux_tip", "રિમોટ Linux સત્ર માટે તમારે લોગિન કરવું પડશે"),
|
||||
("verify_rustdesk_password_tip", "RustDesk પાસવર્ડ ચકાસો"),
|
||||
("remember_account_tip", "આ ખાતું યાદ રાખો"),
|
||||
("os_account_desk_tip", "એક્સેસ માટે OS ખાતાનો ઉપયોગ કરો"),
|
||||
("OS Account", "OS ખાતું"),
|
||||
("another_user_login_title_tip", "બીજો યુઝર પહેલેથી લોગિન છે"),
|
||||
("another_user_login_text_tip", "ડિસ્કનેક્ટ કરો અને ફરી પ્રયાસ કરો"),
|
||||
("xorg_not_found_title_tip", "Xorg મળ્યું નથી"),
|
||||
("xorg_not_found_text_tip", "કૃપા કરીને Xorg ઇન્સ્ટોલ કરો"),
|
||||
("no_desktop_title_tip", "કોઈ ડેસ્કટોપ ઉપલબ્ધ નથી"),
|
||||
("no_desktop_text_tip", "કૃપા કરીને Linux ડેસ્કટોપ ઇન્સ્ટોલ કરો"),
|
||||
("No need to elevate", "એલિવેટ કરવાની જરૂર નથી"),
|
||||
("System Sound", "સિસ્ટમ સાઉન્ડ"),
|
||||
("Default", "ડિફોલ્ટ"),
|
||||
("New RDP", "નવું RDP"),
|
||||
("Fingerprint", "ફિંગરપ્રિન્ટ"),
|
||||
("Copy Fingerprint", "ફિંગરપ્રિન્ટ કોપી કરો"),
|
||||
("no fingerprints", "કોઈ ફિંગરપ્રિન્ટ નથી"),
|
||||
("Select a peer", "એક પીઅર પસંદ કરો"),
|
||||
("Select peers", "પીઅર્સ પસંદ કરો"),
|
||||
("Plugins", "પ્લગઇન્સ"),
|
||||
("Uninstall", "અનઇન્સ્ટોલ કરો"),
|
||||
("Update", "અપડેટ કરો"),
|
||||
("Enable", "સક્ષમ કરો"),
|
||||
("Disable", "અક્ષમ કરો"),
|
||||
("Options", "વિકલ્પો"),
|
||||
("resolution_original_tip", "મૂળ રિઝોલ્યુશન"),
|
||||
("resolution_fit_local_tip", "સ્ક્રીન મુજબ ફીટ કરો"),
|
||||
("resolution_custom_tip", "કસ્ટમ રિઝોલ્યુશન"),
|
||||
("Collapse toolbar", "ટૂલબાર નાનું કરો"),
|
||||
("Accept and Elevate", "સ્વીકારો અને એલિવેટ કરો"),
|
||||
("accept_and_elevate_btn_tooltip", "કનેક્શન સ્વીકારો અને UAC પરવાનગીઓ મેળવો."),
|
||||
("clipboard_wait_response_timeout_tip", "ક્લિપબોર્ડ પ્રતિક્રિયા માટે સમય સમાપ્ત થયો."),
|
||||
("Incoming connection", "આવતું કનેક્શન"),
|
||||
("Outgoing connection", "જતું કનેક્શન"),
|
||||
("Exit", "બહાર નીકળો"),
|
||||
("Open", "ખોલો"),
|
||||
("logout_tip", "શું તમે ખરેખર લોગઆઉટ કરવા માંગો છો?"),
|
||||
("Service", "સેવા"),
|
||||
("Start", "શરૂ કરો"),
|
||||
("Stop", "બંધ કરો"),
|
||||
("exceed_max_devices", "તમે ઉપકરણોની મહત્તમ મર્યાદા વટાવી દીધી છે."),
|
||||
("Sync with recent sessions", "તાજેતરના સત્રો સાથે સિંક કરો"),
|
||||
("Sort tags", "ટેગ્સ ક્રમબદ્ધ કરો"),
|
||||
("Open connection in new tab", "નવી ટેબમાં કનેક્શન ખોલો"),
|
||||
("Move tab to new window", "ટેબને નવી વિન્ડોમાં ખસેડો"),
|
||||
("Can not be empty", "ખાલી ન હોઈ શકે"),
|
||||
("Already exists", "પહેલેથી અસ્તિત્વમાં છે"),
|
||||
("Change Password", "પાસવર્ડ બદલો"),
|
||||
("Refresh Password", "પાસવર્ડ રિફ્રેશ કરો"),
|
||||
("ID", "ID"),
|
||||
("Grid View", "ગ્રીડ વ્યુ"),
|
||||
("List View", "લિસ્ટ વ્યુ"),
|
||||
("Select", "પસંદ કરો"),
|
||||
("Toggle Tags", "ટેગ્સ ચાલુ/બંધ કરો"),
|
||||
("pull_ab_failed_tip", "એડ્રેસ બુક અપડેટ કરવામાં નિષ્ફળ."),
|
||||
("push_ab_failed_tip", "એડ્રેસ બુક સિંક કરવામાં નિષ્ફળ."),
|
||||
("synced_peer_readded_tip", "તાજેતરના સત્રોના ઉપકરણો એડ્રેસ બુકમાં સિંક થયા."),
|
||||
("Change Color", "રંગ બદલો"),
|
||||
("Primary Color", "પ્રાથમિક રંગ"),
|
||||
("HSV Color", "HSV રંગ"),
|
||||
("Installation Successful!", "ઇન્સ્ટોલેશન સફળ!"),
|
||||
("Installation failed!", "ઇન્સ્ટોલેશન નિષ્ફળ!"),
|
||||
("Reverse mouse wheel", "માઉસ વ્હીલ ઊલટું કરો"),
|
||||
("{} sessions", "{} સત્રો"),
|
||||
("scam_title", "છેતરપિંડીની ચેતવણી!"),
|
||||
("scam_text1", "જો તમે અજાણી વ્યક્તિ સાથે વાત કરી રહ્યા હો અને તેણે RustDesk વાપરવા કહ્યું હોય, તો તરત ડિસ્કનેક્ટ કરો."),
|
||||
("scam_text2", "આ એક છેતરપિંડી હોઈ શકે છે. કોઈને પાસવર્ડ આપશો નહીં."),
|
||||
("Don't show again", "ફરીથી ના બતાવશો"),
|
||||
("I Agree", "હું સહમત છું"),
|
||||
("Decline", "અસ્વીકાર"),
|
||||
("Timeout in minutes", "મિનિટોમાં ટાઇમઆઉટ"),
|
||||
("auto_disconnect_option_tip", "નિષ્ક્રિયતા પર આપમેળે ડિસ્કનેક્ટ કરો"),
|
||||
("Connection failed due to inactivity", "નિષ્ક્રિયતાને કારણે કનેક્શન નિષ્ફળ"),
|
||||
("Check for software update on startup", "શરૂઆતમાં અપડેટ તપાસો"),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", "સર્વર પ્રો ને {} માં અપગ્રેડ કરો"),
|
||||
("pull_group_failed_tip", "ગ્રુપ ખેંચવામાં (Pull) નિષ્ફળ"),
|
||||
("Filter by intersection", "ઇન્ટરસેક્શન દ્વારા ફિલ્ટર કરો"),
|
||||
("Remove wallpaper during incoming sessions", "કનેક્શન દરમિયાન વોલપેપર હટાવો"),
|
||||
("Test", "ટેસ્ટ"),
|
||||
("display_is_plugged_out_msg", "ડિસ્પ્લે કાઢી નાખવામાં આવ્યું છે."),
|
||||
("No displays", "કોઈ ડિસ્પ્લે નથી"),
|
||||
("Open in new window", "નવી વિન્ડોમાં ખોલો"),
|
||||
("Show displays as individual windows", "દરેક ડિસ્પ્લે અલગ વિન્ડોમાં બતાવો"),
|
||||
("Use all my displays for the remote session", "તમામ ડિસ્પ્લેનો ઉપયોગ કરો"),
|
||||
("selinux_tip", "SELinux ઉપકરણ પર સક્ષમ છે."),
|
||||
("Change view", "વ્યુ બદલો"),
|
||||
("Big tiles", "મોટી ટાઇલ્સ"),
|
||||
("Small tiles", "નાની ટાઇલ્સ"),
|
||||
("List", "લિસ્ટ"),
|
||||
("Virtual display", "વર્ચ્યુઅલ ડિસ્પ્લે"),
|
||||
("Plug out all", "બધું કાઢી નાખો (Plug out)"),
|
||||
("True color (4:4:4)", "ટ્રુ કલર (4:4:4)"),
|
||||
("Enable blocking user input", "યુઝર ઇનપુટ બ્લોકિંગ સક્ષમ કરો"),
|
||||
("id_input_tip", "તમે ID, Alias અથવા IP એડ્રેસ દાખલ કરી શકો છો."),
|
||||
("privacy_mode_impl_mag_tip", "મેગ્નિફાયર પ્રાઇવસી મોડ"),
|
||||
("privacy_mode_impl_virtual_display_tip", "વર્ચ્યુઅલ ડિસ્પ્લે પ્રાઇવસી મોડ"),
|
||||
("Enter privacy mode", "પ્રાઇવસી મોડમાં પ્રવેશ કરો"),
|
||||
("Exit privacy mode", "પ્રાઇવસી મોડમાંથી બહાર નીકળો"),
|
||||
("idd_not_support_under_win10_2004_tip", "વર્ચ્યુઅલ ડિસ્પ્લે Windows 10 (2004) કે તેથી ઉપર જ સક્ષમ છે."),
|
||||
("input_source_1_tip", "ઇનપુટ સ્ત્રોત ૧"),
|
||||
("input_source_2_tip", "ઇનપુટ સ્ત્રોત ૨"),
|
||||
("Swap control-command key", "Control અને Command કી બદલો"),
|
||||
("swap-left-right-mouse", "ડાબું અને જમણું માઉસ બટન બદલો"),
|
||||
("2FA code", "2FA કોડ"),
|
||||
("More", "વધારે"),
|
||||
("enable-2fa-title", "2FA સક્ષમ કરો"),
|
||||
("enable-2fa-desc", "તમારું ઓથેન્ટિકેટર એપ સેટ કરો."),
|
||||
("wrong-2fa-code", "ખોટો 2FA કોડ."),
|
||||
("enter-2fa-title", "2FA કોડ દાખલ કરો"),
|
||||
("Email verification code must be 6 characters.", "ઇમેઇલ કોડ 6 અક્ષરનો હોવો જોઈએ."),
|
||||
("2FA code must be 6 digits.", "2FA કોડ 6 અંકનો હોવો જોઈએ."),
|
||||
("Multiple Windows sessions found", "બહુવિધ Windows સત્રો મળ્યા"),
|
||||
("Please select the session you want to connect to", "કૃપા કરીને જે સત્ર સાથે જોડાવું હોય તે પસંદ કરો"),
|
||||
("powered_by_me", "મારા દ્વારા સંચાલિત"),
|
||||
("outgoing_only_desk_tip", "આ માત્ર આઉટગોઇંગ મોડ છે"),
|
||||
("preset_password_warning", "સુરક્ષા માટે પાસવર્ડ બદલો."),
|
||||
("Security Alert", "સુરક્ષા ચેતવણી"),
|
||||
("My address book", "મારી એડ્રેસ બુક"),
|
||||
("Personal", "વ્યક્તિગત"),
|
||||
("Owner", "માલિક"),
|
||||
("Set shared password", "શેર કરેલ પાસવર્ડ સેટ કરો"),
|
||||
("Exist in", "માં અસ્તિત્વ ધરાવે છે"),
|
||||
("Read-only", "માત્ર વાંચવા માટે"),
|
||||
("Read/Write", "વાંચવા/લખવા માટે"),
|
||||
("Full Control", "પૂર્ણ નિયંત્રણ"),
|
||||
("share_warning_tip", "તમે તમારો એક્સેસ શેર કરી રહ્યા છો."),
|
||||
("Everyone", "દરેક વ્યક્તિ"),
|
||||
("ab_web_console_tip", "વેબ કન્સોલ એડ્રેસ બુક"),
|
||||
("allow-only-conn-window-open-tip", "માત્ર RustDesk વિન્ડો ખુલ્લી હોય ત્યારે જ કનેક્શનની મંજૂરી આપો"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "ભૌતિક ડિસ્પ્લે નથી, પ્રાઇવસી મોડની જરૂર નથી."),
|
||||
("Follow remote cursor", "રિમોટ કર્સરને અનુસરો"),
|
||||
("Follow remote window focus", "રિમોટ વિન્ડો ફોકસને અનુસરો"),
|
||||
("default_proxy_tip", "ડિફોલ્ટ પ્રોક્સી સેટિંગ"),
|
||||
("no_audio_input_device_tip", "કોઈ ઓડિયો ઇનપુટ મળ્યું નથી."),
|
||||
("Incoming", "આવતું"),
|
||||
("Outgoing", "જતું"),
|
||||
("Clear Wayland screen selection", "Wayland સ્ક્રીન સિલેક્શન સાફ કરો"),
|
||||
("clear_Wayland_screen_selection_tip", "સ્ક્રીન સિલેક્શન રીસેટ કરો."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "શું તમે સિલેક્શન સાફ કરવા માંગો છો?"),
|
||||
("android_new_voice_call_tip", "નવો વોઇસ કોલ વિનંતી"),
|
||||
("texture_render_tip", "ટેક્સચર રેન્ડરિંગ વાપરો"),
|
||||
("Use texture rendering", "ટેક્સચર રેન્ડરિંગનો ઉપયોગ કરો"),
|
||||
("Floating window", "ફ્લોટિંગ વિન્ડો"),
|
||||
("floating_window_tip", "બેકગ્રાઉન્ડમાં હોય ત્યારે RustDesk બતાવો"),
|
||||
("Keep screen on", "સ્ક્રીન ચાલુ રાખો"),
|
||||
("Never", "ક્યારેય નહીં"),
|
||||
("During controlled", "નિયંત્રણ દરમિયાન"),
|
||||
("During service is on", "જ્યારે સેવા ચાલુ હોય ત્યારે"),
|
||||
("Capture screen using DirectX", "DirectX દ્વારા સ્ક્રીન કેપ્ચર કરો"),
|
||||
("Back", "પાછળ"),
|
||||
("Apps", "એપ્સ"),
|
||||
("Volume up", "અવાજ વધારો"),
|
||||
("Volume down", "અવાજ ઘટાડો"),
|
||||
("Power", "પાવર"),
|
||||
("Telegram bot", "Telegram બોટ"),
|
||||
("enable-bot-tip", "સૂચનાઓ માટે બોટ સક્ષમ કરો"),
|
||||
("enable-bot-desc", "સૂચનાઓ માટે ટેલિગ્રામ બોટ સેટ કરો."),
|
||||
("cancel-2fa-confirm-tip", "શું તમે 2FA રદ કરવા માંગો છો?"),
|
||||
("cancel-bot-confirm-tip", "શું તમે બોટ રદ કરવા માંગો છો?"),
|
||||
("About RustDesk", "RustDesk વિશે"),
|
||||
("Send clipboard keystrokes", "ક્લિપબોર્ડ કી-સ્ટ્રોક્સ મોકલો"),
|
||||
("network_error_tip", "નેટવર્ક ભૂલ, ફરી પ્રયાસ કરો."),
|
||||
("Unlock with PIN", "PIN થી અનલોક કરો"),
|
||||
("Requires at least {} characters", "ઓછામાં ઓછા {} અક્ષર જરૂરી"),
|
||||
("Wrong PIN", "ખોટો PIN"),
|
||||
("Set PIN", "PIN સેટ કરો"),
|
||||
("Enable trusted devices", "વિશ્વાસપાત્ર ઉપકરણો સક્ષમ કરો"),
|
||||
("Manage trusted devices", "વિશ્વાસપાત્ર ઉપકરણો સંચાલિત કરો"),
|
||||
("Platform", "પ્લેટફોર્મ"),
|
||||
("Days remaining", "બાકી દિવસો"),
|
||||
("enable-trusted-devices-tip", "માત્ર વિશ્વાસપાત્ર ઉપકરણો જ પાસવર્ડ વગર જોડાઈ શકે"),
|
||||
("Parent directory", "પેરન્ટ ડિરેક્ટરી"),
|
||||
("Resume", "ફરી શરૂ કરો"),
|
||||
("Invalid file name", "અમાન્ય ફાઇલ નામ"),
|
||||
("one-way-file-transfer-tip", "માત્ર એકતરફી ફાઇલ ટ્રાન્સફરની મંજૂરી છે"),
|
||||
("Authentication Required", "ઓથેન્ટિકેશન જરૂરી"),
|
||||
("Authenticate", "ઓથેન્ટિકેટ કરો"),
|
||||
("web_id_input_tip", "રિમોટ ID દાખલ કરો"),
|
||||
("Download", "ડાઉનલોડ"),
|
||||
("Upload folder", "ફોલ્ડર અપલોડ કરો"),
|
||||
("Upload files", "ફાઇલો અપલોડ કરો"),
|
||||
("Clipboard is synchronized", "ક્લિપબોર્ડ સિંક થયેલ છે"),
|
||||
("Update client clipboard", "ક્લાયન્ટ ક્લિપબોર્ડ અપડેટ કરો"),
|
||||
("Untagged", "ટેગ વગરનું"),
|
||||
("new-version-of-{}-tip", "{} નું નવું વર્ઝન ઉપલબ્ધ છે"),
|
||||
("Accessible devices", "એક્સેસિબલ ઉપકરણો"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "રિમોટ ક્લાયન્ટને {} માં અપગ્રેડ કરો"),
|
||||
("d3d_render_tip", "D3D રેન્ડરિંગ વાપરો"),
|
||||
("Printer", "પ્રિન્ટર"),
|
||||
("printer-os-requirement-tip", "પ્રિન્ટિંગ માટે Windows જરૂરી છે."),
|
||||
("printer-requires-installed-{}-client-tip", "આ માટે {} ક્લાયન્ટ ઇન્સ્ટોલ હોવું જોઈએ."),
|
||||
("printer-{}-not-installed-tip", "પ્રિન્ટર {} ઇન્સ્ટોલ નથી."),
|
||||
("printer-{}-ready-tip", "પ્રિન્ટર {} તૈયાર છે."),
|
||||
("Install {} Printer", "{} પ્રિન્ટર ઇન્સ્ટોલ કરો"),
|
||||
("Outgoing Print Jobs", "જતા પ્રિન્ટ કાર્યો"),
|
||||
("Incoming Print Jobs", "આવતા પ્રિન્ટ કાર્યો"),
|
||||
("Incoming Print Job", "આવતું પ્રિન્ટ કાર્ય"),
|
||||
("use-the-default-printer-tip", "ડિફોલ્ટ પ્રિન્ટર વાપરો"),
|
||||
("use-the-selected-printer-tip", "પસંદ કરેલ પ્રિન્ટર વાપરો"),
|
||||
("auto-print-tip", "આપમેળે પ્રિન્ટ કરો"),
|
||||
("print-incoming-job-confirm-tip", "પ્રિન્ટ કરતા પહેલા પુષ્ટિ કરો"),
|
||||
("remote-printing-disallowed-tile-tip", "રિમોટ પ્રિન્ટિંગની મંજૂરી નથી"),
|
||||
("remote-printing-disallowed-text-tip", "સેટિંગ્સમાં રિમોટ પ્રિન્ટિંગ સક્ષમ કરો."),
|
||||
("save-settings-tip", "સેટિંગ્સ સાચવો"),
|
||||
("dont-show-again-tip", "ફરીથી ના બતાવશો"),
|
||||
("Take screenshot", "સ્ક્રીનશોટ લો"),
|
||||
("Taking screenshot", "સ્ક્રીનશોટ લેવાઈ રહ્યો છે"),
|
||||
("screenshot-merged-screen-not-supported-tip", "મર્જ કરેલ સ્ક્રીનશોટ સપોર્ટેડ નથી."),
|
||||
("screenshot-action-tip", "સ્ક્રીનશોટ પછીની ક્રિયા"),
|
||||
("Save as", "તરીકે સાચવો"),
|
||||
("Copy to clipboard", "ક્લિપબોર્ડમાં કોપી કરો"),
|
||||
("Enable remote printer", "રિમોટ પ્રિન્ટર સક્ષમ કરો"),
|
||||
("Downloading {}", "{} ડાઉનલોડ થઈ રહ્યું છે"),
|
||||
("{} Update", "{} અપડેટ"),
|
||||
("{}-to-update-tip", "અપડેટ કરવા માટે {}"),
|
||||
("download-new-version-failed-tip", "નવું વર્ઝન ડાઉનલોડ કરવામાં નિષ્ફળ."),
|
||||
("Auto update", "ઓટો અપડેટ"),
|
||||
("update-failed-check-msi-tip", "અપડેટ નિષ્ફળ, MSI ફાઇલ તપાસો."),
|
||||
("websocket_tip", "જો પોર્ટ બ્લોક હોય તો WebSocket વાપરો."),
|
||||
("Use WebSocket", "WebSocket નો ઉપયોગ કરો"),
|
||||
("Trackpad speed", "ટ્રેકપેડ સ્પીડ"),
|
||||
("Default trackpad speed", "ડિફોલ્ટ ટ્રેકપેડ સ્પીડ"),
|
||||
("Numeric one-time password", "ન્યુમેરિક OTP"),
|
||||
("Enable IPv6 P2P connection", "IPv6 P2P કનેક્શન સક્ષમ કરો"),
|
||||
("Enable UDP hole punching", "UDP હોલ પંચિંગ સક્ષમ કરો"),
|
||||
("View camera", "કેમેરા જુઓ"),
|
||||
("Enable camera", "કેમેરા સક્ષમ કરો"),
|
||||
("No cameras", "કોઈ કેમેરા મળ્યો નથી"),
|
||||
("view_camera_unsupported_tip", "રિમોટ કેમેરા સપોર્ટેડ નથી."),
|
||||
("Terminal", "ટર્મિનલ"),
|
||||
("Enable terminal", "ટર્મિનલ સક્ષમ કરો"),
|
||||
("New tab", "નવી ટેબ"),
|
||||
("Keep terminal sessions on disconnect", "ડિસ્કનેક્ટ વખતે ટર્મિનલ ચાલુ રાખો"),
|
||||
("Terminal (Run as administrator)", "ટર્મિનલ (એડમિનિસ્ટ્રેટર તરીકે)"),
|
||||
("terminal-admin-login-tip", "એડમિન લોગિન જરૂરી છે."),
|
||||
("Failed to get user token.", "યુઝર ટોકન મેળવવામાં નિષ્ફળ."),
|
||||
("Incorrect username or password.", "ખોટું યુઝરનેમ કે પાસવર્ડ."),
|
||||
("The user is not an administrator.", "યુઝર એડમિનિસ્ટ્રેટર નથી."),
|
||||
("Failed to check if the user is an administrator.", "યુઝર એડમિન છે કે નહીં તે ચકાસવામાં નિષ્ફળ."),
|
||||
("Supported only in the installed version.", "માત્ર ઇન્સ્ટોલ કરેલ વર્ઝનમાં ઉપલબ્ધ."),
|
||||
("elevation_username_tip", "એડમિનિસ્ટ્રેટર નામ દાખલ કરો"),
|
||||
("Preparing for installation ...", "ઇન્સ્ટોલેશનની તૈયારી..."),
|
||||
("Show my cursor", "મારું કર્સર બતાવો"),
|
||||
("Scale custom", "કસ્ટમ સ્કેલ"),
|
||||
("Custom scale slider", "કસ્ટમ સ્કેલ સ્લાઇડર"),
|
||||
("Decrease", "ઘટાડો"),
|
||||
("Increase", "વધારો"),
|
||||
("Show virtual mouse", "વર્ચ્યુઅલ માઉસ બતાવો"),
|
||||
("Virtual mouse size", "વર્ચ્યુઅલ માઉસ કદ"),
|
||||
("Small", "નાનું"),
|
||||
("Large", "મોટું"),
|
||||
("Show virtual joystick", "વર્ચ્યુઅલ જોયસ્ટિક બતાવો"),
|
||||
("Edit note", "નોંધ સુધારો"),
|
||||
("Alias", "Alias (ઉપનામ)"),
|
||||
("ScrollEdge", "સ્ક્રોલ એજ"),
|
||||
("Allow insecure TLS fallback", "અસુરક્ષિત TLS ફોલબેકની મંજૂરી આપો"),
|
||||
("allow-insecure-tls-fallback-tip", "જૂના સર્વર માટે વાપરો."),
|
||||
("Disable UDP", "UDP અક્ષમ કરો"),
|
||||
("disable-udp-tip", "કનેક્શન સમસ્યાઓ માટે UDP બંધ કરો."),
|
||||
("server-oss-not-support-tip", "OSS સર્વર આને સપોર્ટ કરતું નથી."),
|
||||
("input note here", "અહીં નોંધ લખો"),
|
||||
("note-at-conn-end-tip", "કનેક્શનના અંતે નોંધ બતાવો"),
|
||||
("Show terminal extra keys", "ટર્મિનલની વધારાની કી બતાવો"),
|
||||
("Relative mouse mode", "રીલેટિવ માઉસ મોડ"),
|
||||
("rel-mouse-not-supported-peer-tip", "સામેથી સપોર્ટેડ નથી."),
|
||||
("rel-mouse-not-ready-tip", "તૈયાર નથી."),
|
||||
("rel-mouse-lock-failed-tip", "માઉસ લોક નિષ્ફળ."),
|
||||
("rel-mouse-exit-{}-tip", "બહાર નીકળવા {} દબાવો"),
|
||||
("rel-mouse-permission-lost-tip", "પરવાનગી ગુમાવી દીધી."),
|
||||
("Changelog", "Changelog (ફેરફારો)"),
|
||||
("keep-awake-during-outgoing-sessions-label", "આઉટગોઇંગ સત્ર વખતે જાગૃત રાખો"),
|
||||
("keep-awake-during-incoming-sessions-label", "ઇનકમિંગ સત્ર વખતે જાગૃત રાખો"),
|
||||
("Continue with {}", "{} સાથે આગળ વધો"),
|
||||
("Display Name", "ડિસ્પ્લે નામ"),
|
||||
("password-hidden-tip", "સુરક્ષા માટે પાસવર્ડ છુપાવેલ છે."),
|
||||
("preset-password-in-use-tip", "પ્રીસેટ પાસવર્ડ વપરાશમાં છે."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "הגדרות מקלדת"),
|
||||
("Full Access", "גישה מלאה"),
|
||||
("Screen Share", "שיתוף מסך"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland דורש Ubuntu 21.04 או גרסה גבוהה יותר"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland דורש גרסת הפצת לינוקס גבוהה יותר. אנא נסה שולחן עבודה מסוג X11 או החלף מערכת הפעלה"),
|
||||
("ubuntu-21-04-required", "Wayland דורש Ubuntu 21.04 או גרסה גבוהה יותר"),
|
||||
("wayland-requires-higher-linux-version", "Wayland דורש גרסת הפצת לינוקס גבוהה יותר. אנא נסה שולחן עבודה מסוג X11 או החלף מערכת הפעלה"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "קישור מהיר"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "אנא בחר את המסך לשיתוף (פעולה בצד העמית)."),
|
||||
("Show RustDesk", "הצג את RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "המשך עם {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Postavke tipkovnice"),
|
||||
("Full Access", "Potpuni pristup"),
|
||||
("Screen Share", "Dijeljenje zaslona"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland zahtijeva Ubuntu verziju 21.04 ili višu"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland zahtijeva višu verziju Linux distribucije. Molimo isprobjate X11 ili promijenite OS."),
|
||||
("ubuntu-21-04-required", "Wayland zahtijeva Ubuntu verziju 21.04 ili višu"),
|
||||
("wayland-requires-higher-linux-version", "Wayland zahtijeva višu verziju Linux distribucije. Molimo isprobjate X11 ili promijenite OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Vidi"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Molimo odaberite zaslon koji će biti podijeljen (Za rad na strani klijenta)"),
|
||||
("Show RustDesk", "Prikaži RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Nastavi sa {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("ID Server", "ID-kiszolgáló"),
|
||||
("Relay Server", "Továbbító-kiszolgáló"),
|
||||
("API Server", "API-kiszolgáló"),
|
||||
("invalid_http", "A címnek mindenképpen http(s)://-el kell kezdődnie."),
|
||||
("invalid_http", "A címnek mindenképpen http(s)://-rel kell kezdődnie."),
|
||||
("Invalid IP", "A megadott IP-cím érvénytelen"),
|
||||
("Invalid format", "Érvénytelen formátum"),
|
||||
("server_not_support", "A kiszolgáló nem támogatja"),
|
||||
|
|
@ -149,7 +149,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Click to upgrade", "Kattintson ide a frissítés telepítéséhez"),
|
||||
("Configure", "Beállítás"),
|
||||
("config_acc", "A számítógép távoli vezérléséhez a RustDesknek hozzáférési jogokat kell adnia."),
|
||||
("config_screen", "Ahhoz, hogy távolról hozzáférhessen a számítógépéhez, meg kell adnia a RustDesknek a \"Képernyőfelvétel\" jogosultságot."),
|
||||
("config_screen", "Ahhoz, hogy távolról hozzáférhessen a számítógépéhez, meg kell adnia a RustDesknek a „Képernyőfelvétel” jogosultságot."),
|
||||
("Installing ...", "Telepítés ..."),
|
||||
("Install", "Telepítse"),
|
||||
("Installation", "Telepítés"),
|
||||
|
|
@ -276,13 +276,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Do you accept?", "Elfogadás?"),
|
||||
("Open System Setting", "Rendszerbeállítások megnyitása"),
|
||||
("How to get Android input permission?", "Hogyan állítható be az Androidos beviteli engedély?"),
|
||||
("android_input_permission_tip1", "Ahhoz, hogy egy távoli eszköz vezérelhesse Android készülékét, engedélyeznie kell a RustDesk számára a \"Hozzáférhetőség\" szolgáltatás használatát."),
|
||||
("android_input_permission_tip2", "A következő rendszerbeállítások oldalon a letöltött alkalmazások menüponton belül, kapcsolja be a [RustDesk Input] szolgáltatást."),
|
||||
("android_input_permission_tip1", "Ahhoz, hogy egy távoli eszköz vezérelhesse Android készülékét, engedélyeznie kell a RustDesk számára a „Hozzáférhetőség” szolgáltatás használatát."),
|
||||
("android_input_permission_tip2", "A következő rendszerbeállítások oldalon a letöltött alkalmazások menüponton belül, kapcsolja be a „RustDesk Input” szolgáltatást."),
|
||||
("android_new_connection_tip", "Új kérés érkezett, mely vezérelni szeretné az eszközét"),
|
||||
("android_service_will_start_tip", "A képernyőmegosztás aktiválása automatikusan elindítja a szolgáltatást, így más eszközök is vezérelhetik ezt az Android-eszközt."),
|
||||
("android_stop_service_tip", "A szolgáltatás leállítása automatikusan szétkapcsol minden létező kapcsolatot."),
|
||||
("android_version_audio_tip", "A jelenlegi Android verzió nem támogatja a hangrögzítést, frissítsen legalább Android 10-re, vagy egy újabb verzióra."),
|
||||
("android_start_service_tip", "A képernyőmegosztó szolgáltatás elindításához koppintson a \"Kapcsolási szolgáltatás indítása\" gombra, vagy aktiválja a \"Képernyőfelvétel\" engedélyt."),
|
||||
("android_start_service_tip", "A képernyőmegosztó szolgáltatás elindításához koppintson a „Kapcsolási szolgáltatás indítása” gombra, vagy aktiválja a „Képernyőfelvétel” engedélyt."),
|
||||
("android_permission_may_not_change_tip", "A meglévő kapcsolatok engedélyei csak új kapcsolódás után módosulnak."),
|
||||
("Account", "Fiók"),
|
||||
("Overwrite", "Felülírás"),
|
||||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Billentyűzetbeállítások"),
|
||||
("Full Access", "Teljes hozzáférés"),
|
||||
("Screen Share", "Képernyőmegosztás"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "A Waylandhez Ubuntu 21.04 vagy újabb verzió szükséges."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "A Wayland a Linux disztribúció magasabb verzióját igényli. Próbálja ki az X11 asztali környezetet, vagy változtassa meg az operációs rendszert."),
|
||||
("ubuntu-21-04-required", "A Waylandhez Ubuntu 21.04 vagy újabb verzió szükséges."),
|
||||
("wayland-requires-higher-linux-version", "A Wayland a Linux disztribúció magasabb verzióját igényli. Próbálja ki az X11 asztali környezetet, vagy változtassa meg az operációs rendszert."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Hiperhivatkozás"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Válassza ki a megosztani kívánt képernyőt."),
|
||||
("Show RustDesk", "A RustDesk megjelenítése"),
|
||||
|
|
@ -407,15 +408,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Select local keyboard type", "Helyi billentyűzet típusának kiválasztása"),
|
||||
("software_render_tip", "Ha Nvidia grafikus kártyát használ Linux alatt, és a távoli ablak a kapcsolat létrehozása után azonnal bezáródik, akkor a Nouveau nyílt forráskódú illesztőprogramra való váltás és a szoftveres leképezés alkalmazása segíthet. A szoftvert újra kell indítani."),
|
||||
("Always use software rendering", "Mindig szoftveres leképezést használjon"),
|
||||
("config_input", "Ahhoz, hogy a távoli asztalt a billentyűzettel vezérelhesse, a RustDesknek meg kell adnia a \"Bemenet figyelése\" jogosultságot."),
|
||||
("config_microphone", "Ahhoz, hogy távolról beszélhessen, meg kell adnia a RustDesknek a \"Hangfelvétel\" jogosultságot."),
|
||||
("config_input", "Ahhoz, hogy a távoli asztalt a billentyűzettel vezérelhesse, a RustDesknek meg kell adnia a „Bemenet figyelése” jogosultságot."),
|
||||
("config_microphone", "Ahhoz, hogy távolról beszélhessen, meg kell adnia a RustDesknek a „Hangfelvétel” jogosultságot."),
|
||||
("request_elevation_tip", "Akkor is kérhet megnövelt jogokat, ha valaki a partneroldalon van."),
|
||||
("Wait", "Várjon"),
|
||||
("Elevation Error", "Emelt szintű hozzáférési hiba"),
|
||||
("Ask the remote user for authentication", "Hitelesítés kérése a távoli felhasználótól"),
|
||||
("Choose this if the remote account is administrator", "Akkor válassza ezt, ha a távoli fiók rendszergazda"),
|
||||
("Transmit the username and password of administrator", "Küldje el a rendszergazda felhasználónevét és jelszavát"),
|
||||
("still_click_uac_tip", "A távoli felhasználónak továbbra is az \"Igen\" gombra kell kattintania a RustDesk UAC ablakában. Kattintson!"),
|
||||
("still_click_uac_tip", "A távoli felhasználónak továbbra is az „Igen” gombra kell kattintania a RustDesk UAC ablakában. Kattintson!"),
|
||||
("Request Elevation", "Emelt szintű jogok igénylése"),
|
||||
("wait_accept_uac_tip", "Várjon, amíg a távoli felhasználó elfogadja az UAC párbeszédet."),
|
||||
("Elevate successfully", "Emelt szintű jogok megadva"),
|
||||
|
|
@ -441,7 +442,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Voice call", "Hanghívás"),
|
||||
("Text chat", "Szöveges csevegés"),
|
||||
("Stop voice call", "Hanghívás leállítása"),
|
||||
("relay_hint_tip", "Ha a közvetlen kapcsolat nem lehetséges, megpróbálhat kapcsolatot létesíteni egy továbbító-kiszolgálón keresztül.\nHa az első próbálkozáskor továbbító-kiszolgálón keresztüli kapcsolatot szeretne létrehozni, használhatja az \"/r\" utótagot. Az azonosítóhoz vagy a \"Mindig továbbító-kiszolgálón keresztül kapcsolódom\" opcióhoz a legutóbbi munkamenetek listájában, ha van ilyen."),
|
||||
("relay_hint_tip", "Ha a közvetlen kapcsolat nem lehetséges, megpróbálhat kapcsolatot létesíteni egy továbbító-kiszolgálón keresztül.\nHa az első próbálkozáskor továbbító-kiszolgálón keresztüli kapcsolatot szeretne létrehozni, használhatja az „/r” utótagot. Az azonosítóhoz vagy a „Mindig továbbító-kiszolgálón keresztül kapcsolódom” opcióhoz a legutóbbi munkamenetek listájában, ha van ilyen."),
|
||||
("Reconnect", "Újrakapcsolódás"),
|
||||
("Codec", "Kodek"),
|
||||
("Resolution", "Felbontás"),
|
||||
|
|
@ -558,7 +559,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Plug out all", "Kapcsolja ki az összeset"),
|
||||
("True color (4:4:4)", "Valódi szín (4:4:4)"),
|
||||
("Enable blocking user input", "Engedélyezze a felhasználói bevitel blokkolását"),
|
||||
("id_input_tip", "Megadhat egy azonosítót, egy közvetlen IP-címet vagy egy tartományt egy porttal (<domain>:<port>).\nHa egy másik kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a kiszolgáló címét (<id>@<kiszolgáló_cím>?key=<key_value>), például\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nHa egy nyilvános kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a \"<id>@public\" lehetőséget. A kulcsra nincs szükség nyilvános kiszolgálók esetén.\n\nHa az első kapcsolathoz továbbító-kiszolgálón keresztüli kapcsolatot akar kényszeríteni, adja hozzá az \"/r\" az azonosítót a végén, például \"9123456234/r\"."),
|
||||
("id_input_tip", "Megadhat egy azonosítót, egy közvetlen IP-címet vagy egy tartományt egy porttal (<domain>:<port>).\nHa egy másik kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a kiszolgáló címét (<id>@<kiszolgáló_cím>?key=<key_value>), például\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nHa egy nyilvános kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a „<id>@public” lehetőséget. A kulcsra nincs szükség nyilvános kiszolgálók esetén.\n\nHa az első kapcsolathoz továbbító-kiszolgálón keresztüli kapcsolatot akar kényszeríteni, adja hozzá az „/r” az azonosítót a végén, például „9123456234/r”."),
|
||||
("privacy_mode_impl_mag_tip", "1. mód"),
|
||||
("privacy_mode_impl_virtual_display_tip", "2. mód"),
|
||||
("Enter privacy mode", "Lépjen be az adatvédelmi módba"),
|
||||
|
|
@ -621,7 +622,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Power", "Főkapcsoló"),
|
||||
("Telegram bot", "Telegram bot"),
|
||||
("enable-bot-tip", "Ha aktiválja ezt a funkciót, akkor a 2FA-kódot a botjától kaphatja meg. Kapcsolati értesítésként is használható."),
|
||||
("enable-bot-desc", "1. Nyisson csevegést @BotFather.\n2. Küldje el a \"/newbot\" parancsot. Miután ezt a lépést elvégezte, kap egy tokent.\n3. Indítson csevegést az újonnan létrehozott botjával. Küldjön egy olyan üzenetet, amely egy perjel (\"/\") kezdetű, pl. \"/hello\" az aktiváláshoz.\n"),
|
||||
("enable-bot-desc", "1. Nyisson csevegést @BotFather.\n2. Küldje el a „/newbot” parancsot. Miután ezt a lépést elvégezte, kap egy tokent.\n3. Indítson csevegést az újonnan létrehozott botjával. Küldjön egy olyan üzenetet, amely egy perjel („/”) kezdetű, pl. „/hello” az aktiváláshoz.\n"),
|
||||
("cancel-2fa-confirm-tip", "Biztosan vissza akarja vonni a 2FA-hitelesítést?"),
|
||||
("cancel-bot-confirm-tip", "Biztosan le akarja mondani a Telegram botot?"),
|
||||
("About RustDesk", "A RustDesk névjegye"),
|
||||
|
|
@ -642,7 +643,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("one-way-file-transfer-tip", "Az egyirányú fájlátvitel engedélyezve van a vezérelt oldalon."),
|
||||
("Authentication Required", "Hitelesítés szükséges"),
|
||||
("Authenticate", "Hitelesítés"),
|
||||
("web_id_input_tip", "Azonos kiszolgálón lévő azonosítót adhat meg, a közvetlen IP elérés nem támogatott a webkliensben.\nHa egy másik kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a kiszolgáló címét (<id>@<kiszolgáló_cím>?key=<key_value>), például\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nHa egy nyilvános kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a \"<id>@public\" betűt. A kulcsra nincs szükség a nyilvános kiszolgálók esetében."),
|
||||
("web_id_input_tip", "Azonos kiszolgálón lévő azonosítót adhat meg, a közvetlen IP elérés nem támogatott a webkliensben.\nHa egy másik kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg a kiszolgáló címét (<id>@<kiszolgáló_cím>?key=<key_value>), például\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nHa egy nyilvános kiszolgálón lévő eszközhöz szeretne hozzáférni, adja meg az „<id>@public” kulcsot. A kulcsra nincs szükség a nyilvános kiszolgálók esetében."),
|
||||
("Download", "Letöltés"),
|
||||
("Upload folder", "Mappa feltöltése"),
|
||||
("Upload files", "Fájlok feltöltése"),
|
||||
|
|
@ -681,9 +682,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Downloading {}", "{} letöltése"),
|
||||
("{} Update", "{} frissítés"),
|
||||
("{}-to-update-tip", "{} bezárása és az új verzió telepítése."),
|
||||
("download-new-version-failed-tip", "Ha a letöltés sikertelen, akkor vagy újrapróbálkozhat, vagy a \"Letöltés\" gombra kattintva letöltheti a kiadási oldalról, és manuálisan frissíthet."),
|
||||
("download-new-version-failed-tip", "Ha a letöltés sikertelen, akkor vagy újrapróbálkozhat, vagy a „Letöltés” gombra kattintva letöltheti a kiadási oldalról, és manuálisan frissíthet."),
|
||||
("Auto update", "Automatikus frissítés"),
|
||||
("update-failed-check-msi-tip", "A telepítési módszer felismerése nem sikerült. Kattintson a \"Letöltés\" gombra, hogy letöltse a kiadási oldalról, és manuálisan frissítse."),
|
||||
("update-failed-check-msi-tip", "A telepítési módszer felismerése nem sikerült. Kattintson a „Letöltés” gombra, hogy letöltse a kiadási oldalról, és manuálisan frissítse."),
|
||||
("websocket_tip", "WebSocket használatakor csak a relé-kapcsolatok támogatottak."),
|
||||
("Use WebSocket", "WebSocket használata"),
|
||||
("Trackpad speed", "Érintőpad sebessége"),
|
||||
|
|
@ -738,5 +739,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Changelog", "Változáslista"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Képernyő aktív állapotban tartása a kimenő munkamenetek során"),
|
||||
("keep-awake-during-incoming-sessions-label", "Képernyő aktív állapotban tartása a bejövő munkamenetek során"),
|
||||
("Continue with {}", "Folytatás ezzel: {}"),
|
||||
("Display Name", "Kijelző név"),
|
||||
("password-hidden-tip", "Állandó jelszó lett beállítva (rejtett)."),
|
||||
("preset-password-in-use-tip", "Jelenleg az alapértelmezett jelszót használja."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Pengaturan Papan Ketik"),
|
||||
("Full Access", "Akses penuh"),
|
||||
("Screen Share", "Berbagi Layar"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland membutuhkan Ubuntu 21.04 atau versi yang lebih tinggi."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland membutuhkan versi distro linux yang lebih tinggi. Silakan coba desktop X11 atau ubah OS Anda."),
|
||||
("ubuntu-21-04-required", "Wayland membutuhkan Ubuntu 21.04 atau versi yang lebih tinggi."),
|
||||
("wayland-requires-higher-linux-version", "Wayland membutuhkan versi distro linux yang lebih tinggi. Silakan coba desktop X11 atau ubah OS Anda."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Tautan Cepat"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Silakan Pilih layar yang akan dibagikan kepada rekan anda."),
|
||||
("Show RustDesk", "Tampilkan RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Lanjutkan dengan {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Impostazioni tastiera"),
|
||||
("Full Access", "Accesso completo"),
|
||||
("Screen Share", "Condivisione schermo"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland richiede Ubuntu 21.04 o versione successiva."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland richiede una versione superiore della distribuzione Linux.\nProva X11 desktop o cambia il sistema operativo."),
|
||||
("ubuntu-21-04-required", "Wayland richiede Ubuntu 21.04 o versione successiva."),
|
||||
("wayland-requires-higher-linux-version", "Wayland richiede una versione superiore della distribuzione Linux.\nProva X11 desktop o cambia il sistema operativo."),
|
||||
("xdp-portal-unavailable", "Acquisizione dello schermo di Wayland non riuscita. Il portale desktop XDG potrebbe essersi bloccato o non essere disponibile. Prova a riavviarlo con `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Vai a"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Seleziona lo schermo da condividere (opera sul lato dispositivo remoto)."),
|
||||
("Show RustDesk", "Visualizza RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Mantieni lo schermo attivo durante le sessioni in ingresso"),
|
||||
("Continue with {}", "Continua con {}"),
|
||||
("Display Name", "Visualizza nome"),
|
||||
("password-hidden-tip", "È impostata una password permanente (nascosta)."),
|
||||
("preset-password-in-use-tip", "È attualmente in uso la password preimpostata."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "キーボードの設定"),
|
||||
("Full Access", "フルアクセス"),
|
||||
("Screen Share", "画面共有"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland を使用するには、Ubuntu 21.04 以降のバージョンが必要です。"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland を使用するには、より新しい Linux ディストリビューションが必要です。 X11 デスクトップを試すか、OS を変更してください。"),
|
||||
("ubuntu-21-04-required", "Wayland を使用するには、Ubuntu 21.04 以降のバージョンが必要です。"),
|
||||
("wayland-requires-higher-linux-version", "Wayland を使用するには、より新しい Linux ディストリビューションが必要です。 X11 デスクトップを試すか、OS を変更してください。"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "表示"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "共有する画面を選択してください(リモートコンピューターが操作します)"),
|
||||
("Show RustDesk", "RustDesk を表示"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "{} で続行"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "키보드 설정"),
|
||||
("Full Access", "전체 액세스"),
|
||||
("Screen Share", "화면 공유"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland는 Ubuntu 21.04 이상 버전이 필요합니다."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland는 상위 버전의 Linux 배포판이 필요합니다. X11 데스크탑을 사용하거나 OS를 변경하세요."),
|
||||
("ubuntu-21-04-required", "Wayland는 Ubuntu 21.04 이상 버전이 필요합니다."),
|
||||
("wayland-requires-higher-linux-version", "Wayland는 상위 버전의 Linux 배포판이 필요합니다. X11 데스크탑을 사용하거나 OS를 변경하세요."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "점프 링크"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "공유할 화면을 선택하세요 (피어 측에서 작동)"),
|
||||
("Show RustDesk", "RustDesk 표시"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "수신 세션 중 화면 켜짐 유지"),
|
||||
("Continue with {}", "{}(으)로 계속"),
|
||||
("Display Name", "표시 이름"),
|
||||
("password-hidden-tip", "영구 비밀번호가 설정되었습니다 (숨김)."),
|
||||
("preset-password-in-use-tip", "현재 사전 설정된 비밀번호가 사용 중입니다."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", ""),
|
||||
("Full Access", ""),
|
||||
("Screen Share", ""),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland Ubuntu 21.04 немесе одан жоғары нұсқасын қажет етеді."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland linux дистрибутивінің жоғарырақ нұсқасын қажет етеді. X11 жұмыс үстелін қолданып көріңіз немесе операциялық жүйеңізді өзгертіңіз."),
|
||||
("ubuntu-21-04-required", "Wayland Ubuntu 21.04 немесе одан жоғары нұсқасын қажет етеді."),
|
||||
("wayland-requires-higher-linux-version", "Wayland linux дистрибутивінің жоғарырақ нұсқасын қажет етеді. X11 жұмыс үстелін қолданып көріңіз немесе операциялық жүйеңізді өзгертіңіз."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Бөлісетін экранды таңдаңыз (бірдей жағынан жұмыс жасаңыз)."),
|
||||
("Show RustDesk", ""),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", ""),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Klaviatūros nustatymai"),
|
||||
("Full Access", "Pilna prieiga"),
|
||||
("Screen Share", "Ekrano bendrinimas"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland reikalauja Ubuntu 21.04 arba naujesnės versijos."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland reikalinga naujesnės Linux Distro versijos. Išbandykite X11 darbalaukį arba pakeiskite OS."),
|
||||
("ubuntu-21-04-required", "Wayland reikalauja Ubuntu 21.04 arba naujesnės versijos."),
|
||||
("wayland-requires-higher-linux-version", "Wayland reikalinga naujesnės Linux Distro versijos. Išbandykite X11 darbalaukį arba pakeiskite OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Peržiūra"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Prašome pasirinkti ekraną, kurį norite bendrinti (veikiantį kitoje pusėje)."),
|
||||
("Show RustDesk", "Rodyti RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Tęsti su {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Tastatūras iestatījumi"),
|
||||
("Full Access", "Pilna piekļuve"),
|
||||
("Screen Share", "Ekrāna kopīgošana"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland nepieciešama Ubuntu 21.04 vai jaunāka versija."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland nepieciešama augstāka Linux distro versija. Lūdzu, izmēģiniet X11 desktop vai mainiet savu OS."),
|
||||
("ubuntu-21-04-required", "Wayland nepieciešama Ubuntu 21.04 vai jaunāka versija."),
|
||||
("wayland-requires-higher-linux-version", "Wayland nepieciešama augstāka Linux distro versija. Lūdzu, izmēģiniet X11 desktop vai mainiet savu OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Skatīt"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Lūdzu, atlasiet kopīgojamo ekrānu (darbojieties sesijas pusē)."),
|
||||
("Show RustDesk", "Rādīt RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Turpināt ar {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Tastaturinnstillinger"),
|
||||
("Full Access", "Full tilgang"),
|
||||
("Screen Share", "Skjermdeling"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland krever Ubuntu version 21.04 eller nyere."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland krever en nyere versjon av Linux. Prøv X11 desktop eller skift OS."),
|
||||
("ubuntu-21-04-required", "Wayland krever Ubuntu version 21.04 eller nyere."),
|
||||
("wayland-requires-higher-linux-version", "Wayland krever en nyere versjon av Linux. Prøv X11 desktop eller skift OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "vennligst velg den skjermen, som skal deles (fjernstyres)."),
|
||||
("Show RustDesk", "Vis RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Fortsett med {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Toetsenbordinstellingen"),
|
||||
("Full Access", "Volledige Toegang"),
|
||||
("Screen Share", "Scherm Delen"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vereist Ubuntu 21.04 of hoger."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vereist een hogere versie van Linux distro. Probeer X11 desktop of verander van OS."),
|
||||
("ubuntu-21-04-required", "Wayland vereist Ubuntu 21.04 of hoger."),
|
||||
("wayland-requires-higher-linux-version", "Wayland vereist een hogere versie van Linux distro. Probeer X11 desktop of verander van OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Selecteer het scherm dat moet worden gedeeld (Bediening aan de kant van de peer)."),
|
||||
("Show RustDesk", "Toon RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Houd het scherm open tijdens de inkomende sessies."),
|
||||
("Continue with {}", "Ga verder met {}"),
|
||||
("Display Name", "Naam Weergeven"),
|
||||
("password-hidden-tip", "Er is een permanent wachtwoord ingesteld (verborgen)."),
|
||||
("preset-password-in-use-tip", "Het basis wachtwoord is momenteel in gebruik."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Ustawienia klawiatury"),
|
||||
("Full Access", "Pełny dostęp"),
|
||||
("Screen Share", "Udostępnianie ekranu"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland wymaga Ubuntu 21.04 lub nowszego."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland wymaga nowszej dystrybucji Linuksa. Wypróbuj pulpit X11 lub zmień system operacyjny."),
|
||||
("ubuntu-21-04-required", "Wayland wymaga Ubuntu 21.04 lub nowszego."),
|
||||
("wayland-requires-higher-linux-version", "Wayland wymaga nowszej dystrybucji Linuksa. Wypróbuj pulpit X11 lub zmień system operacyjny."),
|
||||
("xdp-portal-unavailable", "Nie udało się przechwycić ekranu Wayland. Portal XDG Desktop mógł ulec awarii lub jest niedostępny. Spróbuj go ponownie uruchomić poleceniem `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Podgląd"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Wybierz ekran do udostępnienia (działaj po zdalnego urządzenia)."),
|
||||
("Show RustDesk", "Pokaż RustDesk"),
|
||||
|
|
@ -739,6 +740,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-outgoing-sessions-label", "Utrzymuj urządzenie w stanie aktywnym podczas sesji wychodzących"),
|
||||
("keep-awake-during-incoming-sessions-label", "Utrzymuj urządzenie w stanie aktywnym podczas sesji przychodzących"),
|
||||
("Continue with {}", "Kontynuuj z {}"),
|
||||
("Display Name", ""),
|
||||
("Display Name", "Nazwa wyświetlana"),
|
||||
("password-hidden-tip", "Ustawiono (ukryto) stare hasło."),
|
||||
("preset-password-in-use-tip", "Obecnie używane jest hasło domyślne."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Configurações do teclado"),
|
||||
("Full Access", "Controlo total"),
|
||||
("Screen Share", ""),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requer Ubuntu 21.04 ou versão superior."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."),
|
||||
("ubuntu-21-04-required", "Wayland requer Ubuntu 21.04 ou versão superior."),
|
||||
("wayland-requires-higher-linux-version", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Por favor, selecione a tela a ser compartilhada (operar no lado do peer)."),
|
||||
("Show RustDesk", ""),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", ""),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Configurações de teclado"),
|
||||
("Full Access", "Acesso completo"),
|
||||
("Screen Share", "Compartilhamento de tela"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requer Ubuntu 21.04 ou versão superior."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."),
|
||||
("ubuntu-21-04-required", "Wayland requer Ubuntu 21.04 ou versão superior."),
|
||||
("wayland-requires-higher-linux-version", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Por favor, selecione a tela a ser compartilhada (operar no lado do parceiro)."),
|
||||
("Show RustDesk", "Exibir RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Manter tela ativa durante sessões de entrada"),
|
||||
("Continue with {}", "Continuar com {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
505
src/lang/ro.rs
505
src/lang/ro.rs
|
|
@ -62,7 +62,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Invalid format", "Format nevalid"),
|
||||
("server_not_support", "Încă nu este compatibil cu serverul"),
|
||||
("Not available", "Indisponibil"),
|
||||
("Too frequent", "Modificat prea frecvent"),
|
||||
("Too frequent", "Prea frecvent"),
|
||||
("Cancel", "Anulează"),
|
||||
("Skip", "Omite"),
|
||||
("Close", "Închide"),
|
||||
|
|
@ -87,7 +87,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Modified", "Modificat"),
|
||||
("Size", "Dimensiune"),
|
||||
("Show Hidden Files", "Afișează fișiere ascunse"),
|
||||
("Receive", "Acceptă"),
|
||||
("Receive", "Primește"),
|
||||
("Send", "Trimite"),
|
||||
("Refresh File", "Actualizează fișier"),
|
||||
("Local", "Local"),
|
||||
|
|
@ -108,7 +108,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Do this for all conflicts", "Aplică la toate conflictele"),
|
||||
("This is irreversible!", "Această acțiune este ireversibilă!"),
|
||||
("Deleting", "În curs de ștergere..."),
|
||||
("files", "fișier"),
|
||||
("files", "fișiere"),
|
||||
("Waiting", "În așteptare..."),
|
||||
("Finished", "Finalizat"),
|
||||
("Speed", "Viteză"),
|
||||
|
|
@ -203,7 +203,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("x11 expected", "Este necesar X11"),
|
||||
("Port", "Port"),
|
||||
("Settings", "Setări"),
|
||||
("Username", " Nume utilizator"),
|
||||
("Username", "Nume utilizator"),
|
||||
("Invalid port", "Port nevalid"),
|
||||
("Closed manually by the peer", "Conexiune închisă manual de dispozitivul pereche"),
|
||||
("Enable remote configuration modification", "Activează modificarea configurației de la distanță"),
|
||||
|
|
@ -216,7 +216,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Remember me", "Reține-mă"),
|
||||
("Trust this device", "Acest dispozitiv este de încredere"),
|
||||
("Verification code", "Cod de verificare"),
|
||||
("verification_tip", ""),
|
||||
("verification_tip", "Introdu codul de verificare trimis la adresa ta de e-mail sau generat de aplicația de autentificare."),
|
||||
("Logout", "Deconectează-te"),
|
||||
("Tags", "Etichete"),
|
||||
("Search ID", "Caută după ID"),
|
||||
|
|
@ -228,9 +228,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Username missed", "Lipsește numele de utilizator"),
|
||||
("Password missed", "Lipsește parola"),
|
||||
("Wrong credentials", "Nume sau parolă greșită"),
|
||||
("The verification code is incorrect or has expired", ""),
|
||||
("The verification code is incorrect or has expired", "Codul de verificare este incorect sau a expirat"),
|
||||
("Edit Tag", "Modifică etichetă"),
|
||||
("Forget Password", "Uită parola"),
|
||||
("Forget Password", "Parolă uitată"),
|
||||
("Favorites", "Favorite"),
|
||||
("Add to Favorites", "Adaugă la Favorite"),
|
||||
("Remove from Favorites", "Șterge din Favorite"),
|
||||
|
|
@ -263,7 +263,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Canvas Zoom", "Mărire ecran"),
|
||||
("Reset canvas", "Reinițializează ecranul"),
|
||||
("No permission of file transfer", "Nicio permisiune pentru transferul de fișiere"),
|
||||
("Note", "Reține"),
|
||||
("Note", "Notă"),
|
||||
("Connection", "Conexiune"),
|
||||
("Share screen", "Partajează ecran"),
|
||||
("Chat", "Mesaje"),
|
||||
|
|
@ -276,14 +276,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Do you accept?", "Accepți?"),
|
||||
("Open System Setting", "Deschide setări sistem"),
|
||||
("How to get Android input permission?", "Cum autorizez dispozitive de intrare pe Android?"),
|
||||
("android_input_permission_tip1", "Pentru ca un dispozitiv la distanță să poată controla un dispozitiv Android folosind mouse-ul sau suportul tactil, trebuie să permiți RustDesk să utilize serviciul „Accesibilitate”."),
|
||||
("android_input_permission_tip1", "Pentru ca un dispozitiv la distanță să poată controla un dispozitiv Android folosind mouse-ul sau suportul tactil, trebuie să permiți RustDesk să utilizeze serviciul „Accesibilitate\"."),
|
||||
("android_input_permission_tip2", "Accesează următoarea pagină din Setări, deschide [Aplicații instalate] și pornește serviciul [RustDesk Input]."),
|
||||
("android_new_connection_tip", "Ai primit o nouă solicitare de controlare a dispozitivului actual."),
|
||||
("android_service_will_start_tip", "Activarea setării de capturare a ecranului va porni automat serviciul, permițând altor dispozitive să solicite conectarea la dispozitivul tău."),
|
||||
("android_stop_service_tip", "Închiderea serviciului va închide automat toate conexiunile stabilite."),
|
||||
("android_version_audio_tip", "Versiunea actuală de Android nu suportă captura audio. Fă upgrade la Android 10 sau la o versiune superioară."),
|
||||
("android_start_service_tip", "Apasă [Pornește serviciu] sau DESCHIDE [Capturare ecran] pentru a porni serviciul de partajare a ecranului."),
|
||||
("android_permission_may_not_change_tip", ""),
|
||||
("android_permission_may_not_change_tip", "Este posibil ca unele permisiuni să nu poată fi modificate în funcție de versiunea de Android."),
|
||||
("Account", "Cont"),
|
||||
("Overwrite", "Suprascrie"),
|
||||
("This file exists, skip or overwrite this file?", "Fișier deja existent. Omite sau suprascrie?"),
|
||||
|
|
@ -304,15 +304,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("android_open_battery_optimizations_tip", "Pentru dezactivarea acestei funcții, accesează setările aplicației RustDesk, deschide secțiunea [Baterie] și deselectează [Fără restricții]."),
|
||||
("Start on boot", "Pornește la boot"),
|
||||
("Start the screen sharing service on boot, requires special permissions", "Pornește serviciul de partajare a ecranului la boot; necesită permisiuni speciale"),
|
||||
("Connection not allowed", "Conexiune neautoriztă"),
|
||||
("Connection not allowed", "Conexiune neautorizată"),
|
||||
("Legacy mode", "Mod legacy"),
|
||||
("Map mode", "Mod hartă"),
|
||||
("Translate mode", "Mod traducere"),
|
||||
("Use permanent password", "Folosește parola permanentă"),
|
||||
("Use both passwords", "Folosește ambele programe"),
|
||||
("Use both passwords", "Folosește ambele parole"),
|
||||
("Set permanent password", "Setează parola permanentă"),
|
||||
("Enable remote restart", "Activează repornirea la distanță"),
|
||||
("Restart remote device", "Repornește dispozivul la distanță"),
|
||||
("Restart remote device", "Repornește dispozitivul la distanță"),
|
||||
("Are you sure you want to restart", "Sigur vrei să repornești dispozitivul?"),
|
||||
("Restarting remote device", "Se repornește dispozitivul la distanță"),
|
||||
("remote_restarting_tip", "Dispozitivul este în curs de repornire. Închide acest mesaj și reconectează-te cu parola permanentă după un timp."),
|
||||
|
|
@ -359,8 +359,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Unpin Toolbar", "Detașează bara de instrumente"),
|
||||
("Recording", "Înregistrare"),
|
||||
("Directory", "Director"),
|
||||
("Automatically record incoming sessions", "Înregistrează automat sesiunile viitoare"),
|
||||
("Automatically record outgoing sessions", ""),
|
||||
("Automatically record incoming sessions", "Înregistrează automat sesiunile primite"),
|
||||
("Automatically record outgoing sessions", "Înregistrează automat sesiunile de ieșire"),
|
||||
("Change", "Modifică"),
|
||||
("Start session recording", "Începe înregistrarea"),
|
||||
("Stop session recording", "Oprește înregistrarea"),
|
||||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Setări tastatură"),
|
||||
("Full Access", "Acces total"),
|
||||
("Screen Share", "Partajare ecran"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland necesită Ubuntu 21.04 sau o versiune superioară."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland necesită o versiune superioară a distribuției Linux. Încearcă desktopul X11 sau schimbă sistemul de operare."),
|
||||
("ubuntu-21-04-required", "Wayland necesită Ubuntu 21.04 sau o versiune superioară."),
|
||||
("wayland-requires-higher-linux-version", "Wayland necesită o versiune superioară a distribuției Linux. Încearcă desktopul X11 sau schimbă sistemul de operare."),
|
||||
("xdp-portal-unavailable", "Portalul XDG Desktop nu este disponibil. Asigură-te că rulezi o sesiune Wayland cu suport pentru portal."),
|
||||
("JumpLink", "Afișează"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Partajează ecranul care urmează să fie partajat (operează din partea dispozitivului pereche)."),
|
||||
("Show RustDesk", "Afișează RustDesk"),
|
||||
|
|
@ -435,13 +436,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Default Image Quality", "Calitatea implicită a imaginii"),
|
||||
("Default Codec", "Codec implicit"),
|
||||
("Bitrate", "Rată de biți"),
|
||||
("FPS", "CPS"),
|
||||
("FPS", "FPS"),
|
||||
("Auto", "Auto"),
|
||||
("Other Default Options", "Alte opțiuni implicite"),
|
||||
("Voice call", "Apel vocal"),
|
||||
("Text chat", "Conversație text"),
|
||||
("Stop voice call", "Încheie apel vocal"),
|
||||
("relay_hint_tip", "Este posibil să nu te poți conecta direct; poți încerca să te conectezi prin retransmisie. De asemenea, dacă dorești să te conectezi direct prin retransmisie, poți adăuga sufixul „/r” la ID sau să bifezi opțiunea Conectează-te mereu prin retransmisie."),
|
||||
("relay_hint_tip", "Este posibil să nu te poți conecta direct; poți încerca să te conectezi prin retransmisie. De asemenea, dacă dorești să te conectezi direct prin retransmisie, poți adăuga sufixul „/r\" la ID sau să bifezi opțiunea Conectează-te mereu prin retransmisie."),
|
||||
("Reconnect", "Reconectează-te"),
|
||||
("Codec", "Codec"),
|
||||
("Resolution", "Rezoluție"),
|
||||
|
|
@ -502,243 +503,245 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Exit", "Ieși"),
|
||||
("Open", "Deschide"),
|
||||
("logout_tip", "Sigur vrei să te deconectezi?"),
|
||||
("Service", ""),
|
||||
("Start", ""),
|
||||
("Stop", ""),
|
||||
("exceed_max_devices", ""),
|
||||
("Sync with recent sessions", ""),
|
||||
("Sort tags", ""),
|
||||
("Open connection in new tab", ""),
|
||||
("Move tab to new window", ""),
|
||||
("Can not be empty", ""),
|
||||
("Already exists", ""),
|
||||
("Change Password", ""),
|
||||
("Refresh Password", ""),
|
||||
("ID", ""),
|
||||
("Grid View", ""),
|
||||
("List View", ""),
|
||||
("Select", ""),
|
||||
("Toggle Tags", ""),
|
||||
("pull_ab_failed_tip", ""),
|
||||
("push_ab_failed_tip", ""),
|
||||
("synced_peer_readded_tip", ""),
|
||||
("Change Color", ""),
|
||||
("Primary Color", ""),
|
||||
("HSV Color", ""),
|
||||
("Installation Successful!", ""),
|
||||
("Installation failed!", ""),
|
||||
("Reverse mouse wheel", ""),
|
||||
("{} sessions", ""),
|
||||
("scam_title", ""),
|
||||
("scam_text1", ""),
|
||||
("scam_text2", ""),
|
||||
("Don't show again", ""),
|
||||
("I Agree", ""),
|
||||
("Decline", ""),
|
||||
("Timeout in minutes", ""),
|
||||
("auto_disconnect_option_tip", ""),
|
||||
("Connection failed due to inactivity", ""),
|
||||
("Check for software update on startup", ""),
|
||||
("upgrade_rustdesk_server_pro_to_{}_tip", ""),
|
||||
("pull_group_failed_tip", ""),
|
||||
("Filter by intersection", ""),
|
||||
("Remove wallpaper during incoming sessions", ""),
|
||||
("Test", ""),
|
||||
("display_is_plugged_out_msg", ""),
|
||||
("No displays", ""),
|
||||
("Open in new window", ""),
|
||||
("Show displays as individual windows", ""),
|
||||
("Use all my displays for the remote session", ""),
|
||||
("selinux_tip", ""),
|
||||
("Change view", ""),
|
||||
("Big tiles", ""),
|
||||
("Small tiles", ""),
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color (4:4:4)", ""),
|
||||
("Enable blocking user input", ""),
|
||||
("id_input_tip", ""),
|
||||
("privacy_mode_impl_mag_tip", ""),
|
||||
("privacy_mode_impl_virtual_display_tip", ""),
|
||||
("Enter privacy mode", ""),
|
||||
("Exit privacy mode", ""),
|
||||
("idd_not_support_under_win10_2004_tip", ""),
|
||||
("input_source_1_tip", ""),
|
||||
("input_source_2_tip", ""),
|
||||
("Swap control-command key", ""),
|
||||
("swap-left-right-mouse", ""),
|
||||
("2FA code", ""),
|
||||
("More", ""),
|
||||
("enable-2fa-title", ""),
|
||||
("enable-2fa-desc", ""),
|
||||
("wrong-2fa-code", ""),
|
||||
("enter-2fa-title", ""),
|
||||
("Email verification code must be 6 characters.", ""),
|
||||
("2FA code must be 6 digits.", ""),
|
||||
("Multiple Windows sessions found", ""),
|
||||
("Please select the session you want to connect to", ""),
|
||||
("powered_by_me", ""),
|
||||
("outgoing_only_desk_tip", ""),
|
||||
("preset_password_warning", ""),
|
||||
("Security Alert", ""),
|
||||
("My address book", ""),
|
||||
("Personal", ""),
|
||||
("Owner", ""),
|
||||
("Set shared password", ""),
|
||||
("Exist in", ""),
|
||||
("Read-only", ""),
|
||||
("Read/Write", ""),
|
||||
("Full Control", ""),
|
||||
("share_warning_tip", ""),
|
||||
("Everyone", ""),
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
("default_proxy_tip", ""),
|
||||
("no_audio_input_device_tip", ""),
|
||||
("Incoming", ""),
|
||||
("Outgoing", ""),
|
||||
("Clear Wayland screen selection", ""),
|
||||
("clear_Wayland_screen_selection_tip", ""),
|
||||
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||
("android_new_voice_call_tip", ""),
|
||||
("texture_render_tip", ""),
|
||||
("Use texture rendering", ""),
|
||||
("Floating window", ""),
|
||||
("floating_window_tip", ""),
|
||||
("Keep screen on", ""),
|
||||
("Never", ""),
|
||||
("During controlled", ""),
|
||||
("During service is on", ""),
|
||||
("Capture screen using DirectX", ""),
|
||||
("Back", ""),
|
||||
("Apps", ""),
|
||||
("Volume up", ""),
|
||||
("Volume down", ""),
|
||||
("Power", ""),
|
||||
("Telegram bot", ""),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
("cancel-2fa-confirm-tip", ""),
|
||||
("cancel-bot-confirm-tip", ""),
|
||||
("About RustDesk", ""),
|
||||
("Send clipboard keystrokes", ""),
|
||||
("network_error_tip", ""),
|
||||
("Unlock with PIN", ""),
|
||||
("Requires at least {} characters", ""),
|
||||
("Wrong PIN", ""),
|
||||
("Set PIN", ""),
|
||||
("Enable trusted devices", ""),
|
||||
("Manage trusted devices", ""),
|
||||
("Platform", ""),
|
||||
("Days remaining", ""),
|
||||
("enable-trusted-devices-tip", ""),
|
||||
("Parent directory", ""),
|
||||
("Resume", ""),
|
||||
("Invalid file name", ""),
|
||||
("one-way-file-transfer-tip", ""),
|
||||
("Authentication Required", ""),
|
||||
("Authenticate", ""),
|
||||
("web_id_input_tip", ""),
|
||||
("Download", ""),
|
||||
("Upload folder", ""),
|
||||
("Upload files", ""),
|
||||
("Clipboard is synchronized", ""),
|
||||
("Update client clipboard", ""),
|
||||
("Untagged", ""),
|
||||
("new-version-of-{}-tip", ""),
|
||||
("Accessible devices", ""),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", ""),
|
||||
("d3d_render_tip", ""),
|
||||
("Use D3D rendering", ""),
|
||||
("Printer", ""),
|
||||
("printer-os-requirement-tip", ""),
|
||||
("printer-requires-installed-{}-client-tip", ""),
|
||||
("printer-{}-not-installed-tip", ""),
|
||||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
("auto-print-tip", ""),
|
||||
("print-incoming-job-confirm-tip", ""),
|
||||
("remote-printing-disallowed-tile-tip", ""),
|
||||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
("Enable remote printer", ""),
|
||||
("Downloading {}", ""),
|
||||
("{} Update", ""),
|
||||
("{}-to-update-tip", ""),
|
||||
("download-new-version-failed-tip", ""),
|
||||
("Auto update", ""),
|
||||
("update-failed-check-msi-tip", ""),
|
||||
("websocket_tip", ""),
|
||||
("Use WebSocket", ""),
|
||||
("Trackpad speed", ""),
|
||||
("Default trackpad speed", ""),
|
||||
("Numeric one-time password", ""),
|
||||
("Enable IPv6 P2P connection", ""),
|
||||
("Enable UDP hole punching", ""),
|
||||
("Service", "Serviciu"),
|
||||
("Start", "Pornește"),
|
||||
("Stop", "Oprește"),
|
||||
("exceed_max_devices", "Numărul maxim de dispozitive a fost depășit"),
|
||||
("Sync with recent sessions", "Sincronizează cu sesiunile recente"),
|
||||
("Sort tags", "Sortează etichete"),
|
||||
("Open connection in new tab", "Deschide conexiunea într-o filă nouă"),
|
||||
("Move tab to new window", "Mută fila într-o fereastră nouă"),
|
||||
("Can not be empty", "Nu poate fi gol"),
|
||||
("Already exists", "Există deja"),
|
||||
("Change Password", "Schimbă parola"),
|
||||
("Refresh Password", "Reîmprospătează parola"),
|
||||
("ID", "ID"),
|
||||
("Grid View", "Vizualizare grilă"),
|
||||
("List View", "Vizualizare listă"),
|
||||
("Select", "Selectează"),
|
||||
("Toggle Tags", "Comută etichete"),
|
||||
("pull_ab_failed_tip", "Sincronizarea agendei a eșuat. Verifică conexiunea la rețea sau autentifică-te din nou."),
|
||||
("push_ab_failed_tip", "Salvarea agendei pe server a eșuat. Verifică conexiunea la rețea sau autentifică-te din nou."),
|
||||
("synced_peer_readded_tip", "Dispozitivele pereche eliminate au fost re-adăugate automat din sesiunile recente."),
|
||||
("Change Color", "Schimbă culoarea"),
|
||||
("Primary Color", "Culoare principală"),
|
||||
("HSV Color", "Culoare HSV"),
|
||||
("Installation Successful!", "Instalare reușită!"),
|
||||
("Installation failed!", "Instalare eșuată!"),
|
||||
("Reverse mouse wheel", "Inversează rotiță mouse"),
|
||||
("{} sessions", "{} sesiuni"),
|
||||
("scam_title", "Avertisment de securitate"),
|
||||
("scam_text1", "Escrocii se pot da drept angajați ai asistenței tehnice și îți pot solicita să instalezi sau să rulezi RustDesk pentru a-ți accesa dispozitivul."),
|
||||
("scam_text2", "Dacă nu ai contactat tu primul asistența tehnică, te rugăm să închizi această aplicație imediat."),
|
||||
("Don't show again", "Nu mai afișa"),
|
||||
("I Agree", "Sunt de acord"),
|
||||
("Decline", "Refuză"),
|
||||
("Timeout in minutes", "Timp de expirare în minute"),
|
||||
("auto_disconnect_option_tip", "Deconectează automat sesiunile de la distanță după o perioadă de inactivitate."),
|
||||
("Connection failed due to inactivity", "Conexiunea a eșuat din cauza inactivității"),
|
||||
("Check for software update on startup", "Verifică actualizări la pornire"),
|
||||
("upgrade_rustdesk_server_pro_{}_tip", "Versiunea serverului RustDesk Pro este mai mică decât {}. Te rugăm să o actualizezi."),
|
||||
("pull_group_failed_tip", "Sincronizarea grupului a eșuat. Verifică conexiunea la rețea sau autentifică-te din nou."),
|
||||
("Filter by intersection", "Filtrează prin intersecție"),
|
||||
("Remove wallpaper during incoming sessions", "Elimină imaginea de fundal în timpul sesiunilor primite"),
|
||||
("Test", "Test"),
|
||||
("display_is_plugged_out_msg", "Monitorul selectat a fost deconectat. Sesiunea continuă pe monitorul disponibil."),
|
||||
("No displays", "Niciun monitor"),
|
||||
("Open in new window", "Deschide în fereastră nouă"),
|
||||
("Show displays as individual windows", "Afișează monitoarele ca ferestre individuale"),
|
||||
("Use all my displays for the remote session", "Folosește toate monitoarele mele pentru sesiunea la distanță"),
|
||||
("selinux_tip", "SELinux este activat pe acest sistem. Este posibil ca unele funcții să nu funcționeze corect. Te rugăm să consulți documentația pentru instrucțiuni de configurare."),
|
||||
("Change view", "Schimbă vizualizarea"),
|
||||
("Big tiles", "Dale mari"),
|
||||
("Small tiles", "Dale mici"),
|
||||
("List", "Listă"),
|
||||
("Virtual display", "Monitor virtual"),
|
||||
("Plug out all", "Deconectează toate"),
|
||||
("True color (4:4:4)", "Culori reale (4:4:4)"),
|
||||
("Enable blocking user input", "Activează blocarea intrărilor utilizatorului"),
|
||||
("id_input_tip", "Introdu ID-ul sau adresa IP a dispozitivului la distanță"),
|
||||
("privacy_mode_impl_mag_tip", "Modul privat prin Magnificare — nu este suportat pe toate sistemele"),
|
||||
("privacy_mode_impl_virtual_display_tip", "Modul privat prin monitor virtual — necesită driverul de monitor virtual"),
|
||||
("Enter privacy mode", "Intră în modul privat"),
|
||||
("Exit privacy mode", "Ieși din modul privat"),
|
||||
("idd_not_support_under_win10_2004_tip", "Driverul de monitor virtual nu este suportat pe versiuni de Windows anterioare versiunii 2004 (build 19041)."),
|
||||
("input_source_1_tip", "Sursă de intrare 1 — folosește metodele standard de simulare a tastaturii și mouse-ului"),
|
||||
("input_source_2_tip", "Sursă de intrare 2 — folosește driver-ul RustDesk pentru simulare la nivel de kernel"),
|
||||
("Swap control-command key", "Schimbă tastele Control și Command"),
|
||||
("swap-left-right-mouse", "Schimbă butoanele stâng și drept ale mouse-ului"),
|
||||
("2FA code", "Cod 2FA"),
|
||||
("More", "Mai mult"),
|
||||
("enable-2fa-title", "Activează autentificarea în doi pași (2FA)"),
|
||||
("enable-2fa-desc", "Scanează codul QR cu o aplicație de autentificare (de ex. Google Authenticator) și introdu codul generat pentru a confirma activarea."),
|
||||
("wrong-2fa-code", "Cod 2FA incorect"),
|
||||
("enter-2fa-title", "Introdu codul de autentificare în doi pași"),
|
||||
("Email verification code must be 6 characters.", "Codul de verificare prin e-mail trebuie să aibă 6 caractere."),
|
||||
("2FA code must be 6 digits.", "Codul 2FA trebuie să conțină 6 cifre."),
|
||||
("Multiple Windows sessions found", "Au fost găsite mai multe sesiuni Windows"),
|
||||
("Please select the session you want to connect to", "Selectează sesiunea la care vrei să te conectezi"),
|
||||
("powered_by_me", "Realizat cu RustDesk"),
|
||||
("outgoing_only_desk_tip", "Acest dispozitiv este configurat doar pentru conexiuni de ieșire și nu acceptă conexiuni de intrare."),
|
||||
("preset_password_warning", "Parola prestabilită nu este recomandată din motive de securitate. Te rugăm să o schimbi cât mai curând posibil."),
|
||||
("Security Alert", "Alertă de securitate"),
|
||||
("My address book", "Agenda mea"),
|
||||
("Personal", "Personal"),
|
||||
("Owner", "Proprietar"),
|
||||
("Set shared password", "Setează parola partajată"),
|
||||
("Exist in", "Există în"),
|
||||
("Read-only", "Doar citire"),
|
||||
("Read/Write", "Citire/Scriere"),
|
||||
("Full Control", "Control total"),
|
||||
("share_warning_tip", "Datele partajate vor fi vizibile pentru toți membrii grupului selectat. Asigură-te că partajezi doar informații adecvate."),
|
||||
("Everyone", "Toată lumea"),
|
||||
("ab_web_console_tip", "Gestionează agenda prin consola web RustDesk Pro."),
|
||||
("allow-only-conn-window-open-tip", "Permite conexiunile numai atunci când fereastra de gestionare a conexiunilor este deschisă"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Modul privat nu este necesar deoarece nu există monitoare fizice conectate."),
|
||||
("Follow remote cursor", "Urmărește cursorul de la distanță"),
|
||||
("Follow remote window focus", "Urmărește fereastra activă de la distanță"),
|
||||
("default_proxy_tip", "Proxy-ul implicit este utilizat pentru toate conexiunile dacă nu este specificat altul."),
|
||||
("no_audio_input_device_tip", "Nu a fost găsit niciun dispozitiv de intrare audio. Conectează un microfon și reîncearcă."),
|
||||
("Incoming", "Intrare"),
|
||||
("Outgoing", "Ieșire"),
|
||||
("Clear Wayland screen selection", "Șterge selecția de ecran Wayland"),
|
||||
("clear_Wayland_screen_selection_tip", "Șterge selecția de ecran Wayland salvată, astfel încât să poți alege un alt ecran la următoarea conexiune."),
|
||||
("confirm_clear_Wayland_screen_selection_tip", "Sigur vrei să ștergi selecția de ecran Wayland?"),
|
||||
("android_new_voice_call_tip", "Ai primit un nou apel vocal. Apasă pentru a accepta sau respinge."),
|
||||
("texture_render_tip", "Randarea prin textură poate îmbunătăți performanța grafică pe unele dispozitive. Repornește aplicația dacă apar probleme de afișare."),
|
||||
("Use texture rendering", "Folosește randarea prin textură"),
|
||||
("Floating window", "Fereastră flotantă"),
|
||||
("floating_window_tip", "Fereastra flotantă ajută la menținerea serviciului de partajare a ecranului activ în fundal pe Android."),
|
||||
("Keep screen on", "Menține ecranul pornit"),
|
||||
("Never", "Niciodată"),
|
||||
("During controlled", "În timpul controlului"),
|
||||
("During service is on", "Cât timp serviciul este activ"),
|
||||
("Capture screen using DirectX", "Capturează ecranul folosind DirectX"),
|
||||
("Back", "Înapoi"),
|
||||
("Apps", "Aplicații"),
|
||||
("Volume up", "Mărește volumul"),
|
||||
("Volume down", "Micșorează volumul"),
|
||||
("Power", "Alimentare"),
|
||||
("Telegram bot", "Bot Telegram"),
|
||||
("enable-bot-tip", "Activează botul Telegram pentru a primi notificări și a gestiona conexiunile."),
|
||||
("enable-bot-desc", "Configurează un bot Telegram pentru notificări RustDesk. Introdu token-ul botului și ID-ul chat-ului."),
|
||||
("cancel-2fa-confirm-tip", "Sigur vrei să dezactivezi autentificarea în doi pași? Aceasta va reduce securitatea contului tău."),
|
||||
("cancel-bot-confirm-tip", "Sigur vrei să dezactivezi botul Telegram?"),
|
||||
("About RustDesk", "Despre RustDesk"),
|
||||
("Send clipboard keystrokes", "Trimite conținutul clipboard-ului ca apăsări de taste"),
|
||||
("network_error_tip", "Eroare de rețea. Verifică conexiunea la internet și încearcă din nou."),
|
||||
("Unlock with PIN", "Deblochează cu PIN"),
|
||||
("Requires at least {} characters", "Necesită cel puțin {} caractere"),
|
||||
("Wrong PIN", "PIN incorect"),
|
||||
("Set PIN", "Setează PIN"),
|
||||
("Enable trusted devices", "Activează dispozitive de încredere"),
|
||||
("Manage trusted devices", "Gestionează dispozitivele de încredere"),
|
||||
("Platform", "Platformă"),
|
||||
("Days remaining", "Zile rămase"),
|
||||
("enable-trusted-devices-tip", "Dispozitivele de încredere pot accesa contul fără verificare suplimentară."),
|
||||
("Parent directory", "Director părinte"),
|
||||
("Resume", "Reia"),
|
||||
("Invalid file name", "Nume de fișier nevalid"),
|
||||
("one-way-file-transfer-tip", "Transferul de fișiere în sens unic permite doar trimiterea sau primirea de fișiere, nu ambele direcții simultan."),
|
||||
("Authentication Required", "Autentificare necesară"),
|
||||
("Authenticate", "Autentifică-te"),
|
||||
("web_id_input_tip", "Introdu ID-ul RustDesk al dispozitivului la care vrei să te conectezi"),
|
||||
("Download", "Descarcă"),
|
||||
("Upload folder", "Încarcă folder"),
|
||||
("Upload files", "Încarcă fișiere"),
|
||||
("Clipboard is synchronized", "Clipboard-ul este sincronizat"),
|
||||
("Update client clipboard", "Actualizează clipboard-ul clientului"),
|
||||
("Untagged", "Neetichetat"),
|
||||
("new-version-of-{}-tip", "Este disponibilă o nouă versiune a {}. Fă clic pentru a actualiza."),
|
||||
("Accessible devices", "Dispozitive accesibile"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Versiunea clientului RustDesk de la distanță este mai mică decât {}. Te rugăm să o actualizezi pentru o compatibilitate completă."),
|
||||
("d3d_render_tip", "Randarea Direct3D poate îmbunătăți performanța pe sistemele Windows cu suport hardware adecvat."),
|
||||
("Use D3D rendering", "Folosește randarea D3D"),
|
||||
("Printer", "Imprimantă"),
|
||||
("printer-os-requirement-tip", "Imprimarea la distanță necesită Windows 10 sau o versiune superioară."),
|
||||
("printer-requires-installed-{}-client-tip", "Imprimarea la distanță necesită instalarea clientului {} pe dispozitivul local."),
|
||||
("printer-{}-not-installed-tip", "Imprimanta {} nu este instalată. Instalează driverul imprimantei pentru a continua."),
|
||||
("printer-{}-ready-tip", "Imprimanta {} este pregătită pentru utilizare."),
|
||||
("Install {} Printer", "Instalează imprimanta {}"),
|
||||
("Outgoing Print Jobs", "Lucrări de imprimare de ieșire"),
|
||||
("Incoming Print Jobs", "Lucrări de imprimare de intrare"),
|
||||
("Incoming Print Job", "Lucrare de imprimare de intrare"),
|
||||
("use-the-default-printer-tip", "Folosește imprimanta implicită a sistemului pentru lucrările de imprimare primite."),
|
||||
("use-the-selected-printer-tip", "Folosește imprimanta selectată pentru lucrările de imprimare primite."),
|
||||
("auto-print-tip", "Imprimă automat lucrările primite fără confirmare."),
|
||||
("print-incoming-job-confirm-tip", "Ai primit o lucrare de imprimare. Vrei să o imprimești?"),
|
||||
("remote-printing-disallowed-tile-tip", "Imprimare la distanță nepermisă"),
|
||||
("remote-printing-disallowed-text-tip", "Dispozitivul la distanță nu permite imprimarea. Contactează administratorul pentru a activa această funcție."),
|
||||
("save-settings-tip", "Salvează setările curente ca implicite pentru sesiunile viitoare."),
|
||||
("dont-show-again-tip", "Nu mai afișa acest mesaj"),
|
||||
("Take screenshot", "Fă captură de ecran"),
|
||||
("Taking screenshot", "Se face captura de ecran..."),
|
||||
("screenshot-merged-screen-not-supported-tip", "Captura de ecran a ecranului combinat nu este suportată în prezent."),
|
||||
("screenshot-action-tip", "Selectează acțiunea pentru captura de ecran: salvează ca fișier sau copiază în clipboard."),
|
||||
("Save as", "Salvează ca"),
|
||||
("Copy to clipboard", "Copiază în clipboard"),
|
||||
("Enable remote printer", "Activează imprimanta la distanță"),
|
||||
("Downloading {}", "Se descarcă {}"),
|
||||
("{} Update", "Actualizare {}"),
|
||||
("{}-to-update-tip", "Este disponibilă o actualizare pentru {}. Fă clic pentru a descărca și instala."),
|
||||
("download-new-version-failed-tip", "Descărcarea noii versiuni a eșuat. Verifică conexiunea la internet și încearcă din nou."),
|
||||
("Auto update", "Actualizare automată"),
|
||||
("update-failed-check-msi-tip", "Actualizarea a eșuat. Încearcă să descarci și să instalezi manual fișierul MSI."),
|
||||
("websocket_tip", "WebSocket oferă o conexiune mai stabilă în unele medii de rețea restrictive."),
|
||||
("Use WebSocket", "Folosește WebSocket"),
|
||||
("Trackpad speed", "Viteza touchpad-ului"),
|
||||
("Default trackpad speed", "Viteza implicită a touchpad-ului"),
|
||||
("Numeric one-time password", "Parolă unică numerică"),
|
||||
("Enable IPv6 P2P connection", "Activează conexiunea P2P prin IPv6"),
|
||||
("Enable UDP hole punching", "Activează traversarea UDP (hole punching)"),
|
||||
("View camera", "Vezi camera"),
|
||||
("Enable camera", ""),
|
||||
("No cameras", ""),
|
||||
("view_camera_unsupported_tip", ""),
|
||||
("Terminal", ""),
|
||||
("Enable terminal", ""),
|
||||
("New tab", ""),
|
||||
("Keep terminal sessions on disconnect", ""),
|
||||
("Terminal (Run as administrator)", ""),
|
||||
("terminal-admin-login-tip", ""),
|
||||
("Failed to get user token.", ""),
|
||||
("Incorrect username or password.", ""),
|
||||
("The user is not an administrator.", ""),
|
||||
("Failed to check if the user is an administrator.", ""),
|
||||
("Supported only in the installed version.", ""),
|
||||
("elevation_username_tip", ""),
|
||||
("Preparing for installation ...", ""),
|
||||
("Show my cursor", ""),
|
||||
("Enable camera", "Activează camera"),
|
||||
("No cameras", "Nicio cameră disponibilă"),
|
||||
("view_camera_unsupported_tip", "Vizualizarea camerei nu este suportată pe dispozitivul la distanță."),
|
||||
("Terminal", "Terminal"),
|
||||
("Enable terminal", "Activează terminalul"),
|
||||
("New tab", "Filă nouă"),
|
||||
("Keep terminal sessions on disconnect", "Păstrează sesiunile de terminal la deconectare"),
|
||||
("Terminal (Run as administrator)", "Terminal (Rulează ca administrator)"),
|
||||
("terminal-admin-login-tip", "Introdu datele de autentificare ale administratorului pentru a rula terminalul cu privilegii sporite."),
|
||||
("Failed to get user token.", "Obținerea tokenului de utilizator a eșuat."),
|
||||
("Incorrect username or password.", "Nume de utilizator sau parolă incorectă."),
|
||||
("The user is not an administrator.", "Utilizatorul nu este administrator."),
|
||||
("Failed to check if the user is an administrator.", "Verificarea privilegiilor de administrator a eșuat."),
|
||||
("Supported only in the installed version.", "Suportat doar în versiunea instalată."),
|
||||
("elevation_username_tip", "Introdu numele de utilizator al contului de administrator pentru a solicita sporirea privilegiilor."),
|
||||
("Preparing for installation ...", "Se pregătește instalarea..."),
|
||||
("Show my cursor", "Afișează cursorul meu"),
|
||||
("Scale custom", "Scalare personalizată"),
|
||||
("Custom scale slider", "Glisor pentru scalare personalizată"),
|
||||
("Decrease", "Micșorează"),
|
||||
("Increase", "Mărește"),
|
||||
("Show virtual mouse", ""),
|
||||
("Virtual mouse size", ""),
|
||||
("Small", ""),
|
||||
("Large", ""),
|
||||
("Show virtual joystick", ""),
|
||||
("Edit note", ""),
|
||||
("Alias", ""),
|
||||
("ScrollEdge", ""),
|
||||
("Allow insecure TLS fallback", ""),
|
||||
("allow-insecure-tls-fallback-tip", ""),
|
||||
("Disable UDP", ""),
|
||||
("disable-udp-tip", ""),
|
||||
("server-oss-not-support-tip", ""),
|
||||
("input note here", ""),
|
||||
("note-at-conn-end-tip", ""),
|
||||
("Show terminal extra keys", ""),
|
||||
("Relative mouse mode", ""),
|
||||
("rel-mouse-not-supported-peer-tip", ""),
|
||||
("rel-mouse-not-ready-tip", ""),
|
||||
("rel-mouse-lock-failed-tip", ""),
|
||||
("rel-mouse-exit-{}-tip", ""),
|
||||
("rel-mouse-permission-lost-tip", ""),
|
||||
("Changelog", ""),
|
||||
("keep-awake-during-outgoing-sessions-label", ""),
|
||||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Show virtual mouse", "Afișează mouse virtual"),
|
||||
("Virtual mouse size", "Dimensiunea mouse-ului virtual"),
|
||||
("Small", "Mic"),
|
||||
("Large", "Mare"),
|
||||
("Show virtual joystick", "Afișează joystick virtual"),
|
||||
("Edit note", "Editează notă"),
|
||||
("Alias", "Alias"),
|
||||
("ScrollEdge", "Derulare la margine"),
|
||||
("Allow insecure TLS fallback", "Permite revenirea la TLS nesecurizat"),
|
||||
("allow-insecure-tls-fallback-tip", "Permite conexiunile cu certificate TLS nevalide sau expirate. Nu este recomandat din motive de securitate."),
|
||||
("Disable UDP", "Dezactivează UDP"),
|
||||
("disable-udp-tip", "Dezactivează conexiunile UDP și folosește doar TCP. Poate reduce performanța conexiunii."),
|
||||
("server-oss-not-support-tip", "Serverul open-source nu suportă această funcție. Folosește RustDesk Pro pentru funcționalitate completă."),
|
||||
("input note here", "Introdu o notă aici"),
|
||||
("note-at-conn-end-tip", "Afișează această notă la sfârșitul sesiunii de conexiune."),
|
||||
("Show terminal extra keys", "Afișează taste suplimentare pentru terminal"),
|
||||
("Relative mouse mode", "Mod mouse relativ"),
|
||||
("rel-mouse-not-supported-peer-tip", "Dispozitivul pereche nu suportă modul mouse relativ."),
|
||||
("rel-mouse-not-ready-tip", "Modul mouse relativ nu este pregătit. Încearcă din nou."),
|
||||
("rel-mouse-lock-failed-tip", "Blocarea mouse-ului în modul relativ a eșuat."),
|
||||
("rel-mouse-exit-{}-tip", "Apasă {} pentru a ieși din modul mouse relativ."),
|
||||
("rel-mouse-permission-lost-tip", "Permisiunea pentru modul mouse relativ a fost pierdută."),
|
||||
("Changelog", "Jurnal de modificări"),
|
||||
("keep-awake-during-outgoing-sessions-label", "Menține ecranul activ în timpul sesiunilor de ieșire"),
|
||||
("keep-awake-during-incoming-sessions-label", "Menține ecranul activ în timpul sesiunilor de intrare"),
|
||||
("Continue with {}", "Continuă cu {}"),
|
||||
("Display Name", ""),
|
||||
("Display Name", "Nume afișat"),
|
||||
("password-hidden-tip", "Parola este ascunsă din motive de securitate. Fă clic pe pictograma ochiului pentru a o afișa."),
|
||||
("preset-password-in-use-tip", "Se folosește o parolă prestabilită. Se recomandă setarea unei parole personalizate pentru securitate sporită."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Настройки клавиатуры"),
|
||||
("Full Access", "Полный доступ"),
|
||||
("Screen Share", "Демонстрация экрана"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland требуется Ubuntu версии 21.04 или новее."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Для Wayland требуется более поздняя версия дистрибутива Linux. Используйте рабочий стол X11 или смените ОС."),
|
||||
("ubuntu-21-04-required", "Wayland требуется Ubuntu версии 21.04 или новее."),
|
||||
("wayland-requires-higher-linux-version", "Для Wayland требуется более поздняя версия дистрибутива Linux. Используйте рабочий стол X11 или смените ОС."),
|
||||
("xdp-portal-unavailable", "Невозможно сделать снимок экрана Wayland. Возможно, в XDG Desktop Portal сбой или он недоступен. Попробуйте перезапустить его с помощью `systemctl --user restart xdg-desktop-portal`."),
|
||||
("JumpLink", "Просмотр"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Выберите экран для демонстрации (работайте на одноранговой стороне)."),
|
||||
("Show RustDesk", "Показать RustDesk"),
|
||||
|
|
@ -665,7 +666,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Incoming Print Job", "Входящее задание печати"),
|
||||
("use-the-default-printer-tip", "Использовать принтер по умолчанию"),
|
||||
("use-the-selected-printer-tip", "Использовать выбранный принтер"),
|
||||
("auto-print-tip", "Автоматически выполнять печать на выбранном принтере."),
|
||||
("auto-print-tip", "Автоматически выполнять печать на выбранном принтере"),
|
||||
("print-incoming-job-confirm-tip", "Получено задание на печать с удалённого устройства. Выполнить его локально?"),
|
||||
("remote-printing-disallowed-tile-tip", "Удалённая печать запрещена"),
|
||||
("remote-printing-disallowed-text-tip", "Настройки разрешений на управляемой стороне запрещают удалённую печать."),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Не отключать экран во время входящих сеансов"),
|
||||
("Continue with {}", "Продолжить с {}"),
|
||||
("Display Name", "Отображаемое имя"),
|
||||
("password-hidden-tip", "Установлен постоянный пароль (скрытый)."),
|
||||
("preset-password-in-use-tip", "Установленный пароль сейчас используется."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Impostatziones de tecladu"),
|
||||
("Full Access", "Atzessu cumpridu"),
|
||||
("Screen Share", "Cumpartzidura de ischermu"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland tenet bisòngiu de Ubuntu 21.04 o versione prus noa."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland tenet bisòngiu de una versione prus noa de sa distributzione Linux.\nProa X11 pro elaboradores o càmbia su sistema operativu."),
|
||||
("ubuntu-21-04-required", "Wayland tenet bisòngiu de Ubuntu 21.04 o versione prus noa."),
|
||||
("wayland-requires-higher-linux-version", "Wayland tenet bisòngiu de una versione prus noa de sa distributzione Linux.\nProa X11 pro elaboradores o càmbia su sistema operativu."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Bae a"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Seletziona s'ischermu de cumpartzire (òpera dae s'ala de su dispositivu remotu)."),
|
||||
("Show RustDesk", "Mustra RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Sighi cun {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Nastavenia klávesnice"),
|
||||
("Full Access", "Úplný prístup"),
|
||||
("Screen Share", "Zdielanie obrazovky"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vyžaduje Ubuntu 21.04 alebo vyššiu verziu."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vyžaduje vyššiu verziu linuxovej distribúcie. Skúste X11 desktop alebo zmeňte OS."),
|
||||
("ubuntu-21-04-required", "Wayland vyžaduje Ubuntu 21.04 alebo vyššiu verziu."),
|
||||
("wayland-requires-higher-linux-version", "Wayland vyžaduje vyššiu verziu linuxovej distribúcie. Skúste X11 desktop alebo zmeňte OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Vyberte obrazovku, ktorú chcete zdieľať (Ovládajte na strane partnera)."),
|
||||
("Show RustDesk", "Zobraziť RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Pokračovať s {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Nastavitve tipkovnice"),
|
||||
("Full Access", "Poln dostop"),
|
||||
("Screen Share", "Deljenje zaslona"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland zahteva Ubuntu 21.04 ali novejši"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Zahtevana je novejša različica Waylanda. Posodobite vašo distribucijo ali pa uporabite X11."),
|
||||
("ubuntu-21-04-required", "Wayland zahteva Ubuntu 21.04 ali novejši"),
|
||||
("wayland-requires-higher-linux-version", "Zahtevana je novejša različica Waylanda. Posodobite vašo distribucijo ali pa uporabite X11."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Pogled"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Izberite zaslon za delitev (na oddaljeni strani)."),
|
||||
("Show RustDesk", "Prikaži RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Nadaljuj z {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Cilësimet e tastierës"),
|
||||
("Full Access", "Qasje e plotë"),
|
||||
("Screen Share", "Ndarja e ekranit"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland kërkon Ubuntu 21.04 ose version më të lartë"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland kërkon një version më të lartë të shpërndarjes linux. Ju lutemi provoni desktopin X11 ose ndryshoni OS."),
|
||||
("ubuntu-21-04-required", "Wayland kërkon Ubuntu 21.04 ose version më të lartë"),
|
||||
("wayland-requires-higher-linux-version", "Wayland kërkon një version më të lartë të shpërndarjes linux. Ju lutemi provoni desktopin X11 ose ndryshoni OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Ju lutemi zgjidhni ekranin që do të ndahet (Vepro në anën e kolegëve"),
|
||||
("Show RustDesk", "Shfaq RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Vazhdo me {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Postavke tastature"),
|
||||
("Full Access", "Pun pristup"),
|
||||
("Screen Share", "Deljenje ekrana"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland zahteva Ubuntu 21.04 ili veću verziju"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland zahteva veću verziju Linux distribucije. Molimo pokušajte X11 ili promenite OS."),
|
||||
("ubuntu-21-04-required", "Wayland zahteva Ubuntu 21.04 ili veću verziju"),
|
||||
("wayland-requires-higher-linux-version", "Wayland zahteva veću verziju Linux distribucije. Molimo pokušajte X11 ili promenite OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "Vidi"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Molimo izaberite ekran koji će biti podeljen (Za rad na klijent strani)"),
|
||||
("Show RustDesk", "Prikazi RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Nastavi sa {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Tangentbordsinställningar"),
|
||||
("Full Access", "Full tillgång"),
|
||||
("Screen Share", "Skärmdelning"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland kräver Ubuntu 21.04 eller högre."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland kräver en högre version av linux. Försök igen eller byt OS."),
|
||||
("ubuntu-21-04-required", "Wayland kräver Ubuntu 21.04 eller högre."),
|
||||
("wayland-requires-higher-linux-version", "Wayland kräver en högre version av linux. Försök igen eller byt OS."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "JumpLink"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Välj skärm att dela"),
|
||||
("Show RustDesk", "Visa RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "Fortsätt med {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "விசைப்பலகை அமைப்புகள்"),
|
||||
("Full Access", "முழு அணுகல்"),
|
||||
("Screen Share", "திரை பகிர்வு"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland க்கு Ubuntu 21.04+ தேவை"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland க்கு உயர் Linux பதிப்பு தேவை. X11 முயற்சிக்கவும் அல்லது OS மாற்றவும்."),
|
||||
("ubuntu-21-04-required", "Wayland க்கு Ubuntu 21.04+ தேவை"),
|
||||
("wayland-requires-higher-linux-version", "Wayland க்கு உயர் Linux பதிப்பு தேவை. X11 முயற்சிக்கவும் அல்லது OS மாற்றவும்."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "ஜம்ப் லிங்க்"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "பகிரப்பட வேண்டிய திரை தேர்ந்தெடுக்கவும்"),
|
||||
("Show RustDesk", "RustDesk ஐ காட்டு"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "{} உடன் தொடர்"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", ""),
|
||||
("Full Access", ""),
|
||||
("Screen Share", ""),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", ""),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", ""),
|
||||
("ubuntu-21-04-required", ""),
|
||||
("wayland-requires-higher-linux-version", ""),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", ""),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", ""),
|
||||
("Show RustDesk", ""),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", ""),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "การตั้งค่าคีย์บอร์ด"),
|
||||
("Full Access", "การเข้าถึงทั้งหมด"),
|
||||
("Screen Share", "การแชร์จอ"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland ต้องการ Ubuntu เวอร์ชัน 21.04 หรือสูงกว่า"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland ต้องการลินุกซ์เวอร์ชันที่สูงกว่านี้ กรุณาเปลี่ยนไปใช้เดสก์ท็อป X11 หรือเปลี่ยนระบบปฏิบัติการของคุณ"),
|
||||
("ubuntu-21-04-required", "Wayland ต้องการ Ubuntu เวอร์ชัน 21.04 หรือสูงกว่า"),
|
||||
("wayland-requires-higher-linux-version", "Wayland ต้องการลินุกซ์เวอร์ชันที่สูงกว่านี้ กรุณาเปลี่ยนไปใช้เดสก์ท็อป X11 หรือเปลี่ยนระบบปฏิบัติการของคุณ"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "กรุณาเลือกหน้าจอที่ต้องการแชร์ (ใช้งานในอีกฝั่งของการเชื่อมต่อ)"),
|
||||
("Show RustDesk", "แสดง RustDesk"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", ""),
|
||||
("Continue with {}", "ทำต่อด้วย {}"),
|
||||
("Display Name", ""),
|
||||
("password-hidden-tip", ""),
|
||||
("preset-password-in-use-tip", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "Klavye Ayarları"),
|
||||
("Full Access", "Tam Erişim"),
|
||||
("Screen Share", "Ekran Paylaşımı"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland, Ubuntu 21.04 veya daha yüksek bir sürüm gerektirir."),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland, linux dağıtımının daha yüksek bir sürümünü gerektirir. Lütfen X11 masaüstünü deneyin veya işletim sisteminizi değiştirin."),
|
||||
("ubuntu-21-04-required", "Wayland, Ubuntu 21.04 veya daha yüksek bir sürüm gerektirir."),
|
||||
("wayland-requires-higher-linux-version", "Wayland, linux dağıtımının daha yüksek bir sürümünü gerektirir. Lütfen X11 masaüstünü deneyin veya işletim sisteminizi değiştirin."),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "View"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Lütfen paylaşılacak ekranı seçiniz (Ekran tarafında çalıştırın)."),
|
||||
("Show RustDesk", "RustDesk'i Göster"),
|
||||
|
|
@ -740,5 +741,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-incoming-sessions-label", "Gelen oturumlar süresince ekranı açık tutun"),
|
||||
("Continue with {}", "{} ile devam et"),
|
||||
("Display Name", "Görünen Ad"),
|
||||
("password-hidden-tip", "Şifre gizli"),
|
||||
("preset-password-in-use-tip", "Önceden ayarlanmış şifre kullanılıyor"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Keyboard Settings", "鍵盤設定"),
|
||||
("Full Access", "完全存取"),
|
||||
("Screen Share", "僅分享螢幕畫面"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland 需要 Ubuntu 21.04 或更新的版本。"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更新版的 Linux 發行版。請嘗試使用 X11 桌面或更改您的作業系統。"),
|
||||
("ubuntu-21-04-required", "Wayland 需要 Ubuntu 21.04 或更新的版本。"),
|
||||
("wayland-requires-higher-linux-version", "Wayland 需要更新版的 Linux 發行版。請嘗試使用 X11 桌面或更改您的作業系統。"),
|
||||
("xdp-portal-unavailable", ""),
|
||||
("JumpLink", "查看"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "請選擇要分享的螢幕畫面(在對方的裝置上操作)。"),
|
||||
("Show RustDesk", "顯示 RustDesk"),
|
||||
|
|
@ -739,6 +740,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("keep-awake-during-outgoing-sessions-label", "在連出工作階段期間保持螢幕喚醒"),
|
||||
("keep-awake-during-incoming-sessions-label", "在連入工作階段期間保持螢幕喚醒"),
|
||||
("Continue with {}", "使用 {} 登入"),
|
||||
("Display Name", ""),
|
||||
("Display Name", "顯示名稱"),
|
||||
("password-hidden-tip", "固定密碼已設定(已隱藏)"),
|
||||
("preset-password-in-use-tip", "目前正在使用預設密碼"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue