Merge remote-tracking branch 'upstream/master' into fix/mobile-scale-custom-pr

This commit is contained in:
Alessandro De Blasis
2025-10-29 09:48:13 +01:00
19 changed files with 497 additions and 223 deletions

View File

@@ -4,7 +4,7 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>] | [<a href="docs/README-NO.md">Norsk</a>]<br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>] | [<a href="docs/README-NO.md">Norsk</a>] | [<a href="docs/README-RO.md">Română</a>]<br>
<b>We need your help to translate this README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> and <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> to your native language</b>
</p>

View File

@@ -0,0 +1,85 @@
# Codul de Conduită al Contributorilor
## Angajamentul Nostru
Noi, ca membri, contribuitori și lideri, ne angajăm să facem ca participarea în comunitatea noastră să fie o experiență fără hărțuire pentru toată lumea, indiferent de vârstă, dimensiunea corpului, dizabilități vizibile sau invizibile, etnie, caracteristici sexuale, identitate și exprimare de gen, nivel de experiență, educație, statut socio-economic, naționalitate, aspect personal, rasă, religie sau identitate și orientare sexuală.
Ne angajăm să acționăm și să interacționăm în moduri care contribuie la o comunitate deschisă, primitoare, diversă, incluzivă și sănătoasă.
## Standardele Noastre
Exemple de comportamente care contribuie la un mediu pozitiv pentru comunitatea noastră includ:
* Demonstrarea empatiei și a bunătății față de ceilalți
* Respectarea opiniilor, punctelor de vedere și experiențelor diferite
* Oferirea și acceptarea cu grație a feedback-ului constructiv
* Asumarea responsabilității și cererea de scuze celor afectați de greșelile noastre și învățarea din experiență
* Concentrarea pe ceea ce este cel mai bun nu doar pentru noi ca indivizi, ci pentru întreaga comunitate
Exemple de comportamente inacceptabile includ:
* Utilizarea limbajului sau imaginilor sexualizate, precum și atenția sau avansurile sexuale de orice fel
* Trollare, insulte sau comentarii denigratoare și atacuri personale sau politice
* Hărțuire publică sau privată
* Publicarea informațiilor private ale altora, cum ar fi adresa fizică sau de e-mail, fără permisiunea explicită
* Alte comportamente care ar putea fi considerate inadecvate într-un cadru profesional
## Responsabilități de Aplicare
Liderii comunității sunt responsabili pentru clarificarea și aplicarea standardelor noastre de comportament acceptabil și vor lua măsuri corective adecvate și echitabile ca răspuns la orice comportament pe care îl consideră inadecvat, amenințător, ofensator sau dăunător.
Liderii comunității au dreptul și responsabilitatea de a elimina, edita sau respinge comentarii, commit-uri, cod, editări wiki, probleme și alte contribuții care nu se aliniază acestui Cod de Conduită și vor comunica motivele pentru deciziile de moderare atunci când este cazul.
## Domeniu de Aplicare
Acest Cod de Conduită se aplică în toate spațiile comunității și se aplică și atunci când un individ reprezintă oficial comunitatea în spații publice.
Exemple de reprezentare a comunității includ utilizarea unei adrese de e-mail oficiale, postarea printr-un cont oficial de social media sau acționarea ca reprezentant desemnat la un eveniment online sau offline.
## Aplicare
Cazurile de comportament abuziv, hărțuitor sau altfel inacceptabil pot fi raportate liderilor comunității responsabili pentru aplicare la [info@rustdesk.com](mailto:info@rustdesk.com).
Toate plângerile vor fi revizuite și investigate prompt și corect.
Toți liderii comunității sunt obligați să respecte confidențialitatea și securitatea persoanei care raportează orice incident.
## Ghiduri de Aplicare
Liderii comunității vor urma aceste Ghiduri privind Impactul Comunității pentru a stabili consecințele pentru orice acțiune pe care o consideră o încălcare a acestui Cod de Conduită:
### 1. Corectare
**Impact asupra comunității**: Utilizarea limbajului neadecvat sau alte comportamente considerate neprofesionale sau nedorite în comunitate.
**Consecință**: O avertizare scrisă și privată din partea liderilor comunității, oferind claritate asupra naturii încălcării și o explicație despre motivul pentru care comportamentul a fost inadecvat. Poate fi cerută o scuză publică.
### 2. Avertisment
**Impact asupra comunității**: Încălcare printr-un incident singular sau o serie de acțiuni.
**Consecință**: Un avertisment cu consecințe pentru continuarea comportamentului. Nicio interacțiune cu persoanele implicate, inclusiv interacțiuni nesolicitate cu cei care aplică Codul de Conduită, pentru o perioadă specificată. Aceasta include evitarea interacțiunilor în spațiile comunității, precum și pe canale externe, cum ar fi rețelele sociale. Încălcarea acestor termeni poate duce la o suspendare temporară sau permanentă.
### 3. Suspendare Temporară
**Impact asupra comunității**: O încălcare serioasă a standardelor comunității, inclusiv comportament neadecvat susținut.
**Consecință**: Suspendare temporară de la orice tip de interacțiune sau comunicare publică cu comunitatea pentru o perioadă specificată. Nicio interacțiune publică sau privată cu persoanele implicate, inclusiv interacțiuni nesolicitate cu cei care aplică Codul de Conduită, nu este permisă în această perioadă. Încălcarea acestor termeni poate duce la o interdicție permanentă.
### 4. Interdicție Permanentă
**Impact asupra comunității**: Demonstrând un tipar de încălcare a standardelor comunității, inclusiv comportament neadecvat susținut, hărțuire a unei persoane sau agresiune față de sau denigrare a unor grupuri de persoane.
**Consecință**: Interdicție permanentă de la orice tip de interacțiune publică în cadrul comunității.
## Atribuire
Acest Cod de Conduită este adaptat din [Contributor Covenant][homepage], versiunea 2.0, disponibil la [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Ghidurile privind Impactul Comunității au fost inspirate de [scara de aplicare a codului de conduită Mozilla][Mozilla CoC].
Pentru răspunsuri la întrebări frecvente despre acest cod de conduită, vezi FAQ la [https://www.contributor-covenant.org/faq][FAQ]. Traduceri sunt disponibile la [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

31
docs/CONTRIBUTING-RO.md Normal file
View File

@@ -0,0 +1,31 @@
# Contribuții la RustDesk
RustDesk primește cu plăcere contribuții din partea tuturor. Iată ghidurile dacă te gândești să ne ajuți:
## Contribuții
Contribuțiile la RustDesk sau la dependențele sale ar trebui făcute sub forma de pull request-uri pe GitHub. Fiecare pull request va fi revizuit de un contributor principal (cineva cu permisiunea de a aplica patch-uri) și fie va fi integrat în arborele principal, fie vor fi oferite sugestii pentru modificările necesare. Toate contribuțiile trebuie să urmeze acest format, chiar și cele ale contributorilor principali.
Dacă dorești să lucrezi la o problemă, te rugăm să o revendici mai întâi comentând pe GitHub issue-ul pe care vrei să lucrezi. Aceasta previne eforturi duplicate din partea contributorilor asupra aceleiași probleme.
## Lista de verificare pentru Pull Request
- Creează un branch din branch-ul `master` și, dacă este necesar, fă rebase la branch-ul `master` curent înainte de a trimite pull request-ul. Dacă nu se poate integra curat cu `master`, ți se poate cere să faci rebase la modificările tale.
- Commit-urile ar trebui să fie cât mai mici posibil, asigurând totodată că fiecare commit este corect independent (adică fiecare commit ar trebui să compileze și să treacă testele).
- Commit-urile trebuie să fie însoțite de un semnătura Developer Certificate of Origin (http://developercertificate.org), care indică faptul că tu (și angajatorul tău, dacă este cazul) ești de acord să respecți termenii [licenței proiectului](../LICENCE). În git, aceasta este opțiunea `-s` la `git commit`.
- Dacă patch-ul tău nu este revizuit sau ai nevoie ca o anumită persoană să-l revizuiască, poți @-reply unui reviewer cerând o revizuire în pull request sau într-un comentariu, sau poți solicita o revizuire prin [email](mailto:info@rustdesk.com).
- Adaugă teste relevante pentru bug-ul corectat sau pentru funcționalitatea nouă.
Pentru instrucțiuni specifice git, vezi [GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow).
## Conduită
[Codul de Conduită RustDesk](https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md)
## Comunicare
Contributorii RustDesk frecventează [Discord](https://discord.gg/nDceKgxnkV).

181
docs/README-RO.md Normal file
View File

@@ -0,0 +1,181 @@
<p align="center">
<img src="../res/logo-header.svg" alt="RustDesk - desktopul tău la distanță"><br>
<a href="../README.md#raw-steps-to-build">Construire</a> •
<a href="../README.md#how-to-build-with-docker">Docker</a> •
<a href="../README.md#file-structure">Structură</a> •
<a href="../README.md#snapshot">Capturi</a><br>
[<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>] | [<a href="README-NO.md">Norsk</a>] | [<a href="README-RO.md">Română</a>]<br>
<b>Avem nevoie de ajutorul tău pentru a traduce acest README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> și <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> în limba ta maternă</b>
</p>
> [!Atenție]
> **Declinare de responsabilitate privind utilizarea abuzivă:** <br>
> Dezvoltatorii RustDesk nu susțin sau aprobă utilizarea neetică sau ilegală a acestui software. Utilizarea abuzivă, cum ar fi accesul neautorizat, controlul sau invadarea intimității, este strict împotriva regulilor noastre. Autorii nu sunt responsabili pentru utilizarea necorespunzătoare a aplicației.
Conversați cu noi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Advanced%20Features-blue)](https://rustdesk.com/pricing.html)
Încă o soluție de desktop la distanță scrisă în Rust. Funcționează imediat, fără configurare necesară. Ai control total asupra datelor tale, fără probleme de securitate. Poți folosi serverul nostru de rendezvous/relay, [să-ți configurezi propriul server](https://rustdesk.com/server) sau [să scrii propriul server de rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
![imagine](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk primește contribuții de la oricine. Vezi [CONTRIBUTING.md](../docs/CONTRIBUTING.md) pentru ajutor la început.
[**ÎNTREBĂRI FRECVENTE (FAQ)**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
[**DESCĂRCARE BINARE**](https://github.com/rustdesk/rustdesk/releases)
[**BUILD NIGHTLY**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Get it on Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Dependențe
Versiunile desktop folosesc Flutter sau Sciter (depreciat) pentru interfață; acest ghid este pentru Sciter doar, deoarece este mai ușor și mai prietenos pentru început. Vezi [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) pentru construire cu Flutter.
Te rugăm să descarci singur librăria dinamică Sciter.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Pași pentru construire (Raw Steps to build)
- Pregătește mediul de dezvoltare Rust și mediul de construire C++
- Instalează [vcpkg](https://github.com/microsoft/vcpkg) și setează corect variabila de mediu `VCPKG_ROOT`
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/macOS: vcpkg install libvpx libyuv opus aom
- rulează `cargo run`
## [Construire](https://rustdesk.com/docs/en/dev/build/)
## Cum se construiește pe Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
```
### Instalează vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2023.04.15
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus aom
```
### Repară libvpx (Pentru Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Build
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
## Cum să construiești cu Docker
Începe prin clonarea repository-ului și construirea imaginii Docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
Apoi, de fiecare dată când trebuie să construiești aplicația, rulează comanda următoare:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Reține că prima construire poate dura mai mult până când dependențele sunt în cache; construirile ulterioare vor fi mai rapide. De asemenea, dacă trebuie să specifici argumente diferite comenzii de build, le poți adăuga la finalul comenzii în poziția `<OPTIONAL-ARGS>`. De exemplu, pentru a construi o versiune optimizată de release, adaugă `--release`. Executabilul rezultat va fi disponibil în folderul `target` pe sistemul tău, și poate fi rulat cu:
```sh
target/debug/rustdesk
```
Sau, dacă rulezi un executabil release:
```sh
target/release/rustdesk
```
Asigură-te că rulezi aceste comenzi din rădăcina repository-ului RustDesk, altfel aplicația poate să nu găsească resursele necesare. De asemenea, reține că alte subcomenzi cargo, cum ar fi `install` sau `run`, nu sunt acceptate în prezent prin această metodă, deoarece ar instala sau rula programul în interiorul containerului în loc de gazdă.
## Structura fișierelor
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec video, config, wrapper tcp/udp, protobuf, funcții fs pentru transfer de fișiere și alte funcții utilitare
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: capturare ecran
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: control tastatură/mouse specific platformei
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: implementare copy/paste pentru fișiere pentru Windows, Linux, macOS.
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: interfață Sciter învechită (depreciată)
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: servicii audio/clipboard/input/video și conexiuni de rețea
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: inițiază o conexiune peer
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: comunică cu [rustdesk-server](https://github.com/rustdesk/rustdesk-server), așteaptă conexiune directă remote (TCP hole punching) sau prin relay
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: cod specific platformei
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: cod Flutter pentru desktop și mobil
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript pentru clientul Flutter web
## Capturi de ecran
![Connection Manager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![Connected to a Windows PC](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![File Transfer](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![TCP Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

9
docs/SECURITY-RO.md Normal file
View File

@@ -0,0 +1,9 @@
# Politica de Securitate
## Raportarea unei Vulnerabilități
Acordăm o mare importanță securității proiectului. Încurajăm toți utilizatorii să ne raporteze orice vulnerabilități pe care le descoperă.
Dacă găsești o vulnerabilitate de securitate în proiectul RustDesk, te rugăm să o raportezi responsabil trimițând un e-mail la info@rustdesk.com.
În acest moment, nu avem un program de recompense pentru descoperirea de bug-uri. Suntem o echipă mică care încearcă să rezolve o problemă mare.
Te rugăm să raportezi orice vulnerabilitate în mod responsabil, astfel încât să putem continua să construim o aplicație sigură pentru întreaga comunitate.

View File

@@ -2121,15 +2121,20 @@ void showWindowsSessionsDialog(
return CustomAlertDialog(
title: null,
content: msgboxContent(type, title, text),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
msgboxContent(type, title, text).marginOnly(bottom: 12),
ComboBox(
keys: sids,
values: names,
initialKey: selectedUserValue,
onChanged: (value) {
selectedUserValue = value;
}),
],
),
actions: [
ComboBox(
keys: sids,
values: names,
initialKey: selectedUserValue,
onChanged: (value) {
selectedUserValue = value;
}),
dialogButton('Connect', onPressed: submit, isOutline: false),
],
);

View File

@@ -364,11 +364,12 @@ Future<List<TRadioMenu<String>>> toolbarViewStyle(
value: kRemoteViewStyleAdaptive,
groupValue: groupValue,
onChanged: onChanged),
TRadioMenu<String>(
child: Text(translate('Scale custom')),
value: kRemoteViewStyleCustom,
groupValue: groupValue,
onChanged: onChanged)
if (isDesktop || isWebDesktop)
TRadioMenu<String>(
child: Text(translate('Scale custom')),
value: kRemoteViewStyleCustom,
groupValue: groupValue,
onChanged: onChanged)
];
}

View File

@@ -61,9 +61,11 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
String? connToken,
}) {
final tabKey = '${peerId}_$terminalId';
final alias = bind.mainGetPeerOptionSync(id: peerId, key: 'alias');
final tabLabel = alias.isNotEmpty ? '$alias #$terminalId' : '$peerId #$terminalId';
return TabInfo(
key: tabKey,
label: '$peerId #$terminalId',
label: tabLabel,
selectedIcon: selectedIcon,
unselectedIcon: unselectedIcon,
onTabCloseButton: () async {

View File

@@ -153,135 +153,6 @@ class _ToolbarTheme {
typedef DismissFunc = void Function();
class RemoteMenuEntry {
static MenuEntryRadios<String> viewStyle(
String remoteId,
FFI ffi,
EdgeInsets padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
RxString? rxViewStyle,
}) {
return MenuEntryRadios<String>(
text: translate('Ratio'),
optionsGetter: () => [
MenuEntryRadioOption(
text: translate('Scale original'),
value: kRemoteViewStyleOriginal,
dismissOnClicked: true,
dismissCallback: dismissCallback,
),
MenuEntryRadioOption(
text: translate('Scale adaptive'),
value: kRemoteViewStyleAdaptive,
dismissOnClicked: true,
dismissCallback: dismissCallback,
),
MenuEntryRadioOption(
text: translate('Scale custom'),
value: kRemoteViewStyleCustom,
dismissOnClicked: true,
dismissCallback: dismissCallback,
),
],
curOptionGetter: () async {
// null means peer id is not found, which there's no need to care about
final viewStyle =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
if (rxViewStyle != null) {
rxViewStyle.value = viewStyle;
}
return viewStyle;
},
optionSetter: (String oldValue, String newValue) async {
await bind.sessionSetViewStyle(
sessionId: ffi.sessionId, value: newValue);
if (rxViewStyle != null) {
rxViewStyle.value = newValue;
}
ffi.canvasModel.updateViewStyle();
if (dismissFunc != null) {
dismissFunc();
}
},
padding: padding,
dismissOnClicked: true,
dismissCallback: dismissCallback,
);
}
static MenuEntrySwitch2<String> showRemoteCursor(
String remoteId,
SessionID sessionId,
EdgeInsets padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
final state = ShowRemoteCursorState.find(remoteId);
final optKey = 'show-remote-cursor';
return MenuEntrySwitch2<String>(
switchType: SwitchType.scheckbox,
text: translate('Show remote cursor'),
getter: () {
return state;
},
setter: (bool v) async {
await bind.sessionToggleOption(sessionId: sessionId, value: optKey);
state.value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: optKey);
if (dismissFunc != null) {
dismissFunc();
}
},
padding: padding,
dismissOnClicked: true,
dismissCallback: dismissCallback,
);
}
static MenuEntrySwitch<String> disableClipboard(
SessionID sessionId,
EdgeInsets? padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
return createSwitchMenuEntry(
sessionId,
'Disable clipboard',
'disable-clipboard',
padding,
true,
dismissCallback: dismissCallback,
);
}
static MenuEntrySwitch<String> createSwitchMenuEntry(
SessionID sessionId,
String text,
String option,
EdgeInsets? padding,
bool dismissOnClicked, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
return MenuEntrySwitch<String>(
switchType: SwitchType.scheckbox,
text: translate(text),
getter: () async {
return bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: option);
},
setter: (bool v) async {
await bind.sessionToggleOption(sessionId: sessionId, value: option);
if (dismissFunc != null) {
dismissFunc();
}
},
padding: padding,
dismissOnClicked: dismissOnClicked,
dismissCallback: dismissCallback,
);
}
static MenuEntryButton<String> insertLock(
SessionID sessionId,
EdgeInsets? padding, {

View File

@@ -92,6 +92,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
gFFI.dialogManager.dismissAll();
WakelockPlus.disable();
});
model.jobController.clear();
super.dispose();
}

View File

@@ -1033,30 +1033,54 @@ class JobController {
await bind.sessionCancelJob(sessionId: sessionId, actId: id);
}
void loadLastJob(Map<String, dynamic> evt) {
Future<void> loadLastJob(Map<String, dynamic> evt) async {
debugPrint("load last job: $evt");
Map<String, dynamic> jobDetail = json.decode(evt['value']);
// int id = int.parse(jobDetail['id']);
String remote = jobDetail['remote'];
String to = jobDetail['to'];
bool showHidden = jobDetail['show_hidden'];
int fileNum = jobDetail['file_num'];
bool isRemote = jobDetail['is_remote'];
final currJobId = JobController.jobID.next();
String fileName = path.basename(isRemote ? remote : to);
var jobProgress = JobProgress()
..type = JobType.transfer
..fileName = fileName
..jobName = isRemote ? remote : to
..id = currJobId
..isRemoteToLocal = isRemote
..fileNum = fileNum
..remote = remote
..to = to
..showHidden = showHidden
..state = JobState.paused;
jobTable.add(jobProgress);
bind.sessionAddJob(
bool isAutoStart = jobDetail['auto_start'] == true;
int currJobId = -1;
if (isAutoStart) {
// Ensure jobDetail['id'] exists and is an int
if (jobDetail.containsKey('id') &&
jobDetail['id'] != null &&
jobDetail['id'] is int) {
currJobId = jobDetail['id'];
}
}
if (currJobId < 0) {
// If id is missing or invalid, disable auto-start and assign a new job id
isAutoStart = false;
currJobId = JobController.jobID.next();
}
if (!isAutoStart) {
if (!(isDesktop || isWebDesktop)) {
// Don't add to job table if not auto start on mobile.
// Because mobile does not support job list view now.
return;
}
// Add to job table if not auto start on desktop.
String fileName = path.basename(isRemote ? remote : to);
final jobProgress = JobProgress()
..type = JobType.transfer
..fileName = fileName
..jobName = isRemote ? remote : to
..id = currJobId
..isRemoteToLocal = isRemote
..fileNum = fileNum
..remote = remote
..to = to
..showHidden = showHidden
..state = JobState.paused;
jobTable.add(jobProgress);
}
await bind.sessionAddJob(
sessionId: sessionId,
isRemote: isRemote,
includeHidden: showHidden,
@@ -1065,6 +1089,11 @@ class JobController {
to: isRemote ? to : remote,
fileNum: fileNum,
);
if (isAutoStart) {
await bind.sessionResumeJob(
sessionId: sessionId, actId: currJobId, isRemote: isRemote);
}
}
void resumeJob(int jobId) {
@@ -1095,6 +1124,11 @@ class JobController {
}
debugPrint("update folder files: $info");
}
void clear() {
jobTable.clear();
jobResultListener.clear();
}
}
class JobResultListener<T> {

View File

@@ -687,7 +687,7 @@ pub fn check_available_hwcodec() -> String {
height: 720,
pixfmt: DEFAULT_PIXFMT,
align: HW_STRIDE_ALIGN as _,
kbs: 0,
kbs: 1000,
fps: DEFAULT_FPS,
gop: DEFAULT_GOP,
quality: DEFAULT_HW_QUALITY,

View File

@@ -23,7 +23,7 @@ use std::{
os::raw::{c_char, c_int, c_void},
str::FromStr,
sync::{
atomic::{AtomicBool, Ordering},
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc, RwLock,
},
};
@@ -756,7 +756,7 @@ impl InvokeUiSession for FlutterHandler {
// unused in flutter
fn clear_all_jobs(&self) {}
fn load_last_job(&self, _cnt: i32, job_json: &str) {
fn load_last_job(&self, _cnt: i32, job_json: &str, _auto_start: bool) {
self.push_event("load_last_job", &[("value", job_json)], &[]);
}
@@ -1328,6 +1328,7 @@ pub fn session_add(
server_keyboard_enabled: Arc::new(RwLock::new(true)),
server_file_transfer_enabled: Arc::new(RwLock::new(true)),
server_clipboard_enabled: Arc::new(RwLock::new(true)),
reconnect_count: Arc::new(AtomicUsize::new(0)),
..Default::default()
};

View File

@@ -652,18 +652,18 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Untagged", "Sense etiquetar"),
("new-version-of-{}-tip", ""),
("Accessible devices", "Dispositius accessibles"),
("upgrade_remote_rustdesk_client_to_{}_tip", "Veuillez mettre à niveau le client RustDesk vers la version {} ou plus récente du côté distant !"),
("upgrade_remote_rustdesk_client_to_{}_tip", ""),
("d3d_render_tip", ""),
("Use D3D rendering", ""),
("Printer", ""),
("Use D3D rendering", "Utilitza renderització D3D"),
("Printer", "Impressora"),
("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", ""),
("Install {} Printer", "Instal·la {} impressora"),
("Outgoing Print Jobs", "Treballs d'impressió sortints"),
("Incoming Print Jobs", "Treballs d'impressió entrants"),
("Incoming Print Job", "Treballs d'impressió entrant"),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
("auto-print-tip", ""),
@@ -672,54 +672,54 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("Take screenshot", "Fes una captura de pantalla"),
("Taking screenshot", "Fent la captura de pantalla"),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
("Enable remote printer", ""),
("Downloading {}", ""),
("{} Update", ""),
("Save as", "Anomena i desa"),
("Copy to clipboard", "Copia al porta-retalls"),
("Enable remote printer", "Habilita l'impressora remota"),
("Downloading {}", "Descarregant {}"),
("{} Update", "{} Actualitza"),
("{}-to-update-tip", ""),
("download-new-version-failed-tip", ""),
("Auto update", ""),
("Auto update", "Actualització automàtica"),
("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", ""),
("Trackpad speed", "Velocitat del trackpad"),
("Default trackpad speed", "Velocitat per defecte del trackpad"),
("Numeric one-time password", "Contrasenya numèrica d'un sol ús"),
("Enable IPv6 P2P connection", "Habilita la connexió IPv6 P2P"),
("Enable UDP hole punching", "Activa la perforació UDP"),
("View camera", "Mostra la càmera"),
("Enable camera", ""),
("No cameras", ""),
("Enable camera", "Habilita la càmera"),
("No cameras", "No hi ha càmeres"),
("view_camera_unsupported_tip", ""),
("Terminal", ""),
("Enable terminal", ""),
("New tab", ""),
("Keep terminal sessions on disconnect", ""),
("Terminal (Run as administrator)", ""),
("Terminal", "Terminal"),
("Enable terminal", "Habilita el terminal"),
("New tab", "Nova finestra"),
("Keep terminal sessions on disconnect", "Mantingues les sessions de terminal desconnectades"),
("Terminal (Run as administrator)", "Terminal (executa com a administrador"),
("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.", ""),
("Failed to get user token.", "No s'ha pogut obtenir el token d'usuari."),
("Incorrect username or password.", "Nom d'usuari o contrasenya incorrecte"),
("The user is not an administrator.", "Aquest usuari no és administrador"),
("Failed to check if the user is an administrator.", "No s'ha pogut comprovar si l'usuari és administrador."),
("Supported only in the installed version.", "Només compatible amb la versió instal·lada."),
("elevation_username_tip", ""),
("Preparing for installation ...", ""),
("Show my cursor", ""),
("Preparing for installation ...", "Preparant per a l'instal·lació..."),
("Show my cursor", "Mostra el meu punter"),
("Scale custom", "Escala personalitzada"),
("Custom scale slider", "Control lliscant d'escala personalitzada"),
("Decrease", "Disminueix"),
("Increase", "Augmenta"),
("Show virtual mouse", ""),
("Virtual mouse size", ""),
("Small", ""),
("Large", ""),
("Show virtual joystick", ""),
("Edit note", ""),
("Alias", ""),
("Show virtual mouse", "Mostra el ratolí virtual"),
("Virtual mouse size", "Mida del ratolí virtual"),
("Small", "Petita"),
("Large", "Gran"),
("Show virtual joystick", "Mostra el joystick virtual"),
("Edit note", "Edita la nota"),
("Alias", "Alias"),
].iter().cloned().collect();
}

View File

@@ -679,7 +679,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Save as", "Guardar como"),
("Copy to clipboard", "Copiar al portapapeles"),
("Enable remote printer", "Habilitar impresora remota"),
("Downloading {}", "Descarngando {}"),
("Downloading {}", "Descargando {}"),
("{} Update", "{} Actualizar"),
("{}-to-update-tip", "{} Se cerrará ahora e instalará la nueva versión."),
("download-new-version-failed-tip", "Descarga fallida. Puedes volver a intentarlo o hacer clic en el botón \"Download\" para descargar desde la página de lanzamientos y actualizar manualmente."),

View File

@@ -128,7 +128,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Custom", "カスタム"),
("Show remote cursor", "リモートコンピューターのカーソルを表示する"),
("Show quality monitor", "ディスプレイの品質を表示する"),
("Disable clipboard", "クリップボードを無効化"),
("Disable clipboard", "クリップボードを無効化する"),
("Lock after session end", "セッション終了後にロックする"),
("Insert Ctrl + Alt + Del", "Ctrl + Alt + Del を送信"),
("Insert Lock", "ロック命令を送信"),
@@ -463,7 +463,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty Password", "空のパスワード"),
("Me", "あなた"),
("identical_file_tip", "このファイルはリモートコンピューターと同一です。"),
("show_monitors_tip", "ツールバーにディスプレイを表示します。"),
("show_monitors_tip", "ツールバーにディスプレイを表示する"),
("View Mode", "表示モード"),
("login_linux_tip", "X デスクトップのセッションにログインするには、リモートコンピューターのLinuxアカウントにログインする必要があります。"),
("verify_rustdesk_password_tip", "RustDesk のパスワードを確認する"),
@@ -548,7 +548,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("display_is_plugged_out_msg", "ディスプレイが接続されていません。最初のディスプレイを選択してください。"),
("No displays", "ディスプレイがありません"),
("Open in new window", "新しいウィンドウで開く"),
("Show displays as individual windows", "ディスプレイを別のウィンドウとして表示する"),
("Show displays as individual windows", "ディスプレイを別のウィンドウとして表示する"),
("Use all my displays for the remote session", "すべてのディスプレイをセッションで使用する"),
("selinux_tip", "SELinuxが有効になっているため、RustDesk が正常に動作しない可能性があります。"),
("Change view", "表示を変更"),
@@ -557,7 +557,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("List", "リスト"),
("Virtual display", "仮想ディスプレイ"),
("Plug out all", "すべて切断"),
("True color (4:4:4)", "True color (4:4:4)"),
("True color (4:4:4)", "True Color (4:4:4)"),
("Enable blocking user input", "ユーザー入力のブロックを有効化する"),
("id_input_tip", "ID、IPアドレス、またはドメインとポート番号(<ドメイン>:<ポート>)を使用できます。\n他のサーバーのデバイスにアクセスしたい場合は、サーバーアドレス(<id>@<サーバーアドレス>?key=<キーの値>)を追加してください。 \n(例: 9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=)\nパブリックサーバーのデバイスに接続したい場合は、「<id>@public」のように入力してください。パブリックサーバーの場合、キーは不要です。\n\n初回接続で中継接続を行いたい場合は、「9123456234/r」のように末尾に「/r」を付けてください。"),
("privacy_mode_impl_mag_tip", "モード 1"),
@@ -719,7 +719,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Small", ""),
("Large", ""),
("Show virtual joystick", "仮想ジョイスティックを表示する"),
("Edit note", ""),
("Alias", ""),
("Edit note", "メモを編集"),
("Alias", "エイリアス"),
].iter().cloned().collect();
}

View File

@@ -137,7 +137,7 @@ class JobTable: Reactor.Component {
self.timer(30ms, function() { self.update(); });
}
function addJob(id, path, to, file_num, show_hidden, is_remote) {
function addJob(id, path, to, file_num, show_hidden, is_remote, auto_start) {
var job = { type: "transfer",
id: id, path: path, to: to,
include_hidden: show_hidden,
@@ -146,6 +146,10 @@ class JobTable: Reactor.Component {
this.job_map[id] = this.jobs[this.jobs.length - 1];
handler.update_next_job_id(id + 1);
handler.add_job(id, 0, path, to, file_num, show_hidden, is_remote);
if (auto_start) {
this.continueJob(id);
this.update();
}
stdout.println(JSON.stringify(job));
}
@@ -279,7 +283,8 @@ class JobTable: Reactor.Component {
if (!err) {
handler.remove_dir(job.id, job.path, job.is_remote);
refreshDir(job.is_remote);
if (is_remote) file_transfer.remote_folder_view.table.resetCurrent();
// Use the job's is_remote; local variable `is_remote` is undefined in this scope.
if (job.is_remote) file_transfer.remote_folder_view.table.resetCurrent();
else file_transfer.local_folder_view.table.resetCurrent();
}
} else if (!job.no_confirm) {
@@ -697,9 +702,9 @@ handler.clearAllJobs = function() {
file_transfer.job_table.clearAllJobs();
}
handler.addJob = function (id, path, to, file_num, show_hidden, is_remote) { // load last job
handler.addJob = function (id, path, to, file_num, show_hidden, is_remote, auto_start) { // load last job
// stdout.println("restore job: " + is_remote);
file_transfer.job_table.addJob(id,path,to,file_num,show_hidden,is_remote);
file_transfer.job_table.addJob(id,path,to,file_num,show_hidden,is_remote,auto_start);
}
handler.updateTransferList = function () {

View File

@@ -1,7 +1,7 @@
use std::{
collections::HashMap,
ops::{Deref, DerefMut},
sync::{Arc, Mutex, RwLock},
sync::{atomic::AtomicUsize, Arc, Mutex, RwLock},
};
use sciter::{
@@ -199,7 +199,7 @@ impl InvokeUiSession for SciterHandler {
self.call("clearAllJobs", &make_args!());
}
fn load_last_job(&self, cnt: i32, job_json: &str) {
fn load_last_job(&self, cnt: i32, job_json: &str, auto_start: bool) {
let job: Result<TransferJobMeta, serde_json::Error> = serde_json::from_str(job_json);
if let Ok(job) = job {
let path;
@@ -213,7 +213,15 @@ impl InvokeUiSession for SciterHandler {
}
self.call(
"addJob",
&make_args!(cnt, path, to, job.file_num, job.show_hidden, job.is_remote),
&make_args!(
cnt,
path,
to,
job.file_num,
job.show_hidden,
job.is_remote,
auto_start
),
);
}
}
@@ -570,6 +578,7 @@ impl SciterSession {
server_keyboard_enabled: Arc::new(RwLock::new(true)),
server_file_transfer_enabled: Arc::new(RwLock::new(true)),
server_clipboard_enabled: Arc::new(RwLock::new(true)),
reconnect_count: Arc::new(AtomicUsize::new(0)),
..Default::default()
};

View File

@@ -29,7 +29,10 @@ use std::{
collections::HashMap,
ops::{Deref, DerefMut},
str::FromStr,
sync::{Arc, Mutex, RwLock},
sync::{
atomic::{AtomicUsize, Ordering},
Arc, Mutex, RwLock,
},
time::SystemTime,
};
use uuid::Uuid;
@@ -61,6 +64,9 @@ pub struct Session<T: InvokeUiSession> {
pub last_change_display: Arc<Mutex<ChangeDisplayRecord>>,
pub connection_round_state: Arc<Mutex<ConnectionRoundState>>,
pub printer_names: Arc<RwLock<HashMap<i32, String>>>,
// Indicate whether the session is reconnected.
// Used to auto start file transfer after reconnection.
pub reconnect_count: Arc<AtomicUsize>,
}
#[derive(Clone)]
@@ -1272,6 +1278,7 @@ impl<T: InvokeUiSession> Session<T> {
self.lc.write().unwrap().force_relay = true;
}
self.lc.write().unwrap().peer_info = None;
self.reconnect_count.fetch_add(1, Ordering::SeqCst);
let mut lock = self.thread.lock().unwrap();
// No need to join the previous thread, because it will exit automatically.
// And the previous thread will not change important states.
@@ -1372,6 +1379,24 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::Close);
}
fn try_auto_start_job_str(is_reconnected: bool, job_str: &str) -> Option<String> {
if is_reconnected {
let job_str = job_str.trim();
if let Some(stripped) = job_str.strip_suffix('}') {
format!(r#"{},"auto_start": true}}"#, stripped).into()
} else {
// unreachable in normal cases
log::warn!(
"The last character is not '}}': {}, auto start is ignored on flutter",
job_str
);
Some(job_str.to_owned())
}
} else {
None
}
}
pub fn load_last_jobs(&self) {
self.clear_all_jobs();
let pc = self.load_config();
@@ -1379,18 +1404,32 @@ impl<T: InvokeUiSession> Session<T> {
// no last jobs
return;
}
let reconnect_count_thr = if cfg!(feature = "flutter") { 0 } else { 1 };
let is_reconnected = self.reconnect_count.load(Ordering::SeqCst) > reconnect_count_thr;
// TODO: can add a confirm dialog
let mut cnt = 1;
for job_str in pc.transfer.read_jobs.iter() {
if !job_str.is_empty() {
self.load_last_job(cnt, job_str);
self.load_last_job(
cnt,
Self::try_auto_start_job_str(is_reconnected, job_str)
.as_deref()
.unwrap_or(job_str),
is_reconnected,
);
cnt += 1;
log::info!("restore read_job: {:?}", job_str);
}
}
for job_str in pc.transfer.write_jobs.iter() {
if !job_str.is_empty() {
self.load_last_job(cnt, job_str);
self.load_last_job(
cnt,
Self::try_auto_start_job_str(is_reconnected, job_str)
.as_deref()
.unwrap_or(job_str),
is_reconnected,
);
cnt += 1;
log::info!("restore write_job: {:?}", job_str);
}
@@ -1623,7 +1662,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn clear_all_jobs(&self);
fn new_message(&self, msg: String);
fn update_transfer_list(&self);
fn load_last_job(&self, cnt: i32, job_json: &str);
fn load_last_job(&self, cnt: i32, job_json: &str, auto_start: bool);
fn update_folder_files(
&self,
id: i32,