Compare commits
566 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9383d4c97c | ||
|
|
39e3b136dc | ||
|
|
a48532d0b1 | ||
|
|
83d9cb55f1 | ||
|
|
d8ace7e38b | ||
|
|
8524192a91 | ||
|
|
23e2040797 | ||
|
|
afe12154a2 | ||
|
|
cabfdccfa4 | ||
|
|
16da5ccc91 | ||
|
|
24f8506740 | ||
|
|
e03399749a | ||
|
|
f8a6423bf4 | ||
|
|
ce993ea63a | ||
|
|
25e784fe8a | ||
|
|
b5411b686d | ||
|
|
71f136be20 | ||
|
|
1f0b9bf798 | ||
|
|
cff872dd07 | ||
|
|
662a768d83 | ||
|
|
c3abd3e2b3 | ||
|
|
7ec462737b | ||
|
|
ee8510cec7 | ||
|
|
3cc6ba005a | ||
|
|
7c9068cf17 | ||
|
|
e1ae3601c4 | ||
|
|
8ce51cbf53 | ||
|
|
0cffb3651c | ||
|
|
90e6c016a6 | ||
|
|
9cba0a0b89 | ||
|
|
f68ef1492f | ||
|
|
535e1bd2ce | ||
|
|
df02292338 | ||
|
|
e2d38208c4 | ||
|
|
cdb264d47b | ||
|
|
73c19803a2 | ||
|
|
622b2f3858 | ||
|
|
83061afe6f | ||
|
|
24547c11cb | ||
|
|
cfdc9ad03c | ||
|
|
a012414f9f | ||
|
|
ce5abfc3cd | ||
|
|
30b260ab21 | ||
|
|
15839d9815 | ||
|
|
08af0d4bf2 | ||
|
|
979203cbdb | ||
|
|
a7163c6a04 | ||
|
|
8b5f389cd7 | ||
|
|
d30a9b545e | ||
|
|
d26d680390 | ||
|
|
24e6b54650 | ||
|
|
d56356e595 | ||
|
|
be11c7127d | ||
|
|
cf557bc63e | ||
|
|
78c620126c | ||
|
|
17a6c697c7 | ||
|
|
2279c1ce70 | ||
|
|
7fa1bcfdfb | ||
|
|
5102adfd5c | ||
|
|
9f3a0699f6 | ||
|
|
81bf4bc028 | ||
|
|
d2c84c5fc2 | ||
|
|
8b6be8234d | ||
|
|
d7f0acd96d | ||
|
|
d805d74f05 | ||
|
|
37d540544a | ||
|
|
8651466cf2 | ||
|
|
90c55c0096 | ||
|
|
87d489207c | ||
|
|
6045b5fead | ||
|
|
1976fd6164 | ||
|
|
be4c64de71 | ||
|
|
443d9669b6 | ||
|
|
8dcb2e073a | ||
|
|
b34282e1f3 | ||
|
|
21bb40fce5 | ||
|
|
2a95d13eae | ||
|
|
b1331a6259 | ||
|
|
2e2b6555fa | ||
|
|
be55926cfe | ||
|
|
1ff94d1035 | ||
|
|
8e9f3e2b4d | ||
|
|
4aac3d076f | ||
|
|
014ce28e3a | ||
|
|
1ef2ca83a9 | ||
|
|
1dc96e4fd2 | ||
|
|
542d86b667 | ||
|
|
9ac4346850 | ||
|
|
df32e4e7b6 | ||
|
|
7ccd8e2c87 | ||
|
|
da4679f0ae | ||
|
|
416897994a | ||
|
|
fc8c1793f2 | ||
|
|
f9cd9a97ef | ||
|
|
b063740d3e | ||
|
|
c37732be9b | ||
|
|
1141b99cf4 | ||
|
|
6f8483aecd | ||
|
|
1e75b172d6 | ||
|
|
553a3798a1 | ||
|
|
29c661d919 | ||
|
|
309cb1010c | ||
|
|
1bcac047aa | ||
|
|
0e6bd87e19 | ||
|
|
1bb48e1979 | ||
|
|
f2381a34c7 | ||
|
|
4e20e9c91a | ||
|
|
124fc98116 | ||
|
|
3131d25de4 | ||
|
|
b8b1d9e991 | ||
|
|
4c25f94bd1 | ||
|
|
a1215749d2 | ||
|
|
d45def7cbe | ||
|
|
fb02334b46 | ||
|
|
923d76cf69 | ||
|
|
e01377e100 | ||
|
|
57b8ec178c | ||
|
|
b2f5e2f927 | ||
|
|
5112398ad3 | ||
|
|
e8d1d5f5fc | ||
|
|
91d091aaba | ||
|
|
cf1631130d | ||
|
|
d5a0d0cfa0 | ||
|
|
bf9ed4753e | ||
|
|
9eb1fd0151 | ||
|
|
96d46b4770 | ||
|
|
b60d2501cb | ||
|
|
a5bba37cae | ||
|
|
bbcb1e3d25 | ||
|
|
6f3af14623 | ||
|
|
0d6356c855 | ||
|
|
845fdec015 | ||
|
|
aeae2b3ef7 | ||
|
|
3d49909fc9 | ||
|
|
0bb03a083a | ||
|
|
ff3ca6f719 | ||
|
|
4b33ee6309 | ||
|
|
ae640dda56 | ||
|
|
722b82e1a5 | ||
|
|
089078472f | ||
|
|
214e4285be | ||
|
|
8870283f6f | ||
|
|
815f10876c | ||
|
|
591d631b0d | ||
|
|
a1780d43bb | ||
|
|
f722c6f684 | ||
|
|
d18250d1e7 | ||
|
|
85c149d8e4 | ||
|
|
0e6d368970 | ||
|
|
886fb73521 | ||
|
|
64dd1dc967 | ||
|
|
098df81754 | ||
|
|
53218409d7 | ||
|
|
a7a460a29d | ||
|
|
b4e34b6158 | ||
|
|
6608bf882f | ||
|
|
f5493ab0c4 | ||
|
|
f9f06e91f5 | ||
|
|
3c3d1a84ef | ||
|
|
e85c0d16b6 | ||
|
|
ef022c91bb | ||
|
|
d66b10b508 | ||
|
|
bea88f31e0 | ||
|
|
8b82db1220 | ||
|
|
14cbd842f5 | ||
|
|
26cd24d92f | ||
|
|
e2fdd69524 | ||
|
|
71996c9509 | ||
|
|
544cb203ea | ||
|
|
fdd24dcb72 | ||
|
|
ea12eccc90 | ||
|
|
87600d36e4 | ||
|
|
85e6ed32a1 | ||
|
|
c749ebff46 | ||
|
|
39f0edcb32 | ||
|
|
823632ccba | ||
|
|
86fa3928a7 | ||
|
|
7f6b18fc9c | ||
|
|
8301b4bf4e | ||
|
|
16c94fb1d0 | ||
|
|
1be383e50e | ||
|
|
66b90c2a08 | ||
|
|
f502eb0ea5 | ||
|
|
7921be45f5 | ||
|
|
a1095b8844 | ||
|
|
399af2fbf6 | ||
|
|
d54c96e455 | ||
|
|
eb8231af14 | ||
|
|
59c865293f | ||
|
|
72cfe05323 | ||
|
|
aaa03db69c | ||
|
|
c4f642258b | ||
|
|
67c90eda4b | ||
|
|
d2413b1899 | ||
|
|
bc0a5bf6e1 | ||
|
|
54a396ed1b | ||
|
|
7e9084e10f | ||
|
|
db45552a05 | ||
|
|
46b3cf1871 | ||
|
|
96e3d9496d | ||
|
|
f3e13cd9dd | ||
|
|
8645e92951 | ||
|
|
3fd58bb69d | ||
|
|
5028b8a93d | ||
|
|
9d5027b932 | ||
|
|
064d00f136 | ||
|
|
723a1897b9 | ||
|
|
9a6c38f0e8 | ||
|
|
d3b305ced3 | ||
|
|
e6dd082b0f | ||
|
|
ebfebdffa7 | ||
|
|
0d2c46a893 | ||
|
|
6b17644d98 | ||
|
|
6c38dc7d4a | ||
|
|
714f191a9d | ||
|
|
28cbe0f464 | ||
|
|
09a6b3c30a | ||
|
|
0d16f54c2f | ||
|
|
47956871e8 | ||
|
|
de85c9448a | ||
|
|
f022cbb93f | ||
|
|
52bffd4030 | ||
|
|
a35635f4bb | ||
|
|
fbde794d39 | ||
|
|
9121de746f | ||
|
|
9a7a600407 | ||
|
|
3ecf0cc685 | ||
|
|
38d4f29e51 | ||
|
|
e830a59c2a | ||
|
|
6fbc23a096 | ||
|
|
9093d29ae4 | ||
|
|
7692dcd629 | ||
|
|
dcad52cf52 | ||
|
|
6a500f2ede | ||
|
|
312c6324d2 | ||
|
|
21cf2a01c7 | ||
|
|
3ba979a9d7 | ||
|
|
7defb54f15 | ||
|
|
a926cc0dce | ||
|
|
32fe330946 | ||
|
|
8dac38d844 | ||
|
|
28829ce671 | ||
|
|
bebe2b5282 | ||
|
|
db2ec7df8f | ||
|
|
4d3f5373d4 | ||
|
|
c9c1ad5829 | ||
|
|
8c8b5cbb1c | ||
|
|
d91d87b67f | ||
|
|
772548dbf9 | ||
|
|
9b614c8b32 | ||
|
|
836a2b0fbd | ||
|
|
b5679df7f9 | ||
|
|
ac88f55f25 | ||
|
|
6b375cb0a3 | ||
|
|
be45ec13c0 | ||
|
|
f56def14d2 | ||
|
|
d43af7d8ad | ||
|
|
b6abcaee7a | ||
|
|
6a818763fd | ||
|
|
9905695699 | ||
|
|
278ce0281d | ||
|
|
b34f745837 | ||
|
|
0c50feeb1b | ||
|
|
c44b641cce | ||
|
|
2c86fac208 | ||
|
|
4e1d7ca3de | ||
|
|
35c1cee18b | ||
|
|
0bf007e63c | ||
|
|
3f3c45b663 | ||
|
|
dab956fe85 | ||
|
|
d28d3baf05 | ||
|
|
897dc1c2ba | ||
|
|
dd97dc580b | ||
|
|
8d830382de | ||
|
|
e39be54afa | ||
|
|
7f7e8692a8 | ||
|
|
36d509238d | ||
|
|
a8cddb5b19 | ||
|
|
186f5ed39c | ||
|
|
46233a0f4c | ||
|
|
7dcb28ce33 | ||
|
|
f4b52890e0 | ||
|
|
99bcbaa601 | ||
|
|
d665d91920 | ||
|
|
70d16ab097 | ||
|
|
6111042907 | ||
|
|
0533f7c3d6 | ||
|
|
221fe6223a | ||
|
|
baf8d2511d | ||
|
|
9dd7b4d5d8 | ||
|
|
3edba4e2db | ||
|
|
3c1465692e | ||
|
|
68835586a9 | ||
|
|
26ba25d2ae | ||
|
|
7eec6e2cc0 | ||
|
|
be9cddcad8 | ||
|
|
fdfdbb3ffc | ||
|
|
5124cc49b3 | ||
|
|
a47db31d46 | ||
|
|
d02dc1797c | ||
|
|
7ddc706f2d | ||
|
|
755353dc0b | ||
|
|
2692c29519 | ||
|
|
e2228cc448 | ||
|
|
152616a261 | ||
|
|
21850b4444 | ||
|
|
bc039a31c5 | ||
|
|
2db8f1f9d1 | ||
|
|
5817e48e17 | ||
|
|
bf42d66171 | ||
|
|
30c2c92970 | ||
|
|
01ab0cf196 | ||
|
|
fd12f69afa | ||
|
|
53e87352da | ||
|
|
e12d0ef4aa | ||
|
|
e4ac34da0d | ||
|
|
e121ed8ecb | ||
|
|
1970795093 | ||
|
|
902f56c499 | ||
|
|
1a8463015f | ||
|
|
688ecef4cc | ||
|
|
773a74e2a9 | ||
|
|
f495bf105f | ||
|
|
72c198a1e9 | ||
|
|
bf2dbf5ff4 | ||
|
|
2f5ae54c08 | ||
|
|
7c36bb7b52 | ||
|
|
f5cf291f55 | ||
|
|
f000e05267 | ||
|
|
12e565fb03 | ||
|
|
a9c4bd4a30 | ||
|
|
56c8e00b8b | ||
|
|
5a0865559c | ||
|
|
0f611d03dd | ||
|
|
f64dd3794a | ||
|
|
bdc5cded22 | ||
|
|
cd5658f01d | ||
|
|
e12717fe5f | ||
|
|
7cd12f151c | ||
|
|
5cb4413655 | ||
|
|
e148cc7e51 | ||
|
|
17587bb299 | ||
|
|
4ecbf7aec6 | ||
|
|
c33dd8e2ef | ||
|
|
a7e73df801 | ||
|
|
2ffc528986 | ||
|
|
11595be199 | ||
|
|
7640a51726 | ||
|
|
d59be68e52 | ||
|
|
6fa48b4ada | ||
|
|
6c475bf02a | ||
|
|
d6cbcae08f | ||
|
|
e978d1d0fd | ||
|
|
897bfbaf0e | ||
|
|
bd914497c9 | ||
|
|
8595d3e569 | ||
|
|
4401ccd6fa | ||
|
|
5555cf8fbe | ||
|
|
cc9f69d63b | ||
|
|
9ca01b0898 | ||
|
|
9b7e5b38ad | ||
|
|
f47f2a9151 | ||
|
|
4c32bea702 | ||
|
|
4009fd77e8 | ||
|
|
433059f8a0 | ||
|
|
416cdac1fe | ||
|
|
e143493d7b | ||
|
|
f7c1b8d88f | ||
|
|
63ac61d920 | ||
|
|
3f1a4d581b | ||
|
|
ac60ba40a2 | ||
|
|
831a50e702 | ||
|
|
4bc7466da3 | ||
|
|
d649d13c97 | ||
|
|
086c48cea9 | ||
|
|
cf6fbae30a | ||
|
|
30c002831e | ||
|
|
2ab513893d | ||
|
|
a4600dd8a8 | ||
|
|
285387c4c1 | ||
|
|
c88219b769 | ||
|
|
50c737694f | ||
|
|
549dc05713 | ||
|
|
ac743ca2fe | ||
|
|
97f14d21e8 | ||
|
|
2c619cbe41 | ||
|
|
dd4f52b63d | ||
|
|
69f1969e60 | ||
|
|
64b680e7cf | ||
|
|
ddaefddc6e | ||
|
|
3343210e8b | ||
|
|
2e256c0fca | ||
|
|
5403166552 | ||
|
|
d761d2f00e | ||
|
|
19c8ba719a | ||
|
|
55972bfac5 | ||
|
|
c0ead118a2 | ||
|
|
c15e3c306e | ||
|
|
3c4852a254 | ||
|
|
61a48b5367 | ||
|
|
7f4548021b | ||
|
|
0a29fa87f0 | ||
|
|
8d92ee424f | ||
|
|
ceb78aa095 | ||
|
|
6dd476fecb | ||
|
|
e5bdbffbcf | ||
|
|
1de50e8170 | ||
|
|
27353f98ff | ||
|
|
ef097c7a7a | ||
|
|
33606eee9f | ||
|
|
ac2b9a6fc1 | ||
|
|
264b282f5c | ||
|
|
9321a4f486 | ||
|
|
ffbc6e0c8b | ||
|
|
fa420c4825 | ||
|
|
4d2036512a | ||
|
|
63bf4b5fa8 | ||
|
|
4b58f0b4dd | ||
|
|
029e6a015e | ||
|
|
5d6b1223cc | ||
|
|
813c51b0ca | ||
|
|
4d7a6dd661 | ||
|
|
954df86f3c | ||
|
|
da1126a5a9 | ||
|
|
0e1e8d2b16 | ||
|
|
9967bb993f | ||
|
|
8f851bc781 | ||
|
|
c6d0322080 | ||
|
|
6467b14486 | ||
|
|
88ce98e716 | ||
|
|
343bcbb363 | ||
|
|
5228b3490d | ||
|
|
0f40279060 | ||
|
|
731aa5e9f3 | ||
|
|
791645fa59 | ||
|
|
4fe85cdd4a | ||
|
|
8b8f50ed0f | ||
|
|
c711084807 | ||
|
|
88efd13acb | ||
|
|
f72eed064a | ||
|
|
6c0ca4cec8 | ||
|
|
71ffa21db0 | ||
|
|
bd6b7cdfc4 | ||
|
|
b7123c5be8 | ||
|
|
20b39c7215 | ||
|
|
5e9841e7ab | ||
|
|
09d2502f53 | ||
|
|
033645a7e0 | ||
|
|
eb8b264b18 | ||
|
|
b7c9c187e5 | ||
|
|
b543e6d143 | ||
|
|
4bbef031d5 | ||
|
|
006df4d20b | ||
|
|
0ef2ae4ac4 | ||
|
|
e70f3f2125 | ||
|
|
20cdb87e28 | ||
|
|
28ef64cba1 | ||
|
|
b89bf86f03 | ||
|
|
58e252a875 | ||
|
|
5cf2f47b12 | ||
|
|
088f4a76a7 | ||
|
|
7bff325a7d | ||
|
|
5e36710cde | ||
|
|
5639ce82bd | ||
|
|
29e3616237 | ||
|
|
9a28bab5b2 | ||
|
|
02456280d4 | ||
|
|
93a6410360 | ||
|
|
dc0f21298e | ||
|
|
aa740f4263 | ||
|
|
31b3c5d721 | ||
|
|
2133f91089 | ||
|
|
633c80d5e4 | ||
|
|
22ca7177a6 | ||
|
|
fd9f5475f3 | ||
|
|
96f367943c | ||
|
|
dfd5ea8a7f | ||
|
|
b80051bb35 | ||
|
|
d49dd9377e | ||
|
|
5662121cdb | ||
|
|
e4544d8a22 | ||
|
|
c763478f66 | ||
|
|
8c741bdfd3 | ||
|
|
ac9e4a5582 | ||
|
|
07137ac566 | ||
|
|
b52795bd59 | ||
|
|
893a88bb02 | ||
|
|
e198dd626b | ||
|
|
ef615baaeb | ||
|
|
072338afae | ||
|
|
2ec773e9bf | ||
|
|
5e7efd24eb | ||
|
|
5dbfa71b2c | ||
|
|
b9ad4b2379 | ||
|
|
ca0e00ea5e | ||
|
|
e48f36a227 | ||
|
|
c9d19115e9 | ||
|
|
9ac3128309 | ||
|
|
aacffd979b | ||
|
|
b40c3aae52 | ||
|
|
31fc018526 | ||
|
|
b17c6983ce | ||
|
|
c86a8fff03 | ||
|
|
780cb37d46 | ||
|
|
7bbc5183db | ||
|
|
f0ded8498a | ||
|
|
e37745d0b4 | ||
|
|
2ce0f724bb | ||
|
|
5ebb2565ca | ||
|
|
84dc0b8be8 | ||
|
|
74a492e52e | ||
|
|
2badecba2a | ||
|
|
c01c8d0afc | ||
|
|
76a6b4e09e | ||
|
|
4ed9aa39c7 | ||
|
|
52aebb3bcc | ||
|
|
c950ed1701 | ||
|
|
f97f5d94ae | ||
|
|
5c5413075e | ||
|
|
806c2130b5 | ||
|
|
8cc7dc0a3e | ||
|
|
5fc88fb6e4 | ||
|
|
77eca6bcdc | ||
|
|
195018e22d | ||
|
|
552871d98c | ||
|
|
71e3f86024 | ||
|
|
07f7a9318c | ||
|
|
7f539a2de3 | ||
|
|
30d6edf502 | ||
|
|
60f0a3485f | ||
|
|
ebf25282e3 | ||
|
|
59bc97c2f5 | ||
|
|
a24a7e8d0f | ||
|
|
bf33b28483 | ||
|
|
b60c4bd952 | ||
|
|
0f56aecadf | ||
|
|
ec34470284 | ||
|
|
77231f6538 | ||
|
|
fa0b1436c2 | ||
|
|
7bc98ee434 | ||
|
|
2051bee3cf | ||
|
|
6d70c8af50 | ||
|
|
2cfa61602f | ||
|
|
fbfad5f86d | ||
|
|
889415fb26 | ||
|
|
ebd8903c9b | ||
|
|
314d7f4387 | ||
|
|
5875cb1896 | ||
|
|
7a2e151079 | ||
|
|
7bdf0d0b90 | ||
|
|
ee3e7938c2 | ||
|
|
058a82c79c | ||
|
|
3a831085eb | ||
|
|
9a54cf664b | ||
|
|
5d4f6ff80e | ||
|
|
afae2d110c | ||
|
|
a0171f9cc8 | ||
|
|
261c4b9833 | ||
|
|
f96fd806c0 | ||
|
|
126114dea4 | ||
|
|
3fd1d66f12 | ||
|
|
cdc412afd0 | ||
|
|
1772c66694 | ||
|
|
5e6e921790 | ||
|
|
7d7cfe391a | ||
|
|
d99ff80714 |
3
.github/workflows/bridge.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.10.5"
|
||||
FLUTTER_VERSION: "3.10.6"
|
||||
FLUTTER_RUST_BRIDGE_VERSION: "1.75.3"
|
||||
|
||||
jobs:
|
||||
@@ -42,7 +42,6 @@ jobs:
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: bridge-${{ matrix.job.os }}
|
||||
workspace: "/tmp/flutter_rust_bridge/frb_codegen"
|
||||
|
||||
- name: Cache Bridge
|
||||
id: cache-bridge
|
||||
|
||||
7
.github/workflows/ci.yml
vendored
@@ -124,7 +124,12 @@ jobs:
|
||||
with:
|
||||
use-cross: ${{ matrix.job.use-cross }}
|
||||
command: build
|
||||
args: --locked --release --target=${{ matrix.job.target }}
|
||||
args: --locked --target=${{ matrix.job.target }}
|
||||
|
||||
- name: clean
|
||||
shell: bash
|
||||
run: |
|
||||
cargo clean
|
||||
|
||||
# - name: Strip debug information from executable
|
||||
# id: strip
|
||||
|
||||
189
.github/workflows/flutter-build.yml
vendored
@@ -13,16 +13,16 @@ on:
|
||||
env:
|
||||
CARGO_NDK_VERSION: "3.1.2"
|
||||
LLVM_VERSION: "15.0.6"
|
||||
FLUTTER_VERSION: "3.10.5"
|
||||
FLUTTER_VERSION: "3.10.6"
|
||||
FLUTTER_RUST_BRIDGE_VERSION: "1.75.3"
|
||||
# for arm64 linux
|
||||
FLUTTER_ELINUX_VERSION: "3.10.5"
|
||||
FLUTTER_ELINUX_VERSION: "3.10.6"
|
||||
FLUTTER_ELINUX_COMMIT_ID: "410b3ca42f2cd0c485edf517a1666652bab442d4"
|
||||
TAG_NAME: "${{ inputs.upload-tag }}"
|
||||
# vcpkg version: 2023.04.15
|
||||
# for multiarch gcc compatibility
|
||||
VCPKG_COMMIT_ID: "501db0f17ef6df184fcdbfbe0f87cde2313b6ab1"
|
||||
VERSION: "1.2.1"
|
||||
VERSION: "1.2.2"
|
||||
NDK_VERSION: "r25c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: '${{ secrets.ANDROID_SIGNING_KEY }}'
|
||||
@@ -377,7 +377,7 @@ jobs:
|
||||
uses: ./.github/workflows/bridge.yml
|
||||
|
||||
build-rustdesk-ios:
|
||||
if: ${{ inputs.upload-artifact == 'true' }}
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
needs: [generate-bridge-linux]
|
||||
name: build rustdesk ios ipa ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
@@ -654,7 +654,7 @@ jobs:
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo apt update -y
|
||||
sudo apt install qemu-user-static
|
||||
sudo apt install qemu-user-static -y
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
@@ -666,7 +666,8 @@ jobs:
|
||||
|
||||
- name: Free Space
|
||||
run: |
|
||||
df
|
||||
df -h
|
||||
free -m
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -675,27 +676,11 @@ jobs:
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
cache-directories: "/opt/rust-registry"
|
||||
|
||||
- name: Install local registry
|
||||
|
||||
- name: Save Rust toolchain version
|
||||
run: |
|
||||
mkdir -p /opt/rust-registry
|
||||
cargo install cargo-local-registry
|
||||
|
||||
- name: Build local registry
|
||||
uses: nick-fields/retry@v2
|
||||
id: build-local-registry
|
||||
continue-on-error: true
|
||||
with:
|
||||
max_attempts: 3
|
||||
timeout_minutes: 15
|
||||
retry_on: error
|
||||
command: cargo local-registry --sync ./Cargo.lock /opt/rust-registry
|
||||
RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
|
||||
echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Disable rust bridge build
|
||||
run: |
|
||||
@@ -729,7 +714,6 @@ jobs:
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/rust-registry:/opt/rust-registry"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
@@ -746,19 +730,15 @@ jobs:
|
||||
# rust
|
||||
pushd /opt
|
||||
# do not use rustup, because memory overflow in qemu
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-1.70.0-${{ matrix.job.target }}.tar.gz
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}.tar.gz
|
||||
tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
|
||||
cd rust-1.70.0-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-1.70.0-${{ matrix.job.target }}
|
||||
cd rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}
|
||||
# edit config
|
||||
mkdir -p ~/.cargo/
|
||||
echo """
|
||||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'local-registry'
|
||||
|
||||
[source.local-registry]
|
||||
local-registry = '/opt/rust-registry/'
|
||||
""" > ~/.cargo/config
|
||||
cat ~/.cargo/config
|
||||
# start build
|
||||
@@ -783,10 +763,10 @@ jobs:
|
||||
path: target/release/liblibrustdesk.so
|
||||
|
||||
build-rustdesk-lib-linux-arm:
|
||||
if: ${{ inputs.upload-artifact == 'true' }}
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
needs: [generate-bridge-linux, build-vcpkg-deps-linux]
|
||||
name: build-rust-lib ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -819,25 +799,26 @@ jobs:
|
||||
# - { arch: armv7, target: armv7-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "appimage" }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
run: |
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo apt update -y
|
||||
sudo apt install qemu-user-static
|
||||
#- name: Maximize build space
|
||||
# run: |
|
||||
# sudo rm -rf /opt/ghc
|
||||
# sudo rm -rf /usr/local/lib/android
|
||||
# sudo rm -rf /usr/share/dotnet
|
||||
# sudo apt update -y
|
||||
# sudo apt install qemu-user-static -y
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 12
|
||||
#- name: Set Swap Space
|
||||
# uses: pierotofy/set-swap-space@master
|
||||
# with:
|
||||
# swap-size-gb: 12
|
||||
|
||||
- name: Free Space
|
||||
run: |
|
||||
df
|
||||
df -h
|
||||
free -m
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -846,27 +827,11 @@ jobs:
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
cache-directories: "/opt/rust-registry"
|
||||
|
||||
- name: Install local registry
|
||||
|
||||
- name: Save Rust toolchain version
|
||||
run: |
|
||||
mkdir -p /opt/rust-registry
|
||||
cargo install cargo-local-registry
|
||||
|
||||
- name: Build local registry
|
||||
uses: nick-fields/retry@v2
|
||||
id: build-local-registry
|
||||
continue-on-error: true
|
||||
with:
|
||||
max_attempts: 3
|
||||
timeout_minutes: 15
|
||||
retry_on: error
|
||||
command: cargo local-registry --sync ./Cargo.lock /opt/rust-registry
|
||||
RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
|
||||
echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Disable rust bridge build
|
||||
run: |
|
||||
@@ -898,7 +863,6 @@ jobs:
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/rust-registry:/opt/rust-registry"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
@@ -915,19 +879,15 @@ jobs:
|
||||
# rust
|
||||
pushd /opt
|
||||
# do not use rustup, because memory overflow in qemu
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-1.70.0-${{ matrix.job.target }}.tar.gz
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}.tar.gz
|
||||
tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
|
||||
cd rust-1.70.0-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-1.70.0-${{ matrix.job.target }}
|
||||
cd rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}
|
||||
# edit config
|
||||
mkdir -p ~/.cargo/
|
||||
echo """
|
||||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'local-registry'
|
||||
|
||||
[source.local-registry]
|
||||
local-registry = '/opt/rust-registry/'
|
||||
""" > ~/.cargo/config
|
||||
cat ~/.cargo/config
|
||||
# start build
|
||||
@@ -937,6 +897,7 @@ jobs:
|
||||
if ${{ matrix.job.enable-headless }}; then
|
||||
export DEFAULT_FEAT=linux_headless
|
||||
fi
|
||||
export CARGO_INCREMENTAL=0
|
||||
cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }},$DEFAULT_FEAT --release
|
||||
|
||||
- name: Upload Artifacts
|
||||
@@ -946,10 +907,10 @@ jobs:
|
||||
path: target/release/liblibrustdesk.so
|
||||
|
||||
build-rustdesk-sciter-arm:
|
||||
if: ${{ inputs.upload-artifact == 'true' }}
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
needs: [build-vcpkg-deps-linux]
|
||||
name: build-rustdesk(sciter) ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -968,25 +929,26 @@ jobs:
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
|
||||
- name: Maximize build space
|
||||
run: |
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo apt update -y
|
||||
sudo apt install qemu-user-static
|
||||
#- name: Maximize build space
|
||||
# run: |
|
||||
# sudo rm -rf /opt/ghc
|
||||
# sudo rm -rf /usr/local/lib/android
|
||||
# sudo rm -rf /usr/share/dotnet
|
||||
# sudo apt update -y
|
||||
# sudo apt install qemu-user-static -y
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 12
|
||||
#- name: Set Swap Space
|
||||
# uses: pierotofy/set-swap-space@master
|
||||
# with:
|
||||
# swap-size-gb: 12
|
||||
|
||||
- name: Free Space
|
||||
run: |
|
||||
df
|
||||
df -h
|
||||
free -m
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -995,27 +957,11 @@ jobs:
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
cache-directories: "/opt/rust-registry"
|
||||
|
||||
- name: Install local registry
|
||||
|
||||
- name: Save Rust toolchain version
|
||||
run: |
|
||||
mkdir -p /opt/rust-registry
|
||||
cargo install cargo-local-registry
|
||||
|
||||
- name: Build local registry
|
||||
uses: nick-fields/retry@v2
|
||||
id: build-local-registry
|
||||
continue-on-error: true
|
||||
with:
|
||||
max_attempts: 3
|
||||
timeout_minutes: 15
|
||||
retry_on: error
|
||||
command: cargo local-registry --sync ./Cargo.lock /opt/rust-registry
|
||||
RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
|
||||
echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Restore vcpkg files
|
||||
uses: actions/download-artifact@master
|
||||
@@ -1035,7 +981,6 @@ jobs:
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/rust-registry:/opt/rust-registry"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
@@ -1048,19 +993,15 @@ jobs:
|
||||
# rust
|
||||
pushd /opt
|
||||
# do not use rustup, because memory overflow in qemu
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-1.70.0-${{ matrix.job.target }}.tar.gz
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}.tar.gz
|
||||
tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
|
||||
cd rust-1.70.0-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-1.70.0-${{ matrix.job.target }}
|
||||
cd rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}
|
||||
# edit config
|
||||
mkdir -p ~/.cargo/
|
||||
echo """
|
||||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'local-registry'
|
||||
|
||||
[source.local-registry]
|
||||
local-registry = '/opt/rust-registry/'
|
||||
""" > ~/.cargo/config
|
||||
cat ~/.cargo/config
|
||||
|
||||
@@ -1070,6 +1011,7 @@ jobs:
|
||||
export VCPKG_ROOT=/opt/artifacts/vcpkg
|
||||
export ARCH=armhf
|
||||
export DEFAULT_FEAT=""
|
||||
export CARGO_INCREMENTAL=0
|
||||
if ${{ matrix.job.enable-headless }}; then
|
||||
export DEFAULT_FEAT=linux_headless
|
||||
fi
|
||||
@@ -1105,7 +1047,7 @@ jobs:
|
||||
path: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.deb
|
||||
|
||||
build-rustdesk-linux-arm:
|
||||
if: ${{ inputs.upload-artifact == 'true' }}
|
||||
if: ${{ inputs.upload-artifact }}
|
||||
needs: [build-rustdesk-lib-linux-arm]
|
||||
name: build-rustdesk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ubuntu-20.04 # 20.04 has more performance on arm build
|
||||
@@ -1216,6 +1158,7 @@ jobs:
|
||||
sed -i "s/x64\/release/arm\/release/g" ./build.py
|
||||
;;
|
||||
esac
|
||||
export CARGO_INCREMENTAL=0
|
||||
python3 ./build.py --flutter --hwcodec --skip-cargo
|
||||
# rpm package
|
||||
echo -e "start packaging fedora package"
|
||||
@@ -1233,7 +1176,7 @@ jobs:
|
||||
pushd ~/rpmbuild/RPMS/${{ matrix.job.arch }}
|
||||
mkdir -p /opt/artifacts/rpm
|
||||
for name in rustdesk*??.rpm; do
|
||||
mv "$name" "/opt/artifacts/rpm/${name%%.rpm}-fedora28-centos8.rpm"
|
||||
mv "$name" "/opt/artifacts/rpm/${name%%.rpm}.rpm"
|
||||
done
|
||||
# rpm suse package
|
||||
echo -e "start packaging suse package"
|
||||
@@ -1358,7 +1301,7 @@ jobs:
|
||||
# files: |
|
||||
# res/rustdesk*.zst
|
||||
|
||||
- name: Publish fedora28/centos8 package
|
||||
- name: Publish fedora package
|
||||
if: matrix.job.extra-build-features == '' && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
@@ -1457,7 +1400,7 @@ jobs:
|
||||
pushd ~/rpmbuild/RPMS/${{ matrix.job.arch }}
|
||||
mkdir -p /opt/artifacts/rpm
|
||||
for name in rustdesk*??.rpm; do
|
||||
mv "$name" "/opt/artifacts/rpm/${name%%.rpm}-fedora28-centos8.rpm"
|
||||
mv "$name" "/opt/artifacts/rpm/${name%%.rpm}.rpm"
|
||||
done
|
||||
# rpm suse package
|
||||
pushd /workspace
|
||||
@@ -1572,7 +1515,7 @@ jobs:
|
||||
files: |
|
||||
./appimage/rustdesk-${{ env.VERSION }}-*.AppImage
|
||||
|
||||
- name: Publish fedora28/centos8 package
|
||||
- name: Publish fedora package
|
||||
if: matrix.job.extra-build-features == '' && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
|
||||
2
.github/workflows/flutter-tag.yml
vendored
@@ -15,4 +15,4 @@ jobs:
|
||||
secrets: inherit
|
||||
with:
|
||||
upload-artifact: true
|
||||
upload-tag: "1.2.1"
|
||||
upload-tag: "1.2.2"
|
||||
|
||||
322
.github/workflows/history.yml
vendored
@@ -4,30 +4,28 @@ on: [workflow_dispatch]
|
||||
|
||||
env:
|
||||
LLVM_VERSION: "10.0"
|
||||
# Note: currently 3.0.5 does not support arm64 officially, we use latest stable version first.
|
||||
FLUTTER_VERSION: "3.0.5"
|
||||
FLUTTER_VERSION: "3.10.6"
|
||||
TAG_NAME: "tmp"
|
||||
FLUTTER_RUST_BRIDGE_VERSION: "1.75.3"
|
||||
# vcpkg version: 2022.05.10
|
||||
# for multiarch gcc compatibility
|
||||
VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44"
|
||||
VERSION: "1.2.1"
|
||||
VCPKG_COMMIT_ID: "501db0f17ef6df184fcdbfbe0f87cde2313b6ab1"
|
||||
VERSION: "1.2.2"
|
||||
|
||||
jobs:
|
||||
build-for-windows-2022-12-05:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
build-for-history-windows:
|
||||
name: ${{ matrix.job.date }}
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019, arch: x86_64, date: 2023-08-04, ref: 72c198a1e94cc1e0242fce88f92b3f3caedcd0c3 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: '8d1254cf14b69f545c9cefa026c5eeb0e7dd3e7c'
|
||||
ref: ${{ matrix.job.ref }}
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
@@ -41,49 +39,30 @@ jobs:
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Replace engine with rustdesk custom flutter engine
|
||||
run: |
|
||||
flutter doctor -v
|
||||
flutter precache --windows
|
||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
|
||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
components: rustfmt
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Install flutter rust bridge deps
|
||||
run: |
|
||||
dart pub global activate ffigen --version 5.0.1
|
||||
$exists = Test-Path ~/.cargo/bin/flutter_rust_bridge_codegen.exe
|
||||
Push-Location ..
|
||||
git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1
|
||||
Push-Location flutter_rust_bridge/frb_codegen ; cargo install --path . ; Pop-Location
|
||||
Pop-Location
|
||||
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
|
||||
Push-Location flutter ; flutter pub get ; Pop-Location
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
shell: bash
|
||||
|
||||
cd C:\
|
||||
git clone https://github.com/Kingtous/rustdesk_thirdpary_lib --depth=1
|
||||
|
||||
- name: Build rustdesk
|
||||
run: python3 .\build.py --portable --hwcodec --flutter
|
||||
env:
|
||||
VCPKG_ROOT: C:\rustdesk_thirdpary_lib\vcpkg
|
||||
run: python3 .\build.py --portable --hwcodec --flutter --feature IddDriver
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
@@ -92,274 +71,7 @@ jobs:
|
||||
python3 ./generate.py -f ../../flutter/build/windows/runner/Release/ -o . -e ../../flutter/build/windows/runner/Release/rustdesk.exe
|
||||
popd
|
||||
mkdir -p ./SignOutput
|
||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-2022-12-05-${{ matrix.job.target }}.exe
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
./SignOutput/rustdesk-*.exe
|
||||
|
||||
build-for-windows-2022-12-12:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: '3dd43b79ec0409fc38103bed0c7eb0bc3cd993d5'
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Replace engine with rustdesk custom flutter engine
|
||||
run: |
|
||||
flutter doctor -v
|
||||
flutter precache --windows
|
||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
|
||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
components: rustfmt
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Install flutter rust bridge deps
|
||||
run: |
|
||||
dart pub global activate ffigen --version 5.0.1
|
||||
$exists = Test-Path ~/.cargo/bin/flutter_rust_bridge_codegen.exe
|
||||
Push-Location ..
|
||||
git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1
|
||||
Push-Location flutter_rust_bridge/frb_codegen ; cargo install --path . ; Pop-Location
|
||||
Pop-Location
|
||||
Push-Location flutter ; flutter pub get ; Pop-Location
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
shell: bash
|
||||
|
||||
- name: Build rustdesk
|
||||
run: python3 .\build.py --portable --hwcodec --flutter
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
run: |
|
||||
pushd ./libs/portable
|
||||
python3 ./generate.py -f ../../flutter/build/windows/runner/Release/ -o . -e ../../flutter/build/windows/runner/Release/rustdesk.exe
|
||||
popd
|
||||
mkdir -p ./SignOutput
|
||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-2022-12-12-${{ matrix.job.target }}.exe
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
./SignOutput/rustdesk-*.exe
|
||||
|
||||
build-for-windows-2022-12-19:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: '1054715891c4e73ad9b164acec6dadecfc599a65'
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Replace engine with rustdesk custom flutter engine
|
||||
run: |
|
||||
flutter doctor -v
|
||||
flutter precache --windows
|
||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
|
||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
components: rustfmt
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Install flutter rust bridge deps
|
||||
run: |
|
||||
dart pub global activate ffigen --version 5.0.1
|
||||
$exists = Test-Path ~/.cargo/bin/flutter_rust_bridge_codegen.exe
|
||||
Push-Location ..
|
||||
git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1
|
||||
Push-Location flutter_rust_bridge/frb_codegen ; cargo install --path . ; Pop-Location
|
||||
Pop-Location
|
||||
Push-Location flutter ; flutter pub get ; Pop-Location
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
shell: bash
|
||||
|
||||
- name: Build rustdesk
|
||||
run: python3 .\build.py --portable --hwcodec --flutter
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
run: |
|
||||
pushd ./libs/portable
|
||||
python3 ./generate.py -f ../../flutter/build/windows/runner/Release/ -o . -e ../../flutter/build/windows/runner/Release/rustdesk.exe
|
||||
popd
|
||||
mkdir -p ./SignOutput
|
||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-2022-12-19-${{ matrix.job.target }}.exe
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
./SignOutput/rustdesk-*.exe
|
||||
|
||||
build-for-windows-2022-12-26:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: 'b241925fe093dc4da804a5aac419375f4ca7653f'
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Replace engine with rustdesk custom flutter engine
|
||||
run: |
|
||||
flutter doctor -v
|
||||
flutter precache --windows
|
||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
|
||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
components: rustfmt
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Install flutter rust bridge deps
|
||||
run: |
|
||||
dart pub global activate ffigen --version 5.0.1
|
||||
$exists = Test-Path ~/.cargo/bin/flutter_rust_bridge_codegen.exe
|
||||
Push-Location ..
|
||||
git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1
|
||||
Push-Location flutter_rust_bridge/frb_codegen ; cargo install --path . ; Pop-Location
|
||||
Pop-Location
|
||||
Push-Location flutter ; flutter pub get ; Pop-Location
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
shell: bash
|
||||
|
||||
- name: Build rustdesk
|
||||
run: python3 .\build.py --portable --hwcodec --flutter
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
run: |
|
||||
pushd ./libs/portable
|
||||
python3 ./generate.py -f ../../flutter/build/windows/runner/Release/ -o . -e ../../flutter/build/windows/runner/Release/rustdesk.exe
|
||||
popd
|
||||
mkdir -p ./SignOutput
|
||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-2022-12-26-${{ matrix.job.target }}.exe
|
||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-${{ matrix.job.date }}-${{ matrix.job.target }}.exe
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
|
||||
72
Cargo.lock
generated
@@ -1197,7 +1197,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"libc",
|
||||
"mach2",
|
||||
"ndk 0.7.0",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"oboe",
|
||||
"once_cell",
|
||||
@@ -2987,8 +2987,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hwcodec"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/21pages/hwcodec?branch=stable#3ea79865a10387b7e1b7630c2ae068bd2081f680"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/21pages/hwcodec?branch=stable#82cdc15457e42feaf14e1b38622506b2d54baf76"
|
||||
dependencies = [
|
||||
"bindgen 0.59.2",
|
||||
"cc",
|
||||
@@ -3764,19 +3764,6 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"jni-sys",
|
||||
"ndk-sys 0.3.0",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.7.0"
|
||||
@@ -3785,7 +3772,7 @@ checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"jni-sys",
|
||||
"ndk-sys 0.4.1+23.1.7779620",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
@@ -3797,15 +3784,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.4.1+23.1.7779620"
|
||||
@@ -4116,7 +4094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0"
|
||||
dependencies = [
|
||||
"jni 0.20.0",
|
||||
"ndk 0.7.0",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"num-derive",
|
||||
"num-traits 0.2.15",
|
||||
@@ -4894,7 +4872,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rdev"
|
||||
version = "0.5.0-2"
|
||||
source = "git+https://github.com/fufesou/rdev#ab48d5798c86303b9398727684509b1b43ecfdab"
|
||||
source = "git+https://github.com/fufesou/rdev#ee3057bd97c91529e8b9daf2ca133a5c49f0c0eb"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"core-foundation",
|
||||
@@ -5146,7 +5124,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustdesk"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"arboard",
|
||||
@@ -5409,7 +5387,7 @@ dependencies = [
|
||||
"jni 0.21.1",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"ndk 0.7.0",
|
||||
"ndk",
|
||||
"num_cpus",
|
||||
"pkg-config",
|
||||
"quest",
|
||||
@@ -5841,9 +5819,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.29.0"
|
||||
version = "0.29.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02f1dc6930a439cc5d154221b5387d153f8183529b07c19aca24ea31e0a167e1"
|
||||
checksum = "c7cb97a5a85a136d84e75d5c3cf89655090602efb1be0d8d5337b7e386af2908"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"core-foundation-sys 0.8.4",
|
||||
@@ -5915,8 +5893,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.19.1"
|
||||
source = "git+https://github.com/rustdesk-org/tao?branch=muda#173f128608d282dc4036f213c1c42137464ff096"
|
||||
version = "0.22.2"
|
||||
source = "git+https://github.com/rustdesk-org/tao?branch=dev#1e5b97258cf42a30f80f85a6aa0b1a4aece1977e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cairo-rs",
|
||||
@@ -5937,13 +5915,13 @@ dependencies = [
|
||||
"gtk",
|
||||
"image",
|
||||
"instant",
|
||||
"jni 0.20.0",
|
||||
"jni 0.21.1",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"ndk 0.6.0",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"ndk-sys 0.3.0",
|
||||
"ndk-sys",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
@@ -5952,16 +5930,18 @@ dependencies = [
|
||||
"scopeguard",
|
||||
"tao-macros",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
"uuid",
|
||||
"windows 0.44.0",
|
||||
"windows 0.48.0",
|
||||
"windows-implement",
|
||||
"x11-dl",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tao-macros"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/rustdesk-org/tao?branch=muda#173f128608d282dc4036f213c1c42137464ff096"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/rustdesk-org/tao?branch=dev#1e5b97258cf42a30f80f85a6aa0b1a4aece1977e"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"quote 1.0.27",
|
||||
@@ -6850,8 +6830,6 @@ version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
@@ -6870,14 +6848,16 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.44.0"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6"
|
||||
checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"quote 1.0.27",
|
||||
@@ -6886,9 +6866,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.44.0"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f"
|
||||
checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"quote 1.0.27",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustdesk"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
authors = ["rustdesk <info@rustdesk.com>"]
|
||||
edition = "2021"
|
||||
build= "build.rs"
|
||||
@@ -48,7 +48,7 @@ lazy_static = "1.4"
|
||||
sha2 = "0.10"
|
||||
repng = "0.2"
|
||||
parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" }
|
||||
runas = "1.0"
|
||||
runas = "=1.0" # https://github.com/mitsuhiko/rust-runas/issues/13
|
||||
magnum-opus = { git = "https://github.com/rustdesk/magnum-opus" }
|
||||
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true }
|
||||
rubato = { version = "0.12", optional = true }
|
||||
@@ -111,7 +111,7 @@ objc_id = "0.1"
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
||||
tray-icon = { git = "https://github.com/rustdesk-org/tray-icon" }
|
||||
tao = { git = "https://github.com/rustdesk-org/tao", branch = "muda" }
|
||||
tao = { git = "https://github.com/rustdesk-org/tao", branch = "dev" }
|
||||
image = "0.24"
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies]
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
FROM debian
|
||||
|
||||
WORKDIR /
|
||||
RUN apt update -y && apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev cmake ninja-build
|
||||
RUN apt update -y && apt install -y g++ gcc git curl nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev cmake ninja-build && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN git clone https://github.com/microsoft/vcpkg && cd vcpkg && git checkout 2023.04.15
|
||||
RUN git clone --branch 2023.04.15 --depth=1 https://github.com/microsoft/vcpkg
|
||||
RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics
|
||||
RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus aom
|
||||
|
||||
RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user && echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user
|
||||
WORKDIR /home/user
|
||||
RUN wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
RUN curl -LO https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||
USER user
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh
|
||||
RUN chmod +x rustup.sh
|
||||
|
||||
@@ -35,7 +35,6 @@ Below are the servers you are using for free, they may change over time. If you
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | [Hetzner](https://www.hetzner.com) | 2 vCPU / 4 GB RAM |
|
||||
| Germany | [Codext](https://codext.de) | 4 vCPU / 8 GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
||||
|
||||
## Dev Container
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
version: 1
|
||||
script:
|
||||
- rm -rf ./AppDir || true
|
||||
- bsdtar -zxvf ../rustdesk-1.2.1.deb
|
||||
- bsdtar -zxvf ../rustdesk-1.2.2.deb
|
||||
- tar -xvf ./data.tar.xz
|
||||
- mkdir ./AppDir
|
||||
- mv ./usr ./AppDir/usr
|
||||
# 32x32 icon
|
||||
- for i in {32,64,128}; do mkdir -p ./AppDir/usr/share/icons/hicolor/$i\x$i/apps/; cp ../res/$i\x$i.png ./AppDir/usr/share/icons/hicolor/$i\x$i/apps/rustdesk.png; done
|
||||
- mkdir -p ./AppDir/usr/share/icons/hicolor/scalable/apps/; cp ../res/scalable.svg ./AppDir/usr/share/icons/hicolor/scalable/apps/rustdesk.svg
|
||||
# desktop file
|
||||
# - sed -i "s/Icon=\/usr\/share\/rustdesk\/files\/rustdesk.png/Icon=rustdesk/g" ./AppDir/usr/share/applications/rustdesk.desktop
|
||||
- rm -rf ./AppDir/usr/share/applications
|
||||
@@ -17,7 +18,7 @@ AppDir:
|
||||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.2.1
|
||||
version: 1.2.2
|
||||
exec: usr/lib/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
@@ -50,7 +51,6 @@ AppDir:
|
||||
- libva-x11-2
|
||||
- libvdpau1
|
||||
- libgstreamer-plugins-base1.0-0
|
||||
- gstreamer1.0-pipewire
|
||||
- libwayland-cursor0
|
||||
- libwayland-egl1
|
||||
- libpulse0
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
version: 1
|
||||
script:
|
||||
- rm -rf ./AppDir || true
|
||||
- bsdtar -zxvf ../rustdesk-1.2.1.deb
|
||||
- bsdtar -zxvf ../rustdesk-1.2.2.deb
|
||||
- tar -xvf ./data.tar.xz
|
||||
- mkdir ./AppDir
|
||||
- mv ./usr ./AppDir/usr
|
||||
# 32x32 icon
|
||||
- for i in {32,64,128}; do mkdir -p ./AppDir/usr/share/icons/hicolor/$i\x$i/apps/; cp ../res/$i\x$i.png ./AppDir/usr/share/icons/hicolor/$i\x$i/apps/rustdesk.png; done
|
||||
- mkdir -p ./AppDir/usr/share/icons/hicolor/scalable/apps/; cp ../res/scalable.svg ./AppDir/usr/share/icons/hicolor/scalable/apps/rustdesk.svg
|
||||
# desktop file
|
||||
# - sed -i "s/Icon=\/usr\/share\/rustdesk\/files\/rustdesk.png/Icon=rustdesk/g" ./AppDir/usr/share/applications/rustdesk.desktop
|
||||
- rm -rf ./AppDir/usr/share/applications
|
||||
@@ -17,7 +18,7 @@ AppDir:
|
||||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.2.1
|
||||
version: 1.2.2
|
||||
exec: usr/lib/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
|
||||
24
build.py
@@ -71,14 +71,14 @@ def parse_rc_features(feature):
|
||||
return 'osx' in platforms
|
||||
else:
|
||||
return 'linux' in platforms
|
||||
|
||||
|
||||
def get_all_features():
|
||||
features = []
|
||||
for (feat, feat_info) in available_features.items():
|
||||
if platform_check(feat_info['platform']):
|
||||
features.append(feat)
|
||||
return features
|
||||
|
||||
|
||||
if isinstance(feature, str) and feature.upper() == 'ALL':
|
||||
return get_all_features()
|
||||
elif isinstance(feature, list):
|
||||
@@ -311,6 +311,8 @@ def build_flutter_deb(version, features):
|
||||
system2('mkdir -p tmpdeb/etc/rustdesk/')
|
||||
system2('mkdir -p tmpdeb/etc/pam.d/')
|
||||
system2('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/256x256/apps/')
|
||||
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/scalable/apps/')
|
||||
system2('mkdir -p tmpdeb/usr/share/applications/')
|
||||
system2('mkdir -p tmpdeb/usr/share/polkit-1/actions')
|
||||
system2('rm tmpdeb/usr/bin/rustdesk || true')
|
||||
@@ -319,7 +321,9 @@ def build_flutter_deb(version, features):
|
||||
system2(
|
||||
'cp ../res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2(
|
||||
'cp ../res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png')
|
||||
'cp ../res/128x128@2x.png tmpdeb/usr/share/icons/hicolor/256x256/apps/rustdesk.png')
|
||||
system2(
|
||||
'cp ../res/scalable.svg tmpdeb/usr/share/icons/hicolor/scalable/apps/rustdesk.svg')
|
||||
system2(
|
||||
'cp ../res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
|
||||
system2(
|
||||
@@ -351,6 +355,8 @@ def build_deb_from_folder(version, binary_folder):
|
||||
system2('mkdir -p tmpdeb/usr/bin/')
|
||||
system2('mkdir -p tmpdeb/usr/lib/rustdesk')
|
||||
system2('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/256x256/apps/')
|
||||
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/scalable/apps/')
|
||||
system2('mkdir -p tmpdeb/usr/share/applications/')
|
||||
system2('mkdir -p tmpdeb/usr/share/polkit-1/actions')
|
||||
system2('rm tmpdeb/usr/bin/rustdesk || true')
|
||||
@@ -359,7 +365,9 @@ def build_deb_from_folder(version, binary_folder):
|
||||
system2(
|
||||
'cp ../res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2(
|
||||
'cp ../res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png')
|
||||
'cp ../res/128x128@2x.png tmpdeb/usr/share/icons/hicolor/256x256/apps/rustdesk.png')
|
||||
system2(
|
||||
'cp ../res/scalable.svg tmpdeb/usr/share/icons/hicolor/scalable/apps/rustdesk.svg')
|
||||
system2(
|
||||
'cp ../res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
|
||||
system2(
|
||||
@@ -556,7 +564,7 @@ def main():
|
||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/*
|
||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app
|
||||
'''.format(pa))
|
||||
system2('create-dmg target/release/bundle/osx/RustDesk.app')
|
||||
system2('create-dmg "RustDesk %s.dmg" "target/release/bundle/osx/RustDesk.app"' % version)
|
||||
os.rename('RustDesk %s.dmg' %
|
||||
version, 'rustdesk-%s.dmg' % version)
|
||||
if pa:
|
||||
@@ -581,10 +589,14 @@ def main():
|
||||
'mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb')
|
||||
system2('dpkg-deb -R rustdesk.deb tmpdeb')
|
||||
system2('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/256x256/apps/')
|
||||
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/scalable/apps/')
|
||||
system2(
|
||||
'cp res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2(
|
||||
'cp res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png')
|
||||
'cp res/128x128@2x.png tmpdeb/usr/share/icons/hicolor/256x256/apps/rustdesk.png')
|
||||
system2(
|
||||
'cp res/scalable.svg tmpdeb/usr/share/icons/hicolor/scalable/apps/rustdesk.svg')
|
||||
system2(
|
||||
'cp res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
|
||||
system2(
|
||||
|
||||
37
docs/CONTRIBUTING-IT.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Contribuzione a RustDesk
|
||||
|
||||
RustDesk accoglie con favore il contributo di tutti.
|
||||
Ecco le linee guida se stai pensando di aiutarci.
|
||||
|
||||
## Contribuzione
|
||||
|
||||
I contributi a RustDesk o alle sue dipendenze dovrebbero essere forniti sotto forma di richieste pull GitHub.
|
||||
Ogni richiesta pull verr<72> esaminata da un collaboratore principale (qualcuno con il permesso di applicare) ed <20> abilitato all'uso dell'albero principale o dare un feedback per le modifiche che sarebbero necessarie.
|
||||
Tutti i contributi dovrebbero seguire questo formato, anche quelli dei contributori principali.
|
||||
|
||||
Se desideri lavorare su un problema, rivendicalo prima commentando
|
||||
il problema di GitHub su cui vuoi lavorare.
|
||||
Questo per evitare duplicati sforzi dei contributori sullo stesso problema.
|
||||
|
||||
## Elenco di controllo delle richieste pull
|
||||
|
||||
- Branch del master branch e, se necessario, rebase al master attuale branch prima di inviare la richiesta pull.
|
||||
Se l'unione non <20> in mod pulito con il master ti potrebbe essere chiesto di effettuare il rebase delle modifiche.
|
||||
|
||||
- Le modifiche dovrebbero essere le pi<70> piccole possibile, assicurando al tempo stesso che ogni modifica sia corretta in modo indipendente (ovvero, ogni modifica dovrebbe essere compilabile e superare i test).
|
||||
|
||||
- Le modifiche devono essere accompagnati da un certificato di origine per sviluppatori firmato (http://developercertificate.org), che indica che tu (e il tuo datore di lavoro se applicabile) accetti di essere vincolato dai termini della [licenza progetto](../LICENCE). In git, questa <20> l'opzione `-s` di `git commit`
|
||||
|
||||
- Se la tua patch non viene esaminata o hai bisogno che una persona specifica la esamini, puoi @-rispondere ad un revisore chiedendo una revisione nella richiesta pull o un commento, oppure puoi chiedere una revisione tramite [email](mailto:info@rustdesk.com).
|
||||
|
||||
- Aggiungi test relativi al bug corretto o alla nuova funzionalit<69>.
|
||||
|
||||
Per istruzioni specifiche su git, vedi [Workflow GitHub - 101](https://github.com/servo/servo/wiki/GitHub-workflow).
|
||||
|
||||
## Condotta
|
||||
|
||||
https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT-IT.md
|
||||
|
||||
## Comunicazioni
|
||||
|
||||
I contributori di RustDesk frequentano [Discord](https://discord.gg/nDceKgxnkV).
|
||||
14
docs/DEVCONTAINER-IT.md
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
Dopo l'avvio di devcontainer nel contenitore docker, viene creato un binario linux in modalità debug.
|
||||
|
||||
Attualmente devcontainer consente creazione build Linux e Android sia in modalità debug che in modalità rilascio.
|
||||
|
||||
Di seguito è riportata la tabella dei comandi da eseguire dalla root del progetto per la creazione di build specifiche.
|
||||
|
||||
Comando|Tipo build|Modo
|
||||
-|-|-|
|
||||
`.devcontainer/build.sh --debug linux`|Linux|debug
|
||||
`.devcontainer/build.sh --release linux`|Linux|release
|
||||
`.devcontainer/build.sh --debug android`|android-arm64|debug
|
||||
`.devcontainer/build.sh --release android`|android-arm64|release
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
| الموقع | المورد | المواصفات |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
||||
|
||||
## التبعيات
|
||||
|
||||
@@ -28,7 +28,6 @@ Níže jsou uvedeny servery zdarma k vašemu použití (údaje se mohou v čase
|
||||
| umístění | dodavatel | parametry |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
||||
|
||||
## Softwarové součásti, na kterých závisí
|
||||
|
||||
@@ -26,8 +26,6 @@ Nedenfor er de servere, du bruger gratis, det kan ændre sig med tiden. Hvis du
|
||||
| Beliggenhed | Udbyder | Specifikation |
|
||||
| ---------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Seoul | AWS lightsail | 1 vCPU / 0.5GB RAM |
|
||||
|
||||
## Afhængigheder
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ Nachfolgend sind die Server gelistet, die Sie kostenlos nutzen können. Es kann
|
||||
| Standort | Anbieter | Spezifikation |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Deutschland | [Hetzner](https://www.hetzner.com/de/) | 2 vCPU / 4 GB RAM |
|
||||
| Deutschland | [Codext](https://codext.de/) | 4 vCPU / 8 GB RAM |
|
||||
| Ukraine (Kiew) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
||||
|
||||
## Dev-Container
|
||||
|
||||
@@ -25,7 +25,6 @@ Malsupre estas la serviloj, kiuj vi uzas senpage, ĝi povas ŝanĝi laŭlonge de
|
||||
| Situo | Vendanto | Detaloj |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dependantaĵoj
|
||||
|
||||
@@ -32,7 +32,6 @@ A continuación se muestran los servidores gratuitos, pueden cambiar a medida qu
|
||||
| Ubicación | Compañía | Especificación |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dependencias
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
| موقعیت | سرویس دهنده | مشخصات |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| آلمان | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| آلمان | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## وابستگی ها
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ Alla on palvelimia, joita voit käyttää ilmaiseksi, ne saattavat muuttua ajan
|
||||
| Sijainti | Myyjä | Määrittely |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Riippuvuudet
|
||||
|
||||
@@ -26,7 +26,6 @@ Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut ch
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## Dépendances
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
| Περιοχή | Πάροχος | Προδιαγραφές |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Γερμανία | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Γερμανία | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ουκρανία (Κίεβο) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dev Container
|
||||
|
||||
@@ -33,7 +33,6 @@ Ezalatt az üzenet alatt találhatóak azok a publikus szerverek, amelyeket ingy
|
||||
| Hely | Host | Specifikáció |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -6,53 +6,64 @@
|
||||
<a href="#file-structure">Structure</a> •
|
||||
<a href="#snapshot">Snapshot</a><br>
|
||||
[<a href="../README.md">English</a>] | [<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-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-GR.md">Ελληνικά</a>]<br>
|
||||
<b>Kami membutuhkan bantuan Anda untuk menerjemahkan README ini dan <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> ke bahasa asli anda</b>
|
||||
<b>Kami membutuhkan bantuanmu untuk menterjemahkan file README dan <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> ke Bahasa Indonesia</b>
|
||||
</p>
|
||||
|
||||
Birbincang bersama kami: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
Mari mengobrol bersama kami: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Perangkat lunak desktop jarak jauh lainnya, ditulis dengan Rust. Bekerja begitu saja, tidak memerlukan konfigurasi. Anda memiliki kendali penuh atas data Anda, tanpa khawatir tentang keamanan. Anda dapat menggunakan server rendezvous/relay kami, [konfigurasi server sendiri](https://rustdesk.com/server), or [tulis rendezvous/relay server anda sendiri](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
Merupakan perangkat lunak Remote Desktop yang baru, dibangun dengan Rust. kamu bisa langsung menggunakannya tanpa perlu konfigurasi tambahan. Serta ,emiliki kontrol penuh terhadap semua data, tanpa perlu merasa was-was tentang isu keamanan, dan yang lebih menarik adalah memiliki opsi untuk menggunakan server rendezvous/relay milik kami, [konfigurasi server sendiri](https://rustdesk.com/server), atau [tulis rendezvous/relay server anda sendiri](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk menyambut baik kontribusi dari semua orang. Lihat [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) untuk membantu sebelum memulai.
|
||||
RustDesk mengajak semua orang untuk ikut berkontribusi. Lihat [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) untuk melihat panduan.
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
[**UNDUH BINARY**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Publik Server Gratis
|
||||
## Server Publik Gratis
|
||||
|
||||
Di bawah ini adalah server yang bisa Anda gunakan secara gratis, dapat berubah seiring waktu. Jika Anda tidak dekat dengan salah satu dari ini, jaringan Anda mungkin lambat.
|
||||
| Lokasi | Vendor | Spesifikasi |
|
||||
Di bawah ini merupakan server gratis yang bisa kamu gunakan, seiring waktu kemungkinan akan terjadi perubahan spesifikasi pada setiap server. Jika lokasi kamu berada jauh dengan salah satu server yang tersedia, kemungkinan koneksi akan terasa lambat ketika melakukan proses remote.
|
||||
| Lokasi | Penyedia | Spesifikasi |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
| Jerman | [Hetzner](https://www.hetzner.com) | 2 vCPU / 4GB RAM |
|
||||
| Ukraina (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dependencies
|
||||
## Dev Container
|
||||
|
||||
Versi desktop menggunakan [sciter](https://sciter.com/) untuk GUI, silahkan download sendiri sciter dynamic library.
|
||||
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/rustdesk/rustdesk)
|
||||
|
||||
Apabila kamu sudah menginstall VS Code dan Docker, kamu bisa mengklik badge yang ada diatas untuk memulainya. Dengan mengklik badge tersebut secara otomatis akan menginstal ekstensi pada VS Code, lakukan kloning (clone) source code kedalam container volume, dan aktifkan dev container untuk menggunakannya.
|
||||
|
||||
## Dependensi
|
||||
|
||||
Pada versi desktop, antarmuka pengguna (GUI) menggunakan [Sciter](https://sciter.com/) atau flutter, tutorial ini hanya berlaku untuk Sciter
|
||||
|
||||
Kamu bisa mengunduh Sciter dynamic library disini.
|
||||
|
||||
[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)
|
||||
|
||||
## Langkah untuk RAW Build
|
||||
## Langkah awal untuk memulai
|
||||
|
||||
- Siapkan env pengembangan Rust dan C++ build env
|
||||
- Siapkan env development Rust dan env build C++
|
||||
|
||||
- Install [vcpkg](https://github.com/microsoft/vcpkg), dan arahkan `VCPKG_ROOT` env variable dengan benar
|
||||
- Install [vcpkg](https://github.com/microsoft/vcpkg), dan atur variabel env `VCPKG_ROOT` dengan benar
|
||||
|
||||
- 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
|
||||
|
||||
- jalankan `cargo run`
|
||||
|
||||
## Bagaimana Build di Linux
|
||||
## [Build](https://rustdesk.com/docs/en/dev/build/)
|
||||
|
||||
## Cara Build di Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
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
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
@@ -79,7 +90,7 @@ export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus aom
|
||||
```
|
||||
|
||||
### Perbaiki libvpx (Untuk Fedora)
|
||||
### Mengatasi masalah libvpx (Untuk Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
@@ -105,13 +116,40 @@ mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Ubah Wayland menjadi X11 (Xorg)
|
||||
### Mengubah Wayland ke X11 (Xorg)
|
||||
|
||||
RustDesk tidak mendukung Wayland. Cek [ini](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) untuk mengonfigurasi Xorg sebagai sesi GNOME default.
|
||||
RustDesk tidak mendukung Wayland. Cek [ini](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) untuk mengonfigurasi Xorg sebagai sesi standar di GNOME.
|
||||
|
||||
## Bagaimana build dengan Docker
|
||||
## Kompatibilitas dengan Wayland
|
||||
|
||||
Mulailah dengan mengkloning repositori dan build dengan docker container:
|
||||
Sepertinya Wayland tidak memiliki API untuk mengirimkan ketukan tombol ke jendela lain. Maka dari itu, RustDesk menggunakan API dari level yang lebih rendah, lebih tepatnya perangkat `/dev/uinput` (linux kernel level)
|
||||
|
||||
Saat Wayland menjadi sisi yang dikendalikan atau sisi yang sedang diremote, kamu harus memulai dengan cara ini
|
||||
|
||||
```bash
|
||||
# Start uinput service
|
||||
$ sudo rustdesk --service
|
||||
$ rustdesk
|
||||
```
|
||||
|
||||
**Harap Diperhatikan**: Saat Perekaman layar menggunakan Wayland antarmuka (UI) yang ditampilkan akan berbeda. Untuk saat ini RustDesk hanya mendukung org.freedesktop.portal.ScreenCast.
|
||||
|
||||
```bash
|
||||
$ dbus-send --session --print-reply \
|
||||
--dest=org.freedesktop.portal.Desktop \
|
||||
/org/freedesktop/portal/desktop \
|
||||
org.freedesktop.DBus.Properties.Get \
|
||||
string:org.freedesktop.portal.ScreenCast string:version
|
||||
# Not support
|
||||
Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast”
|
||||
# Support
|
||||
method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2
|
||||
variant uint32 4
|
||||
```
|
||||
|
||||
## Cara Build dengan Docker
|
||||
|
||||
Mulailah dengan melakukan kloning (clone) repositori dan build dengan docker container:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
@@ -119,25 +157,25 @@ cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Kemudian, setiap kali Anda perlu build aplikasi, jalankan perintah berikut:
|
||||
Selanjutnya, setiap kali ketika kamu akan melakukan build aplikasi, jalankan perintah berikut:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Perhatikan bahwa build pertama mungkin memerlukan waktu lebih lama sebelum dependensi di-cache, build berikutnya akan lebih cepat. Selain itu, jika Anda perlu menentukan argumen yang berbeda untuk perintah build, Anda dapat melakukannya di akhir perintah di posisi `<OPTIONAL-ARGS>`. Misalnya, jika Anda ingin membangun versi rilis yang dioptimalkan, Anda akan menjalankan perintah di atas diikuti oleh `--release`. Hasil eksekusi akan tersedia pada target folder di sistem anda, dan dapat dijalankan dengan:
|
||||
Perlu diingat bahwa pada saat build pertama kali, mungkin memerlukan waktu lebih lama sebelum dependensi di-cache, build berikutnya akan lebih cepat. Selain itu, jika perlu menentukan argumen yang berbeda untuk perintah build, kamu dapat melakukannya di akhir perintah di posisi `<OPTIONAL-ARGS>`. Misalnya, jika ingin membangun versi rilis yang dioptimalkan, jalankan perintah di atas dan tambahkan `--release`. Hasil eksekusi perintah tersebut akan tersimpan pada target folder di sistem kamu, dan dapat dijalankan dengan:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Atau, jika Anda menjalankan rilis yang dapat dieksekusi:
|
||||
Atau, jika kamu menjalankan rilis yang dapat dieksekusi:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Harap pastikan bahwa Anda menjalankan perintah ini dari root repositori RustDesk, jika tidak, aplikasi mungkin tidak dapat menemukan sumber daya yang diperlukan. Perhatikan juga perintah cargo seperti `install` atau `run` saat ini tidak didukung melalui metode ini karena mereka akan menginstal atau menjalankan program di dalam container bukan pada host.
|
||||
Harap pastikan bahwa kamu menjalankan perintah ini dari repositori root RustDesk, jika tidak demikian, aplikasi mungkin tidak dapat menemukan sumber yang diperlukan. Dan juga, perintah cargo seperti `install` atau `run` saat ini tidak didukung melalui metode ini karena, proses menginstal atau menjalankan program terjadi di dalam container bukan pada host.
|
||||
|
||||
## Struktur File
|
||||
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
<p align="center">
|
||||
<img src="../res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#server-pubblici-gratuiti">Servers</a> •
|
||||
<img src="../res/logo-header.svg" alt="RustDesk - il tuo desktop remoto"><br>
|
||||
<a href="#server-pubblici-gratuiti">Server</a> •
|
||||
<a href="#passaggi-per-la-compilazione">Compilazione</a> •
|
||||
<a href="#come-compilare-con-docker">Docker</a> •
|
||||
<a href="#struttura-dei-file">Struttura</a> •
|
||||
<a href="#screenshots">Screenshots</a><br>
|
||||
<a href="#screenshots">Schermate</a><br>
|
||||
[<a href="../README.md">English</a>] | [<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-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-GR.md">Ελληνικά</a>]<br>
|
||||
<b>Abbiamo bisogno del tuo aiuto per tradurre questo README e la <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> nella tua lingua nativa</b>
|
||||
<b>Abbiamo bisogno del tuo aiuto per tradurre questo file README e la <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">UI RustDesk</a> nella tua lingua nativa</b>
|
||||
</p>
|
||||
|
||||
Chatta con noi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
Chatta con noi su: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
Ancora un altro software per il controllo remoto del desktop, scritto in Rust. Funziona immediatamente, nessuna configurazione richiesta. Hai il pieno controllo dei tuoi dati, senza preoccupazioni per la sicurezza. Puoi utilizzare il nostro server rendezvous/relay, [configurare il tuo](https://rustdesk.com/server) o [scrivere il tuo rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
Ancora un altro software per il controllo remoto del desktop, scritto in Rust.
|
||||
Funziona immediatamente, nessuna configurazione richiesta. Hai il pieno controllo dei tuoi dati, senza preoccupazioni per la sicurezza.
|
||||
Puoi usare il nostro server rendezvous/relay, [configurare il tuo server](https://rustdesk.com/server) o [realizzare il tuo server rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||
RustDesk accoglie il contributo di tutti. Per ulteriori informazioni su come inizare a contribuire, vedere [`docs/CONTRIBUTING.md`](CONTRIBUTING.md).
|
||||
RustDesk accoglie il contributo di tutti.
|
||||
Per ulteriori informazioni su come iniziare a contribuire, vedi [`docs/CONTRIBUTING-IT.md`](CONTRIBUTING.md).
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
[**DOWNLOAD PROGRAMMA**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
## Server pubblici gratuiti
|
||||
|
||||
Qui sotto trovate i server che possono essere usati gratuitamente, la lista potrebbe cambiare nel tempo. Se non si è vicini a uno di questi server, la vostra connessione potrebbe essere lenta.
|
||||
| Posizione | Vendor | Specifiche |
|
||||
Qui sotto trovi i server che possono essere usati gratuitamente, la lista potrebbe cambiare nel tempo.
|
||||
Se non sei vicino a uno di questi server, la connessione potrebbe essere lenta.
|
||||
|
||||
| Posizione | Venditore | Specifiche |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
| Germania | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Ucraina (Kyev) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dipendenze
|
||||
|
||||
La versione Desktop utilizza [sciter](https://sciter.com/) per la GUI, per favore scarica sciter dynamic library.
|
||||
La versione Desktop usa per la GUI [sciter](https://sciter.com/), per favore scarica la libreria dinamica 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) |
|
||||
@@ -47,7 +51,7 @@ La versione Desktop utilizza [sciter](https://sciter.com/) per la GUI, per favor
|
||||
|
||||
- Esegui `cargo run`
|
||||
|
||||
## Come compilare su Linux
|
||||
## Come compilare in Linux
|
||||
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
@@ -67,7 +71,7 @@ sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-
|
||||
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
|
||||
```
|
||||
|
||||
### Installare vcpkg
|
||||
### Installa vcpkg
|
||||
|
||||
```sh
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
@@ -79,7 +83,7 @@ export VCPKG_ROOT=$HOME/vcpkg
|
||||
vcpkg/vcpkg install libvpx libyuv opus aom
|
||||
```
|
||||
|
||||
### Fix libvpx (Per Fedora)
|
||||
### Correzione libvpx (per Fedora)
|
||||
|
||||
```sh
|
||||
cd vcpkg/buildtrees/libvpx/src
|
||||
@@ -105,13 +109,14 @@ mv libsciter-gtk.so target/debug
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### Cambiare Wayland a X11 (Xorg)
|
||||
### Cambiare Wayland in X11 (Xorg)
|
||||
|
||||
RustDesk non supporta Wayland. Controlla [questo](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) per configurare Xorg come sessione di default di GNOME.
|
||||
RustDesk non supporta Wayland.
|
||||
Controlla [qui](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) per configurare Xorg come sessione predefinita di GNOME.
|
||||
|
||||
## Come compilare con Docker
|
||||
|
||||
Cominciare clonando il repository e compilare i container docker:
|
||||
Clona il repository e compila i container docker:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
@@ -119,38 +124,42 @@ cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Quindi, ogni volta che devi compilare l'applicazione, esegui il comando seguente:
|
||||
Quindi, ogni volta che devi compilare l'applicazione, esegui il seguente comando:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Tieni presente che la prima build potrebbe richiedere più tempo prima che le dipendenze vengano memorizzate nella cache, le build successive saranno più veloci. Inoltre, se hai bisogno di specificare argomenti diversi per il comando build, puoi farlo alla fine del comando nella posizione `<OPTIONAL-ARGS>`. Ad esempio, se si desidera creare una versione di rilascio ottimizzata, eseguire il comando sopra seguito da `--release`. L'eseguibile generato sarà creato nella cartella di destinazione del proprio sistema e può essere eseguito con:
|
||||
Tieni presente che la prima build potrebbe richiedere più tempo prima che le dipendenze vengano memorizzate nella cache, le build successive saranno più veloci.
|
||||
Inoltre, se hai bisogno di specificare argomenti diversi per il comando build, puoi farlo alla fine del comando nella posizione `<OPTIONAL-ARGS>`.
|
||||
Ad esempio, se vuoi creare una versione di rilascio ottimizzata, esegui il comando precedentemente indicato seguito da `--release`.
|
||||
L'eseguibile generato sarà creato nella cartella destinazione del sistema e può essere eseguito con:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Oppure, se si sta eseguendo un eseguibile di rilascio:
|
||||
Oppure, se stai avviando un eseguibile di rilascio:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Assicurati di eseguire questi comandi dalla radice del repository RustDesk, altrimenti l'applicazione potrebbe non essere in grado di trovare le risorse richieste. Notare inoltre che altri sottocomandi cargo come `install` o `run` non sono attualmente supportati tramite questo metodo poiché installerebbero o eseguirebbero il programma all'interno del container anziché nell'host.
|
||||
Assicurati di eseguire questi comandi dalla radice del repository RustDesk, altrimenti l'applicazione potrebbe non essere in grado di trovare le risorse richieste.
|
||||
Nota inoltre che altri sottocomandi cargo come `install` o `run` non sono attualmente supportati tramite questo metodo poiché installerebbero o eseguirebbero il programma all'interno del container anziché nell'host.
|
||||
|
||||
## Struttura dei file
|
||||
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs funzioni per il trasferimento file, e altre funzioni utili.
|
||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec video, config, wrapper tcp/udp, protobuf, funzioni per il trasferimento file, e altre funzioni utili.
|
||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: cattura dello schermo
|
||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controllo tastiera/mouse specifico della piattaforma
|
||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: servizi audio/appunti/input/video e connessioni di rete
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: avviare una connessione peer
|
||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: avvio di una connessione peer
|
||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunica con [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attende la connessione remota diretta (TCP hole punching) oppure indiretta (relayed)
|
||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: codice specifico della piattaforma
|
||||
|
||||
## Screenshots
|
||||
## Schermate
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ RustDeskは誰からの貢献も歓迎します。 貢献するには [`docs/CON
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## 依存関係
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ RustDesk는 모든 기여를 환영합니다. 기여하고자 한다면 [`docs/C
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## 의존관계
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
| സ്ഥാനം | കച്ചവടക്കാരൻ | വിവരണം |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## ഡിപെൻഡൻസികൾ
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ Hieronder staan de servers die u gratis gebruikt, ze kunnen in de loop van de ti
|
||||
| Locatie | Aanbieder | Specificaties |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Duitsland | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Duitsland | Codext | 4 vCPU / 8GB RAM |
|
||||
| Oekraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dev Container
|
||||
|
||||
@@ -35,7 +35,6 @@ Poniżej znajdują się serwery, z których można korzystać za darmo, może si
|
||||
| Lokalizacja | Dostawca | Specyfikacja |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Niemcy | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Niemcy | Codext | 4 vCPU / 8GB RAM |
|
||||
| Ukraina (Kijów) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Konterner Programisty (Dev Container)
|
||||
|
||||
@@ -26,7 +26,6 @@ Abaixo estão os servidores que você está utilizando de graça, ele pode mudar
|
||||
| Localização | Fornecedor | Especificações |
|
||||
| ----------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## Dependências
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ RustDesk приветствует вклад каждого. Ознакомьт
|
||||
| Расположение | Поставщик | Технические характеристики |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Германия | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Германия | Codext | 4 vCPU / 8GB RAM |
|
||||
| Россия (Москва) | [nt-vps](https://nt-vps.ru) | 8 vCPU / 8GB RAM |
|
||||
|
||||
## Зависимости
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ RustDesk вітає внесок кожного. Дивіться [`docs/CONTRIB
|
||||
| Місцезнаходження | Постачальник | Технічні характеристики |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Німеччина | Hetzner | 2 VCPU / 4GB RAM |
|
||||
| Німеччина | Codext | 4 vCPU / 8GB RAM |
|
||||
| Україна (Київ) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
||||
|
||||
## Dev Container
|
||||
|
||||
@@ -34,7 +34,6 @@ Dưới đây là những máy chủ mà bạn có thể sử dụng mà không
|
||||
| Địa điểm | Nhà cung cấp | Cấu hình |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<p align="center">
|
||||
<img src="../res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||
<a href="#免费公共服务器">服务器</a> •
|
||||
<a href="#免费的公共服务器">服务器</a> •
|
||||
<a href="#基本构建步骤">编译</a> •
|
||||
<a href="#使用Docker编译">Docker</a> •
|
||||
<a href="#使用-Docker-编译">Docker</a> •
|
||||
<a href="#文件结构">结构</a> •
|
||||
<a href="#截图">截图</a><br>
|
||||
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</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-GR.md">Ελληνικά</a>]<br>
|
||||
@@ -16,9 +16,19 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
|
||||
或者[自己设置](https://rustdesk.com/server),
|
||||
亦或者[开发您的版本](https://github.com/rustdesk/rustdesk-server-demo)。
|
||||
|
||||
欢迎大家贡献代码, 请看 [`docs/CONTRIBUTING.md`](CONTRIBUTING.md).
|
||||

|
||||
|
||||
[**可执行程序下载**](https://github.com/rustdesk/rustdesk/releases)
|
||||
RustDesk 期待各位的贡献. 如何参与开发? 详情请看 [CONTRIBUTING.md](docs/CONTRIBUTING.md).
|
||||
|
||||
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||
|
||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||
|
||||
[**NIGHTLY BUILD**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||
|
||||
## 免费的公共服务器
|
||||
|
||||
@@ -26,8 +36,16 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
|
||||
|
||||
| Location | Vendor | Specification |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
||||
| Germany | Codext | 4 vCPU / 8GB RAM |
|
||||
| Germany | [Hetzner](https://www.hetzner.com) | 2 vCPU / 4 GB RAM |
|
||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
||||
|
||||
## Dev Container
|
||||
|
||||
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/rustdesk/rustdesk)
|
||||
|
||||
如果你已经安装了 VS Code 和 Docker, 你可以点击上面的徽章开始使用. 点击后, VS Code 将自动安装 Dev Containers 扩展(如果需要),将源代码克隆到容器卷中, 并启动一个 Dev 容器供使用.
|
||||
|
||||
Go through [DEVCONTAINER.md](docs/DEVCONTAINER.md) for more info.
|
||||
|
||||
## 依赖
|
||||
|
||||
@@ -37,16 +55,14 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
|
||||
[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)
|
||||
|
||||
移动版本使用Flutter,未来会将桌面版本从Sciter迁移到Flutter。
|
||||
|
||||
## 基本构建步骤
|
||||
|
||||
- 请准备好 Rust 开发环境和 C++编译环境
|
||||
- 请准备好 Rust 开发环境和 C++ 编译环境
|
||||
|
||||
- 安装[vcpkg](https://github.com/microsoft/vcpkg), 正确设置`VCPKG_ROOT`环境变量
|
||||
- 安装 [vcpkg](https://github.com/microsoft/vcpkg), 正确设置 `VCPKG_ROOT` 环境变量
|
||||
|
||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
|
||||
- Linux/Osx: vcpkg install libvpx libyuv opus aom
|
||||
- Linux/macOS: vcpkg install libvpx libyuv opus aom
|
||||
|
||||
- 运行 `cargo run`
|
||||
|
||||
@@ -57,7 +73,15 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
|
||||
### Ubuntu 18 (Debian 10)
|
||||
|
||||
```sh
|
||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
|
||||
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
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### Fedora 28 (CentOS 8)
|
||||
@@ -107,24 +131,52 @@ 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
|
||||
cargo run
|
||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||
```
|
||||
|
||||
### 把 Wayland 修改成 X11 (Xorg)
|
||||
|
||||
RustDesk 暂时不支持 Wayland,不过正在积极开发中。
|
||||
> [点我](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)
|
||||
查看 如何将Xorg设置成默认的GNOME session
|
||||
查看如何将 Xorg 设置成默认的 GNOME session.
|
||||
|
||||
## Wayland 支持
|
||||
|
||||
Wayland 似乎没有提供任何将按键发送到其他窗口的 API. 因此, RustDesk 使用较低级别的 API, 即 `/dev/uinput` devices (Linux kernal level).
|
||||
|
||||
当 Wayland 是受控方时,您必须以下列方式开始操作:
|
||||
|
||||
```bash
|
||||
# Start uinput service
|
||||
$ sudo rustdesk --service
|
||||
$ rustdesk
|
||||
```
|
||||
|
||||
**Notice**: Wayland 屏幕录制使用不同的接口. RustDesk 目前只支持 org.freedesktop.portal.ScreenCast.
|
||||
|
||||
```bash
|
||||
$ dbus-send --session --print-reply \
|
||||
--dest=org.freedesktop.portal.Desktop \
|
||||
/org/freedesktop/portal/desktop \
|
||||
org.freedesktop.DBus.Properties.Get \
|
||||
string:org.freedesktop.portal.ScreenCast string:version
|
||||
# Not support
|
||||
Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast”
|
||||
# Support
|
||||
method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2
|
||||
variant uint32 4
|
||||
```
|
||||
|
||||
## 使用 Docker 编译
|
||||
|
||||
### 构建Docker容器
|
||||
克隆版本库并构建 Docker 容器:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk # 克隆Github存储库
|
||||
cd rustdesk # 进入文件夹
|
||||
docker build -t "rustdesk-builder" . # 构建容器
|
||||
```
|
||||
|
||||
请注意:
|
||||
* 针对国内网络访问问题,可以做以下几点优化:
|
||||
1. Dockerfile 中修改系统的源到国内镜像
|
||||
@@ -163,8 +215,9 @@ docker build -t "rustdesk-builder" . # 构建容器
|
||||
docker build -t "rustdesk-builder" . --build-arg http_proxy=http://host:port --build-arg https_proxy=http://host:port
|
||||
```
|
||||
|
||||
### 构建RustDesk程序
|
||||
容器构建完成后,运行下列指令以完成对RustDesk应用程序的构建:
|
||||
### 构建 RustDesk 程序
|
||||
|
||||
然后, 每次需要构建应用程序时, 运行以下命令:
|
||||
|
||||
```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
|
||||
@@ -179,25 +232,25 @@ docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user
|
||||
groupmod: Permission denied.
|
||||
groupmod: cannot lock /etc/group; try again later.
|
||||
```
|
||||
> **原因:** 容器的entrypoint脚本会检测UID和GID,在度判和给定的环境变量的不一致时,会强行修改user的UID和GID并重新运行。但在重启后读不到环境中的UID和GID,然后再次进入判错重启环节
|
||||
> **原因:** 容器的 entrypoint 脚本会检测 UID 和 GID,在度判和给定的环境变量的不一致时,会强行修改 user 的 UID 和 GID 并重新运行。但在重启后读不到环境中的 UID 和 GID,然后再次进入判错重启环节
|
||||
|
||||
|
||||
### 运行RustDesk程序
|
||||
### 运行 RustDesk 程序
|
||||
|
||||
生成的可执行程序在target目录下,可直接通过指令运行调试(Debug)版本的RustDesk:
|
||||
生成的可执行程序在 target 目录下,可直接通过指令运行调试 (Debug) 版本的 RustDesk:
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
或者您想运行发行(Release)版本:
|
||||
或者您想运行发行 (Release) 版本:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
请注意:
|
||||
* 请保证您运行的目录是在RustDesk库的根目录内,否则软件会读不到文件。
|
||||
* `install`、`run`等Cargo的子指令在容器内不可用,宿主机才行。
|
||||
* 请保证您运行的目录是在 RustDesk 库的根目录内,否则软件会读不到文件。
|
||||
* `install`、`run`等 Cargo 的子指令在容器内不可用,宿主机才行。
|
||||
|
||||
## 文件结构
|
||||
|
||||
|
||||
11
docs/SECURITY-IT.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Policy sicurezza
|
||||
|
||||
## Segnalazione di una vulnerabilità
|
||||
|
||||
Attribuiamo grande importanza alla sicurezza del progetto.
|
||||
Incoraggiamo tutti gli utenti a segnalare eventuali vulnerabilità di sicurezza che ci scoprono.
|
||||
Se trovi una vulnerabilità nel progetto RustDesk, segnalala responsabilmente inviando un'email a info@rustdesk.com.
|
||||
|
||||
Al momento non abbiamo un programma di taglia sui bug.
|
||||
Siamo una piccola squadra che cerca di risolvere un grosso problema.
|
||||
Ti esortiamo a segnalare responsabilmente tutte le vulnerabilità in modo da poter continuare a sviluppare un'applicazione sicura per l'intera comunità.
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 422 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 452 KiB After Width: | Height: | Size: 451 KiB |
|
Before Width: | Height: | Size: 379 KiB After Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 266 KiB |
@@ -4,7 +4,7 @@
|
||||
"runtime-version": "21.08",
|
||||
"sdk": "org.freedesktop.Sdk",
|
||||
"command": "rustdesk",
|
||||
"icon": "share/rustdesk/files/rustdesk.png",
|
||||
"icon": "share/icons/hicolor/scalable/apps/rustdesk.svg",
|
||||
"modules": [
|
||||
"shared-modules/libappindicator/libappindicator-gtk3-12.10.json",
|
||||
"xdotool.json",
|
||||
@@ -12,20 +12,21 @@
|
||||
"name": "rustdesk",
|
||||
"buildsystem": "simple",
|
||||
"build-commands": [
|
||||
"bsdtar -zxvf rustdesk-1.2.1.deb",
|
||||
"bsdtar -zxvf rustdesk-1.2.2.deb",
|
||||
"tar -xvf ./data.tar.xz",
|
||||
"cp -r ./usr/* /app/",
|
||||
"mkdir -p /app/bin && ln -s /app/lib/rustdesk/rustdesk /app/bin/rustdesk",
|
||||
"mv /app/share/applications/rustdesk.desktop /app/share/applications/com.rustdesk.RustDesk.desktop",
|
||||
"sed -i '/^Icon=/ c\\Icon=com.rustdesk.RustDesk' /app/share/applications/com.rustdesk.RustDesk.desktop",
|
||||
"sed -i '/^Icon=/ c\\Icon=com.rustdesk.RustDesk' /app/share/applications/rustdesk-link.desktop",
|
||||
"mv /app/share/icons/hicolor/scalable/apps/rustdesk.svg /app/share/icons/hicolor/scalable/apps/com.rustdesk.RustDesk.svg",
|
||||
"for size in 16 24 32 48 64 128 256 512; do\n rsvg-convert -w $size -h $size -f png -o $size.png logo.svg\n install -Dm644 $size.png /app/share/icons/hicolor/${size}x${size}/apps/com.rustdesk.RustDesk.png\n done"
|
||||
],
|
||||
"cleanup": ["/include", "/lib/pkgconfig", "/share/gtk-doc"],
|
||||
"sources": [
|
||||
{
|
||||
"type": "file",
|
||||
"path": "../rustdesk-1.2.1.deb"
|
||||
"path": "../rustdesk-1.2.2.deb"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 487 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 719 B |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="#fff" d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"/></svg>
|
||||
|
Before Width: | Height: | Size: 792 B |
|
Before Width: | Height: | Size: 18 KiB |
1
flutter/assets/auth-apple.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><circle cx="512" cy="512" r="512" fill="#999"/><path fill="#fff" d="M407.2 722.1c-10.1-6.7-19-15-26.5-24.5-8.2-9.9-15.7-20.3-22.7-31-16.3-23.9-29.1-50-38-77.5-10.7-32-15.8-62.7-15.8-92.7 0-33.5 7.2-62.7 21.4-87.2 10.4-19.2 26-35.2 44.8-46.5 18.1-11.3 39.2-17.5 60.6-17.9 7.5 0 15.6 1.1 24.1 3.2 6.2 1.7 13.6 4.5 22.8 7.9 11.7 4.5 18.1 7.2 20.3 7.9 6.8 2.6 12.6 3.6 17.1 3.6 3.4 0 8.3-1.1 13.8-2.8 3.1-1.1 9-3 17.3-6.6 8.2-3 14.8-5.5 19.9-7.5 7.9-2.3 15.5-4.5 22.4-5.5 8.3-1.3 16.6-1.7 24.5-1.1 15.1 1.1 29 4.3 41.4 9 21.7 8.7 39.3 22.4 52.4 41.8-5.5 3.4-10.7 7.4-15.5 11.7-10.4 9.2-19.2 20-26.2 32.1-9.2 16.4-13.9 35-13.7 53.7.3 23.1 6.2 43.4 17.9 61 8.3 12.8 19.3 23.8 32.7 32.7 6.6 4.5 12.4 7.6 17.9 9.6-2.6 8-5.4 15.8-8.6 23.5-7.4 17.2-16.2 33.7-26.7 49.3-9.2 13.4-16.5 23.5-22 30.1-8.6 10.2-16.8 17.9-25.2 23.4-9.2 6.1-19.9 9.3-31 9.3-7.5.3-14.9-.6-22-2.7-6.2-2-12.3-4.3-18.3-6.9-6.2-2.9-12.7-5.3-19.3-7.2-8.1-2.1-16.4-3.2-24.8-3.1-8.5 0-16.8 1.1-24.7 3.1-6.6 1.9-13 4.2-19.3 6.9-9 3.7-14.8 6.2-18.2 7.2-6.9 2-14 3.3-21.1 3.7-11.1 0-21.4-3.2-31.7-9.6zm146.1-393.6c-14.5 7.2-28.3 10.3-42.1 9.3-2.1-13.8 0-27.9 5.8-43.4 5.1-13.2 11.9-25.2 21.3-35.8 9.8-11.1 21.5-20.3 34.8-26.9 14.1-7.2 27.5-11.1 40.3-11.7 1.7 14.5 0 28.8-5.3 44.1-4.9 13.6-12.1 26.2-21.3 37.5-9.3 11.1-20.8 20.3-33.8 26.9z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
flutter/assets/auth-auth0.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32"><path d="M29.307 9.932 26.161 0H5.796L2.692 9.932c-1.802 5.75.042 12.271 5.089 16.021L16.01 32l8.208-6.068c5.005-3.75 6.911-10.25 5.089-16.021l-8.214 6.104 3.12 9.938-8.208-6.13-8.208 6.104 3.141-9.911-8.25-6.063 10.177-.063 3.146-9.891 3.141 9.87z"/></svg>
|
||||
|
After Width: | Height: | Size: 285 B |
1
flutter/assets/auth-azure.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="199"><path fill="#0089d6" d="M118.432 187.698c32.89-5.81 60.055-10.618 60.367-10.684l.568-.12-31.052-36.935c-17.078-20.314-31.051-37.014-31.051-37.11 0-.182 32.063-88.477 32.243-88.792.06-.105 21.88 37.567 52.893 91.32 29.035 50.323 52.973 91.815 53.195 92.203l.405.707-98.684-.012-98.684-.013 59.8-10.564zM0 176.435c0-.052 14.631-25.451 32.514-56.442l32.514-56.347 37.891-31.799C123.76 14.358 140.867.027 140.935.001c.069-.026-.205.664-.609 1.534s-18.919 40.582-41.145 88.25l-40.41 86.67-29.386.037c-16.162.02-29.385-.005-29.385-.057z"/></svg>
|
||||
|
After Width: | Height: | Size: 604 B |
1
flutter/assets/auth-default.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120"><path d="M142.554 52.81c0-4.113 1.078-6.374 5.369-11.26 17.207-19.593 57.193-19.593 74.4 0 4.291 4.886 5.37 7.147 5.37 11.26v5.145h-85.14zm71.239-42.863 6.676-6.692 10.462 10.74 25.49-25.453 6.133 6.543-31.536 32.356-17.225-17.494Zm-34.474 3.377c-15.027-5.337-19.348-22.264-8.57-33.575 10.85-11.387 29.85-6.099 34.149 9.503 2.523 9.161-4.38 21.951-12.951 23.995-4.39 1.58-8.73 1.433-12.628.077z" style="fill:#024eff;fill-opacity:1;stroke-width:.999998" transform="translate(-142.554 44.365)"/></svg>
|
||||
|
After Width: | Height: | Size: 564 B |
1
flutter/assets/auth-facebook.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><rect width="512" height="512" fill="#1877f2" rx="76.8"/><path fill="#fff" d="m355.6 330 11.4-74h-71v-48c0-20.2 9.9-40 41.7-40H370v-63s-29.3-5-57.3-5c-58.5 0-96.7 35.4-96.7 99.6V256h-65v74h65v182h80V330z"/></svg>
|
||||
|
After Width: | Height: | Size: 274 B |
1
flutter/assets/auth-github.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24"><path fill="#231f20" d="M12 1A10.89 10.89 0 0 0 1 11.77 10.79 10.79 0 0 0 8.52 22c.55.1.75-.23.75-.52v-1.83c-3.06.65-3.71-1.44-3.71-1.44a2.86 2.86 0 0 0-1.22-1.58c-1-.66.08-.65.08-.65a2.31 2.31 0 0 1 1.68 1.11 2.37 2.37 0 0 0 3.2.89 2.33 2.33 0 0 1 .7-1.44c-2.44-.27-5-1.19-5-5.32a4.15 4.15 0 0 1 1.11-2.91 3.78 3.78 0 0 1 .11-2.84s.93-.29 3 1.1a10.68 10.68 0 0 1 5.5 0c2.1-1.39 3-1.1 3-1.1a3.78 3.78 0 0 1 .11 2.84A4.15 4.15 0 0 1 19 11.2c0 4.14-2.58 5.05-5 5.32a2.5 2.5 0 0 1 .75 2v2.95s.2.63.75.52A10.8 10.8 0 0 0 23 11.77 10.89 10.89 0 0 0 12 1"/></svg>
|
||||
|
After Width: | Height: | Size: 582 B |
1
flutter/assets/auth-google.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48"><path fill="#ffc107" d="M43.611 20.083H42V20H24v8h11.303c-1.649 4.657-6.08 8-11.303 8-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 12.955 4 4 12.955 4 24s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z"/><path fill="#ff3d00" d="m6.306 14.691 6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 16.318 4 9.656 8.337 6.306 14.691z"/><path fill="#4caf50" d="M24 44c5.166 0 9.86-1.977 13.409-5.192l-6.19-5.238A11.91 11.91 0 0 1 24 36c-5.202 0-9.619-3.317-11.283-7.946l-6.522 5.025C9.505 39.556 16.227 44 24 44z"/><path fill="#1976d2" d="M43.611 20.083H42V20H24v8h11.303a12.04 12.04 0 0 1-4.087 5.571l.003-.002 6.19 5.238C36.971 39.205 44 34 44 24c0-1.341-.138-2.65-.389-3.917z"/></svg>
|
||||
|
After Width: | Height: | Size: 846 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
flutter/assets/checkbox.ttf
Normal file
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 669 B After Width: | Height: | Size: 511 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 989 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 755 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 989 B |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -11,15 +11,16 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
|
||||
import 'package:flutter_hbb/main.dart';
|
||||
import 'package:flutter_hbb/models/peer_model.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:flutter_hbb/utils/platform_channel.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
@@ -47,11 +48,6 @@ var isMobile = isAndroid || isIOS;
|
||||
var version = "";
|
||||
int androidVersion = 0;
|
||||
|
||||
/// Incriment count for textureId.
|
||||
int _textureId = 0;
|
||||
int get newTextureId => _textureId++;
|
||||
final textureRenderer = TextureRgbaRenderer();
|
||||
|
||||
/// only available for Windows target
|
||||
int windowsBuildNumber = 0;
|
||||
DesktopType? desktopType;
|
||||
@@ -95,6 +91,7 @@ class IconFont {
|
||||
static const IconData roundClose = IconData(0xe6ed, fontFamily: _family2);
|
||||
static const IconData addressBook =
|
||||
IconData(0xe602, fontFamily: "AddressBook");
|
||||
static const IconData checkbox = IconData(0xe7d6, fontFamily: "CheckBox");
|
||||
}
|
||||
|
||||
class ColorThemeExtension extends ThemeExtension<ColorThemeExtension> {
|
||||
@@ -223,6 +220,13 @@ class MyTheme {
|
||||
),
|
||||
);
|
||||
|
||||
//tooltip
|
||||
static TooltipThemeData tooltipTheme() {
|
||||
return TooltipThemeData(
|
||||
waitDuration: Duration(seconds: 1, milliseconds: 500),
|
||||
);
|
||||
}
|
||||
|
||||
// Dialogs
|
||||
static const double dialogPadding = 24;
|
||||
|
||||
@@ -292,6 +296,7 @@ class MyTheme {
|
||||
tabBarTheme: const TabBarTheme(
|
||||
labelColor: Colors.black87,
|
||||
),
|
||||
tooltipTheme: tooltipTheme(),
|
||||
splashColor: isDesktop ? Colors.transparent : null,
|
||||
highlightColor: isDesktop ? Colors.transparent : null,
|
||||
splashFactory: isDesktop ? NoSplash.splashFactory : null,
|
||||
@@ -381,6 +386,7 @@ class MyTheme {
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: MaterialStateProperty.all(Colors.grey[500]),
|
||||
),
|
||||
tooltipTheme: tooltipTheme(),
|
||||
splashColor: isDesktop ? Colors.transparent : null,
|
||||
highlightColor: isDesktop ? Colors.transparent : null,
|
||||
splashFactory: isDesktop ? NoSplash.splashFactory : null,
|
||||
@@ -549,17 +555,19 @@ closeConnection({String? id}) {
|
||||
}
|
||||
}
|
||||
|
||||
void window_on_top(int? id) async {
|
||||
void windowOnTop(int? id) async {
|
||||
if (!isDesktop) {
|
||||
return;
|
||||
}
|
||||
print("Bring window '$id' on top");
|
||||
if (id == null) {
|
||||
print("Bring window on top");
|
||||
// main window
|
||||
windowManager.restore();
|
||||
windowManager.show();
|
||||
windowManager.focus();
|
||||
rustDeskWinManager.registerActiveWindow(kWindowMainId);
|
||||
if (stateGlobal.isMinimized) {
|
||||
await windowManager.restore();
|
||||
}
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
await rustDeskWinManager.registerActiveWindow(kWindowMainId);
|
||||
} else {
|
||||
WindowController.fromWindowId(id)
|
||||
..focus()
|
||||
@@ -689,9 +697,12 @@ class OverlayDialogManager {
|
||||
String showLoading(String text,
|
||||
{bool clickMaskDismiss = false,
|
||||
bool showCancel = true,
|
||||
VoidCallback? onCancel}) {
|
||||
final tag = _tagCount.toString();
|
||||
_tagCount++;
|
||||
VoidCallback? onCancel,
|
||||
String? tag}) {
|
||||
if (tag == null) {
|
||||
tag = _tagCount.toString();
|
||||
_tagCount++;
|
||||
}
|
||||
show((setState, close, context) {
|
||||
cancel() {
|
||||
dismissAll();
|
||||
@@ -1066,6 +1077,37 @@ Color str2color(String str, [alpha = 0xFF]) {
|
||||
return Color((hash & 0xFF7FFF) | (alpha << 24));
|
||||
}
|
||||
|
||||
Color str2color2(String str, [alpha = 0xFF]) {
|
||||
Map<String, Color> colorMap = {
|
||||
"red": Colors.red,
|
||||
"green": Colors.green,
|
||||
"blue": Colors.blue,
|
||||
"orange": Colors.orange,
|
||||
"purple": Colors.purple,
|
||||
"grey": Colors.grey,
|
||||
"cyan": Colors.cyan,
|
||||
"lime": Colors.lime,
|
||||
"teal": Colors.teal,
|
||||
"pink": Colors.pink[200]!,
|
||||
"indigo": Colors.indigo,
|
||||
"brown": Colors.brown,
|
||||
};
|
||||
final color = colorMap[str.toLowerCase()];
|
||||
if (color != null) {
|
||||
return color.withAlpha(alpha);
|
||||
}
|
||||
if (str.toLowerCase() == 'yellow') {
|
||||
return Colors.yellow.withAlpha(alpha);
|
||||
}
|
||||
var hash = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
hash += str.codeUnitAt(i);
|
||||
}
|
||||
List<Color> colorList = colorMap.values.toList();
|
||||
hash = hash % colorList.length;
|
||||
return colorList[hash].withAlpha(alpha);
|
||||
}
|
||||
|
||||
const K = 1024;
|
||||
const M = K * K;
|
||||
const G = M * K;
|
||||
@@ -1222,7 +1264,7 @@ FFI get gFFI => _globalFFI;
|
||||
|
||||
Future<void> initGlobalFFI() async {
|
||||
debugPrint("_globalFFI init");
|
||||
_globalFFI = FFI();
|
||||
_globalFFI = FFI(null);
|
||||
debugPrint("_globalFFI init end");
|
||||
// after `put`, can also be globally found by Get.find<FFI>();
|
||||
Get.put(_globalFFI, permanent: true);
|
||||
@@ -1243,7 +1285,7 @@ bool option2bool(String option, String value) {
|
||||
option == "stop-service" ||
|
||||
option == "direct-server" ||
|
||||
option == "stop-rendezvous-service" ||
|
||||
option == "force-always-relay") {
|
||||
option == kOptionForceAlwaysRelay) {
|
||||
res = value == "Y";
|
||||
} else {
|
||||
assert(false);
|
||||
@@ -1260,7 +1302,7 @@ String bool2option(String option, bool b) {
|
||||
option == "stop-service" ||
|
||||
option == "direct-server" ||
|
||||
option == "stop-rendezvous-service" ||
|
||||
option == "force-always-relay") {
|
||||
option == kOptionForceAlwaysRelay) {
|
||||
res = b ? 'Y' : '';
|
||||
} else {
|
||||
assert(false);
|
||||
@@ -1269,6 +1311,36 @@ String bool2option(String option, bool b) {
|
||||
return res;
|
||||
}
|
||||
|
||||
mainSetBoolOption(String key, bool value) async {
|
||||
String v = bool2option(key, value);
|
||||
await bind.mainSetOption(key: key, value: v);
|
||||
}
|
||||
|
||||
Future<bool> mainGetBoolOption(String key) async {
|
||||
return option2bool(key, await bind.mainGetOption(key: key));
|
||||
}
|
||||
|
||||
bool mainGetBoolOptionSync(String key) {
|
||||
return option2bool(key, bind.mainGetOptionSync(key: key));
|
||||
}
|
||||
|
||||
mainSetLocalBoolOption(String key, bool value) async {
|
||||
String v = bool2option(key, value);
|
||||
await bind.mainSetLocalOption(key: key, value: v);
|
||||
}
|
||||
|
||||
bool mainGetLocalBoolOptionSync(String key) {
|
||||
return option2bool(key, bind.mainGetLocalOption(key: key));
|
||||
}
|
||||
|
||||
bool mainGetPeerBoolOptionSync(String id, String key) {
|
||||
return option2bool(key, bind.mainGetPeerOptionSync(id: id, key: key));
|
||||
}
|
||||
|
||||
mainSetPeerBoolOptionSync(String id, String key, bool v) {
|
||||
bind.mainSetPeerOptionSync(id: id, key: key, value: bool2option(key, v));
|
||||
}
|
||||
|
||||
Future<bool> matchPeer(String searchText, Peer peer) async {
|
||||
if (searchText.isEmpty) {
|
||||
return true;
|
||||
@@ -1280,7 +1352,7 @@ Future<bool> matchPeer(String searchText, Peer peer) async {
|
||||
peer.username.toLowerCase().contains(searchText)) {
|
||||
return true;
|
||||
}
|
||||
final alias = await bind.mainGetPeerOption(id: peer.id, key: 'alias');
|
||||
final alias = peer.alias;
|
||||
if (alias.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
@@ -1337,7 +1409,9 @@ class LastWindowPosition {
|
||||
return LastWindowPosition(m["width"], m["height"], m["offsetWidth"],
|
||||
m["offsetHeight"], m["isMaximized"]);
|
||||
} catch (e) {
|
||||
debugPrintStack(label: e.toString());
|
||||
debugPrintStack(
|
||||
label:
|
||||
'Failed to load LastWindowPosition "$content" ${e.toString()}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1350,18 +1424,30 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
|
||||
debugPrint(
|
||||
"Error: windowId cannot be null when saving positions for sub window");
|
||||
}
|
||||
|
||||
late Offset position;
|
||||
late Size sz;
|
||||
late bool isMaximized;
|
||||
setFrameIfMaximized() {
|
||||
if (isMaximized) {
|
||||
final pos = bind.getLocalFlutterOption(k: kWindowPrefix + type.name);
|
||||
var lpos = LastWindowPosition.loadFromString(pos);
|
||||
position = Offset(
|
||||
lpos?.offsetWidth ?? position.dx, lpos?.offsetHeight ?? position.dy);
|
||||
sz = Size(lpos?.width ?? sz.width, lpos?.height ?? sz.height);
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case WindowType.Main:
|
||||
final position = await windowManager.getPosition();
|
||||
final sz = await windowManager.getSize();
|
||||
final isMaximized = await windowManager.isMaximized();
|
||||
final pos = LastWindowPosition(
|
||||
sz.width, sz.height, position.dx, position.dy, isMaximized);
|
||||
await bind.setLocalFlutterConfig(
|
||||
k: kWindowPrefix + type.name, v: pos.toString());
|
||||
isMaximized = await windowManager.isMaximized();
|
||||
position = await windowManager.getPosition();
|
||||
sz = await windowManager.getSize();
|
||||
setFrameIfMaximized();
|
||||
break;
|
||||
default:
|
||||
final wc = WindowController.fromWindowId(windowId!);
|
||||
isMaximized = await wc.isMaximized();
|
||||
final Rect frame;
|
||||
try {
|
||||
frame = await wc.getFrame();
|
||||
@@ -1369,38 +1455,72 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
|
||||
debugPrint("Failed to get frame of window $windowId, it may be hidden");
|
||||
return;
|
||||
}
|
||||
final position = frame.topLeft;
|
||||
final sz = frame.size;
|
||||
final isMaximized = await wc.isMaximized();
|
||||
final pos = LastWindowPosition(
|
||||
sz.width, sz.height, position.dx, position.dy, isMaximized);
|
||||
debugPrint(
|
||||
"saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}");
|
||||
await bind.setLocalFlutterConfig(
|
||||
k: kWindowPrefix + type.name, v: pos.toString());
|
||||
position = frame.topLeft;
|
||||
sz = frame.size;
|
||||
setFrameIfMaximized();
|
||||
break;
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
const kMinOffset = -10000;
|
||||
const kMaxOffset = 10000;
|
||||
if (position.dx < kMinOffset ||
|
||||
position.dy < kMinOffset ||
|
||||
position.dx > kMaxOffset ||
|
||||
position.dy > kMaxOffset) {
|
||||
debugPrint("Invalid position: $position, ignore saving position");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final pos = LastWindowPosition(
|
||||
sz.width, sz.height, position.dx, position.dy, isMaximized);
|
||||
debugPrint(
|
||||
"Saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}, isMaximized:${pos.isMaximized}");
|
||||
|
||||
await bind.setLocalFlutterOption(
|
||||
k: kWindowPrefix + type.name, v: pos.toString());
|
||||
|
||||
if (type == WindowType.RemoteDesktop && windowId != null) {
|
||||
await _saveSessionWindowPosition(type, windowId, isMaximized, pos);
|
||||
}
|
||||
}
|
||||
|
||||
Future _saveSessionWindowPosition(WindowType windowType, int windowId,
|
||||
bool isMaximized, LastWindowPosition pos) async {
|
||||
final remoteList = await DesktopMultiWindow.invokeMethod(
|
||||
windowId, kWindowEventGetRemoteList, null);
|
||||
getPeerPos(String peerId) {
|
||||
if (isMaximized) {
|
||||
final peerPos = bind.mainGetPeerFlutterOptionSync(
|
||||
id: peerId, k: kWindowPrefix + windowType.name);
|
||||
var lpos = LastWindowPosition.loadFromString(peerPos);
|
||||
return LastWindowPosition(
|
||||
lpos?.width ?? pos.offsetWidth,
|
||||
lpos?.height ?? pos.offsetHeight,
|
||||
lpos?.offsetWidth ?? pos.offsetWidth,
|
||||
lpos?.offsetHeight ?? pos.offsetHeight,
|
||||
isMaximized)
|
||||
.toString();
|
||||
} else {
|
||||
return pos.toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteList != null) {
|
||||
for (final peerId in remoteList.split(',')) {
|
||||
bind.mainSetPeerFlutterOptionSync(
|
||||
id: peerId,
|
||||
k: kWindowPrefix + windowType.name,
|
||||
v: getPeerPos(peerId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<Size> _adjustRestoreMainWindowSize(double? width, double? height) async {
|
||||
const double minWidth = 600;
|
||||
const double minHeight = 100;
|
||||
double maxWidth = (((isDesktop || isWebDesktop)
|
||||
? kDesktopMaxDisplayWidth
|
||||
: kMobileMaxDisplayWidth))
|
||||
.toDouble();
|
||||
double maxHeight = ((isDesktop || isWebDesktop)
|
||||
? kDesktopMaxDisplayHeight
|
||||
: kMobileMaxDisplayHeight)
|
||||
.toDouble();
|
||||
|
||||
if (isDesktop || isWebDesktop) {
|
||||
final screen = (await window_size.getWindowInfo()).screen;
|
||||
if (screen != null) {
|
||||
maxWidth = screen.visibleFrame.width;
|
||||
maxHeight = screen.visibleFrame.height;
|
||||
}
|
||||
}
|
||||
const double minWidth = 1;
|
||||
const double minHeight = 1;
|
||||
const double maxWidth = 6480;
|
||||
const double maxHeight = 6480;
|
||||
|
||||
final defaultWidth =
|
||||
((isDesktop || isWebDesktop) ? 1280 : kMobileDefaultDisplayWidth)
|
||||
@@ -1412,64 +1532,79 @@ Future<Size> _adjustRestoreMainWindowSize(double? width, double? height) async {
|
||||
double restoreHeight = height ?? defaultHeight;
|
||||
|
||||
if (restoreWidth < minWidth) {
|
||||
restoreWidth = minWidth;
|
||||
restoreWidth = defaultWidth;
|
||||
}
|
||||
if (restoreHeight < minHeight) {
|
||||
restoreHeight = minHeight;
|
||||
restoreHeight = defaultHeight;
|
||||
}
|
||||
if (restoreWidth > maxWidth) {
|
||||
restoreWidth = maxWidth;
|
||||
restoreWidth = defaultWidth;
|
||||
}
|
||||
if (restoreHeight > maxHeight) {
|
||||
restoreHeight = maxHeight;
|
||||
restoreHeight = defaultHeight;
|
||||
}
|
||||
return Size(restoreWidth, restoreHeight);
|
||||
}
|
||||
|
||||
/// return null means center
|
||||
Future<Offset?> _adjustRestoreMainWindowOffset(
|
||||
double? left, double? top) async {
|
||||
if (left == null || top == null) {
|
||||
await windowManager.center();
|
||||
} else {
|
||||
double windowLeft = max(0.0, left);
|
||||
double windowTop = max(0.0, top);
|
||||
double? left,
|
||||
double? top,
|
||||
double? width,
|
||||
double? height,
|
||||
) async {
|
||||
if (left == null || top == null || width == null || height == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
double frameLeft = double.infinity;
|
||||
double frameTop = double.infinity;
|
||||
double frameRight = ((isDesktop || isWebDesktop)
|
||||
? kDesktopMaxDisplayWidth
|
||||
: kMobileMaxDisplayWidth)
|
||||
.toDouble();
|
||||
double frameBottom = ((isDesktop || isWebDesktop)
|
||||
? kDesktopMaxDisplayHeight
|
||||
: kMobileMaxDisplayHeight)
|
||||
.toDouble();
|
||||
double? frameLeft;
|
||||
double? frameTop;
|
||||
double? frameRight;
|
||||
double? frameBottom;
|
||||
|
||||
if (isDesktop || isWebDesktop) {
|
||||
for (final screen in await window_size.getScreenList()) {
|
||||
frameLeft = min(screen.visibleFrame.left, frameLeft);
|
||||
frameTop = min(screen.visibleFrame.top, frameTop);
|
||||
frameRight = max(screen.visibleFrame.right, frameRight);
|
||||
frameBottom = max(screen.visibleFrame.bottom, frameBottom);
|
||||
}
|
||||
}
|
||||
|
||||
if (windowLeft < frameLeft ||
|
||||
windowLeft > frameRight ||
|
||||
windowTop < frameTop ||
|
||||
windowTop > frameBottom) {
|
||||
return null;
|
||||
} else {
|
||||
return Offset(windowLeft, windowTop);
|
||||
if (isDesktop || isWebDesktop) {
|
||||
for (final screen in await window_size.getScreenList()) {
|
||||
frameLeft = frameLeft == null
|
||||
? screen.visibleFrame.left
|
||||
: min(screen.visibleFrame.left, frameLeft);
|
||||
frameTop = frameTop == null
|
||||
? screen.visibleFrame.top
|
||||
: min(screen.visibleFrame.top, frameTop);
|
||||
frameRight = frameRight == null
|
||||
? screen.visibleFrame.right
|
||||
: max(screen.visibleFrame.right, frameRight);
|
||||
frameBottom = frameBottom == null
|
||||
? screen.visibleFrame.bottom
|
||||
: max(screen.visibleFrame.bottom, frameBottom);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (frameLeft == null) {
|
||||
frameLeft = 0.0;
|
||||
frameTop = 0.0;
|
||||
frameRight = ((isDesktop || isWebDesktop)
|
||||
? kDesktopMaxDisplaySize
|
||||
: kMobileMaxDisplaySize)
|
||||
.toDouble();
|
||||
frameBottom = ((isDesktop || isWebDesktop)
|
||||
? kDesktopMaxDisplaySize
|
||||
: kMobileMaxDisplaySize)
|
||||
.toDouble();
|
||||
}
|
||||
final minWidth = 10.0;
|
||||
if ((left + minWidth) > frameRight! ||
|
||||
(top + minWidth) > frameBottom! ||
|
||||
(left + width - minWidth) < frameLeft ||
|
||||
top < frameTop!) {
|
||||
return null;
|
||||
} else {
|
||||
return Offset(left, top);
|
||||
}
|
||||
}
|
||||
|
||||
/// Restore window position and size on start
|
||||
/// Note that windowId must be provided if it's subwindow
|
||||
Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
||||
Future<bool> restoreWindowPosition(WindowType type,
|
||||
{int? windowId, String? peerId}) async {
|
||||
if (bind
|
||||
.mainGetEnv(key: "DISABLE_RUSTDESK_RESTORE_WINDOW_POSITION")
|
||||
.isNotEmpty) {
|
||||
@@ -1478,42 +1613,74 @@ Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
||||
if (type != WindowType.Main && windowId == null) {
|
||||
debugPrint(
|
||||
"Error: windowId cannot be null when saving positions for sub window");
|
||||
return false;
|
||||
}
|
||||
final pos = bind.getLocalFlutterConfig(k: kWindowPrefix + type.name);
|
||||
|
||||
bool isRemotePeerPos = false;
|
||||
String? pos;
|
||||
// No need to check mainGetLocalBoolOptionSync(kOptionOpenNewConnInTabs)
|
||||
// Though "open in tabs" is true and the new window restore peer position, it's ok.
|
||||
if (type == WindowType.RemoteDesktop && windowId != null && peerId != null) {
|
||||
// If the restore position is called by main window, and the peer id is not null
|
||||
// then we may need to get the position by reading the peer config.
|
||||
// Because the session may not be read at this time.
|
||||
if (desktopType == DesktopType.main) {
|
||||
pos = bind.mainGetPeerFlutterOptionSync(
|
||||
id: peerId, k: kWindowPrefix + type.name);
|
||||
} else {
|
||||
pos = await bind.sessionGetFlutterOptionByPeerId(
|
||||
id: peerId, k: kWindowPrefix + type.name);
|
||||
}
|
||||
isRemotePeerPos = pos != null;
|
||||
}
|
||||
pos ??= bind.getLocalFlutterOption(k: kWindowPrefix + type.name);
|
||||
|
||||
var lpos = LastWindowPosition.loadFromString(pos);
|
||||
if (lpos == null) {
|
||||
debugPrint("no window position saved, ignoring position restoration");
|
||||
return false;
|
||||
}
|
||||
if (type == WindowType.RemoteDesktop &&
|
||||
!isRemotePeerPos &&
|
||||
windowId != null) {
|
||||
if (lpos.offsetWidth != null) {
|
||||
lpos.offsetWidth = lpos.offsetWidth! + windowId * 20;
|
||||
}
|
||||
if (lpos.offsetHeight != null) {
|
||||
lpos.offsetHeight = lpos.offsetHeight! + windowId * 20;
|
||||
}
|
||||
}
|
||||
|
||||
final size = await _adjustRestoreMainWindowSize(lpos.width, lpos.height);
|
||||
final offset = await _adjustRestoreMainWindowOffset(
|
||||
lpos.offsetWidth,
|
||||
lpos.offsetHeight,
|
||||
size.width,
|
||||
size.height,
|
||||
);
|
||||
debugPrint(
|
||||
"restore lpos: ${size.width}/${size.height}, offset:${offset?.dx}/${offset?.dy}");
|
||||
|
||||
switch (type) {
|
||||
case WindowType.Main:
|
||||
if (lpos.isMaximized == true) {
|
||||
await windowManager.maximize();
|
||||
} else {
|
||||
final size =
|
||||
await _adjustRestoreMainWindowSize(lpos.width, lpos.height);
|
||||
final offset = await _adjustRestoreMainWindowOffset(
|
||||
lpos.offsetWidth, lpos.offsetHeight);
|
||||
await windowManager.setSize(size);
|
||||
restorePos() async {
|
||||
if (offset == null) {
|
||||
await windowManager.center();
|
||||
} else {
|
||||
await windowManager.setPosition(offset);
|
||||
}
|
||||
}
|
||||
if (lpos.isMaximized == true) {
|
||||
await restorePos();
|
||||
await windowManager.maximize();
|
||||
} else {
|
||||
await windowManager.setSize(size);
|
||||
await restorePos();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
final wc = WindowController.fromWindowId(windowId!);
|
||||
if (lpos.isMaximized == true) {
|
||||
await wc.maximize();
|
||||
} else {
|
||||
final size =
|
||||
await _adjustRestoreMainWindowSize(lpos.width, lpos.height);
|
||||
final offset = await _adjustRestoreMainWindowOffset(
|
||||
lpos.offsetWidth, lpos.offsetHeight);
|
||||
debugPrint(
|
||||
"restore lpos: ${size.width}/${size.height}, offset:${offset?.dx}/${offset?.dy}");
|
||||
restoreFrame() async {
|
||||
if (offset == null) {
|
||||
await wc.center();
|
||||
} else {
|
||||
@@ -1522,6 +1689,12 @@ Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
||||
await wc.setFrame(frame);
|
||||
}
|
||||
}
|
||||
if (lpos.isMaximized == true) {
|
||||
await restoreFrame();
|
||||
await wc.maximize();
|
||||
} else {
|
||||
await restoreFrame();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
@@ -1560,7 +1733,7 @@ StreamSubscription? listenUniLinks({handleByFlutter = true}) {
|
||||
}
|
||||
|
||||
final sub = uriLinkStream.listen((Uri? uri) {
|
||||
debugPrint("A uri was received: $uri.");
|
||||
debugPrint("A uri was received: $uri. handleByFlutter $handleByFlutter");
|
||||
if (uri != null) {
|
||||
if (handleByFlutter) {
|
||||
handleUriLink(uri: uri);
|
||||
@@ -1603,7 +1776,14 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
|
||||
args = urlLinkToCmdArgs(uri);
|
||||
}
|
||||
}
|
||||
if (args == null) return false;
|
||||
if (args == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.isEmpty) {
|
||||
windowOnTop(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
UriLinkType? type;
|
||||
String? id;
|
||||
@@ -1654,7 +1834,7 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
rustDeskWinManager.newRemoteDesktop(id!,
|
||||
password: password,
|
||||
switch_uuid: switchUuid,
|
||||
switchUuid: switchUuid,
|
||||
forceRelay: forceRelay);
|
||||
});
|
||||
break;
|
||||
@@ -1687,7 +1867,10 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
|
||||
List<String>? urlLinkToCmdArgs(Uri uri) {
|
||||
String? command;
|
||||
String? id;
|
||||
if (uri.authority == "connection" && uri.path.startsWith("/new/")) {
|
||||
if (uri.authority.isEmpty &&
|
||||
uri.path.split('').every((char) => char == '/')) {
|
||||
return [];
|
||||
} else if (uri.authority == "connection" && uri.path.startsWith("/new/")) {
|
||||
// For compatibility
|
||||
command = '--connect';
|
||||
id = uri.path.substring("/new/".length);
|
||||
@@ -1719,11 +1902,13 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
connectMainDesktop(String id,
|
||||
{required bool isFileTransfer,
|
||||
required bool isTcpTunneling,
|
||||
required bool isRDP,
|
||||
bool? forceRelay}) async {
|
||||
connectMainDesktop(
|
||||
String id, {
|
||||
required bool isFileTransfer,
|
||||
required bool isTcpTunneling,
|
||||
required bool isRDP,
|
||||
bool? forceRelay,
|
||||
}) async {
|
||||
if (isFileTransfer) {
|
||||
await rustDeskWinManager.newFileTransfer(id, forceRelay: forceRelay);
|
||||
} else if (isTcpTunneling || isRDP) {
|
||||
@@ -1737,11 +1922,22 @@ connectMainDesktop(String id,
|
||||
/// If [isFileTransfer], starts a session only for file transfer.
|
||||
/// If [isTcpTunneling], starts a session only for tcp tunneling.
|
||||
/// If [isRDP], starts a session only for rdp.
|
||||
connect(BuildContext context, String id,
|
||||
{bool isFileTransfer = false,
|
||||
bool isTcpTunneling = false,
|
||||
bool isRDP = false}) async {
|
||||
connect(
|
||||
BuildContext context,
|
||||
String id, {
|
||||
bool isFileTransfer = false,
|
||||
bool isTcpTunneling = false,
|
||||
bool isRDP = false,
|
||||
}) async {
|
||||
if (id == '') return;
|
||||
if (!isDesktop || desktopType == DesktopType.main) {
|
||||
try {
|
||||
if (Get.isRegistered<IDTextEditingController>()) {
|
||||
final idController = Get.find<IDTextEditingController>();
|
||||
idController.text = formatID(id);
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
id = id.replaceAll(' ', '');
|
||||
final oldId = id;
|
||||
id = await bind.mainHandleRelayId(id: id);
|
||||
@@ -1751,18 +1947,20 @@ connect(BuildContext context, String id,
|
||||
|
||||
if (isDesktop) {
|
||||
if (desktopType == DesktopType.main) {
|
||||
await connectMainDesktop(id,
|
||||
isFileTransfer: isFileTransfer,
|
||||
isTcpTunneling: isTcpTunneling,
|
||||
isRDP: isRDP,
|
||||
forceRelay: forceRelay);
|
||||
await connectMainDesktop(
|
||||
id,
|
||||
isFileTransfer: isFileTransfer,
|
||||
isTcpTunneling: isTcpTunneling,
|
||||
isRDP: isRDP,
|
||||
forceRelay: forceRelay,
|
||||
);
|
||||
} else {
|
||||
await rustDeskWinManager.call(WindowType.Main, kWindowConnect, {
|
||||
'id': id,
|
||||
'isFileTransfer': isFileTransfer,
|
||||
'isTcpTunneling': isTcpTunneling,
|
||||
'isRDP': isRDP,
|
||||
"forceRelay": forceRelay,
|
||||
'forceRelay': forceRelay,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -1851,10 +2049,14 @@ Future<void> onActiveWindowChanged() async {
|
||||
if (rustDeskWinManager.getActiveWindows().isEmpty) {
|
||||
// close all sub windows
|
||||
try {
|
||||
await Future.wait([
|
||||
saveWindowPosition(WindowType.Main),
|
||||
rustDeskWinManager.closeAllSubWindows()
|
||||
]);
|
||||
if (Platform.isLinux) {
|
||||
await Future.wait([
|
||||
saveWindowPosition(WindowType.Main),
|
||||
rustDeskWinManager.closeAllSubWindows()
|
||||
]);
|
||||
} else {
|
||||
await rustDeskWinManager.closeAllSubWindows();
|
||||
}
|
||||
} catch (err) {
|
||||
debugPrintStack(label: "$err");
|
||||
} finally {
|
||||
@@ -2154,10 +2356,18 @@ void onCopyFingerprint(String value) {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> callMainCheckSuperUserPermission() async {
|
||||
bool checked = await bind.mainCheckSuperUserPermission();
|
||||
if (Platform.isMacOS) {
|
||||
await windowManager.show();
|
||||
}
|
||||
return checked;
|
||||
}
|
||||
|
||||
Future<void> start_service(bool is_start) async {
|
||||
bool checked = !bind.mainIsInstalled() ||
|
||||
!Platform.isMacOS ||
|
||||
await bind.mainCheckSuperUserPermission();
|
||||
await callMainCheckSuperUserPermission();
|
||||
if (checked) {
|
||||
bind.mainSetOption(key: "stop-service", value: is_start ? "" : "Y");
|
||||
}
|
||||
@@ -2223,3 +2433,10 @@ Widget unreadTopRightBuilder(RxInt? count, {Widget? icon}) {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String toCapitalized(String s) {
|
||||
if (s.isEmpty) {
|
||||
return s;
|
||||
}
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ class IDTextInputFormatter extends TextInputFormatter {
|
||||
selection: TextSelection.collapsed(
|
||||
offset: newID.length - selectionIndexFromTheRight,
|
||||
),
|
||||
// https://github.com/flutter/flutter/issues/78066#issuecomment-797869906
|
||||
composing: newValue.composing,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +35,11 @@ class IDTextInputFormatter extends TextInputFormatter {
|
||||
|
||||
String formatID(String id) {
|
||||
String id2 = id.replaceAll(' ', '');
|
||||
String suffix = '';
|
||||
if (id2.endsWith(r'\r') || id2.endsWith(r'/r')) {
|
||||
suffix = id2.substring(id2.length - 2, id2.length);
|
||||
id2 = id2.substring(0, id2.length - 2);
|
||||
}
|
||||
if (int.tryParse(id2) == null) return id;
|
||||
String newID = '';
|
||||
if (id2.length <= 3) {
|
||||
@@ -45,7 +52,7 @@ String formatID(String id) {
|
||||
newID += " ${id2.substring(i, i + 3)}";
|
||||
}
|
||||
}
|
||||
return newID;
|
||||
return newID + suffix;
|
||||
}
|
||||
|
||||
String trimID(String id) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_hbb/models/peer_model.dart';
|
||||
|
||||
@@ -70,16 +71,6 @@ class PeerPayload {
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceInfo {
|
||||
static Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['os'] = Platform.operatingSystem;
|
||||
data['type'] = "client";
|
||||
data['name'] = bind.mainGetHostname();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class LoginRequest {
|
||||
String? username;
|
||||
String? password;
|
||||
@@ -88,7 +79,6 @@ class LoginRequest {
|
||||
bool? autoLogin;
|
||||
String? type;
|
||||
String? verificationCode;
|
||||
Map<String, dynamic> deviceInfo = DeviceInfo.toJson();
|
||||
|
||||
LoginRequest(
|
||||
{this.username,
|
||||
@@ -110,6 +100,13 @@ class LoginRequest {
|
||||
if (verificationCode != null) {
|
||||
data['verificationCode'] = verificationCode;
|
||||
}
|
||||
|
||||
Map<String, dynamic> deviceInfo = {};
|
||||
try {
|
||||
deviceInfo = jsonDecode(bind.mainGetLoginDeviceInfo());
|
||||
} catch (e) {
|
||||
debugPrint('Failed to decode get device info: $e');
|
||||
}
|
||||
data['deviceInfo'] = deviceInfo;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -3,11 +3,13 @@ import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
||||
import '../../consts.dart';
|
||||
import 'package:flutter_hbb/models/ab_model.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import 'dialog.dart';
|
||||
import 'login.dart';
|
||||
|
||||
final hideAbTagsPanel = false.obs;
|
||||
@@ -37,63 +39,115 @@ class _AddressBookState extends State<AddressBook> {
|
||||
child: ElevatedButton(
|
||||
onPressed: loginDialog, child: Text(translate("Login"))));
|
||||
} else {
|
||||
if (gFFI.abModel.abLoading.value) {
|
||||
if (gFFI.abModel.abLoading.value && gFFI.abModel.emtpy) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
if (gFFI.abModel.abError.isNotEmpty) {
|
||||
return _buildShowError(gFFI.abModel.abError.value);
|
||||
}
|
||||
return isDesktop
|
||||
? _buildAddressBookDesktop()
|
||||
: _buildAddressBookMobile();
|
||||
return Column(
|
||||
children: [
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (gFFI.abModel.retrying.value) LinearProgressIndicator(),
|
||||
_buildErrorBanner(
|
||||
err: gFFI.abModel.pullError,
|
||||
retry: null,
|
||||
close: () => gFFI.abModel.pullError.value = ''),
|
||||
_buildErrorBanner(
|
||||
err: gFFI.abModel.pushError,
|
||||
retry: () => gFFI.abModel.pushAb(isRetry: true),
|
||||
close: () => gFFI.abModel.pushError.value = ''),
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
? _buildAddressBookDesktop()
|
||||
: _buildAddressBookMobile())
|
||||
],
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Widget _buildShowError(String error) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(translate(error)),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
gFFI.abModel.pullAb();
|
||||
},
|
||||
child: Text(translate("Retry")))
|
||||
],
|
||||
));
|
||||
Widget _buildErrorBanner(
|
||||
{required RxString err,
|
||||
required Function? retry,
|
||||
required Function close}) {
|
||||
const double height = 25;
|
||||
return Obx(() => Offstage(
|
||||
offstage: !(!gFFI.abModel.abLoading.value && err.value.isNotEmpty),
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: height,
|
||||
color: Color.fromARGB(255, 253, 238, 235),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
FittedBox(
|
||||
child: Icon(
|
||||
Icons.info,
|
||||
color: Color.fromARGB(255, 249, 81, 81),
|
||||
),
|
||||
).marginAll(4),
|
||||
Flexible(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Tooltip(
|
||||
message: translate(err.value),
|
||||
child: Text(
|
||||
translate(err.value),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)).marginSymmetric(vertical: 2),
|
||||
),
|
||||
if (retry != null)
|
||||
InkWell(
|
||||
onTap: () {
|
||||
retry.call();
|
||||
},
|
||||
child: Text(
|
||||
translate("Retry"),
|
||||
style: TextStyle(color: MyTheme.accent),
|
||||
)).marginSymmetric(horizontal: 5),
|
||||
FittedBox(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
close.call();
|
||||
},
|
||||
child: Icon(Icons.close).marginSymmetric(horizontal: 5),
|
||||
),
|
||||
).marginAll(4)
|
||||
],
|
||||
),
|
||||
)).marginOnly(bottom: 14),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildAddressBookDesktop() {
|
||||
return Row(
|
||||
children: [
|
||||
Offstage(
|
||||
offstage: hideAbTagsPanel.value,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border:
|
||||
Border.all(color: Theme.of(context).colorScheme.background)),
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: double.infinity,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: _buildTags(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
).marginOnly(right: 12.0)),
|
||||
offstage: hideAbTagsPanel.value,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.background)),
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: double.infinity,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: _buildTags(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
).marginOnly(right: 12.0)),
|
||||
_buildPeersViews()
|
||||
],
|
||||
);
|
||||
@@ -102,25 +156,27 @@ class _AddressBookState extends State<AddressBook> {
|
||||
Widget _buildAddressBookMobile() {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border:
|
||||
Border.all(color: Theme.of(context).colorScheme.background)),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
child: _buildTags(),
|
||||
Offstage(
|
||||
offstage: hideAbTagsPanel.value,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.background)),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
child: _buildTags(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
).marginOnly(bottom: 12.0),
|
||||
),
|
||||
).marginOnly(bottom: 12.0)),
|
||||
_buildPeersViews()
|
||||
],
|
||||
);
|
||||
@@ -144,9 +200,16 @@ class _AddressBookState extends State<AddressBook> {
|
||||
}
|
||||
|
||||
Widget _buildTags() {
|
||||
return Obx(
|
||||
() => Wrap(
|
||||
children: gFFI.abModel.tags
|
||||
return Obx(() {
|
||||
final List tags;
|
||||
if (gFFI.abModel.sortTags.value) {
|
||||
tags = gFFI.abModel.tags.toList();
|
||||
tags.sort();
|
||||
} else {
|
||||
tags = gFFI.abModel.tags;
|
||||
}
|
||||
return Wrap(
|
||||
children: tags
|
||||
.map((e) => AddressBookTag(
|
||||
name: e,
|
||||
tags: gFFI.abModel.selectedTags,
|
||||
@@ -158,8 +221,8 @@ class _AddressBookState extends State<AddressBook> {
|
||||
}
|
||||
}))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildPeersViews() {
|
||||
@@ -174,11 +237,44 @@ class _AddressBookState extends State<AddressBook> {
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
MenuEntryBase<String> syncMenuItem() {
|
||||
return MenuEntrySwitch<String>(
|
||||
switchType: SwitchType.scheckbox,
|
||||
text: translate('Sync with recent sessions'),
|
||||
getter: () async {
|
||||
return shouldSyncAb();
|
||||
},
|
||||
setter: (bool v) async {
|
||||
bind.mainSetLocalOption(key: syncAbOption, value: v ? 'Y' : '');
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
MenuEntryBase<String> sortMenuItem() {
|
||||
return MenuEntrySwitch<String>(
|
||||
switchType: SwitchType.scheckbox,
|
||||
text: translate('Sort tags'),
|
||||
getter: () async {
|
||||
return shouldSortTags();
|
||||
},
|
||||
setter: (bool v) async {
|
||||
bind.mainSetLocalOption(key: sortAbTagsOption, value: v ? 'Y' : '');
|
||||
gFFI.abModel.sortTags.value = v;
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
);
|
||||
}
|
||||
|
||||
void _showMenu(RelativeRect pos) {
|
||||
final items = [
|
||||
getEntry(translate("Add ID"), abAddId),
|
||||
getEntry(translate("Add Tag"), abAddTag),
|
||||
getEntry(translate("Unselect all tags"), gFFI.abModel.unsetSelectedTags),
|
||||
sortMenuItem(),
|
||||
syncMenuItem(),
|
||||
];
|
||||
|
||||
mod_menu.showMenu(
|
||||
@@ -198,6 +294,9 @@ class _AddressBookState extends State<AddressBook> {
|
||||
}
|
||||
|
||||
void abAddId() async {
|
||||
if (gFFI.abModel.isFull(true)) {
|
||||
return;
|
||||
}
|
||||
var isInProgress = false;
|
||||
IDTextEditingController idController = IDTextEditingController(text: '');
|
||||
TextEditingController aliasController = TextEditingController(text: '');
|
||||
@@ -224,13 +323,14 @@ class _AddressBookState extends State<AddressBook> {
|
||||
return;
|
||||
}
|
||||
gFFI.abModel.addId(id, aliasController.text.trim(), selectedTag);
|
||||
await gFFI.abModel.pushAb();
|
||||
gFFI.abModel.pushAb();
|
||||
this.setState(() {});
|
||||
// final currentPeers
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
double marginBottom = 4;
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Add ID")),
|
||||
content: Column(
|
||||
@@ -252,7 +352,7 @@ class _AddressBookState extends State<AddressBook> {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
).marginOnly(bottom: marginBottom),
|
||||
TextField(
|
||||
controller: idController,
|
||||
inputFormatters: [IDTextInputFormatter()],
|
||||
@@ -264,7 +364,7 @@ class _AddressBookState extends State<AddressBook> {
|
||||
translate('Alias'),
|
||||
style: style,
|
||||
),
|
||||
).marginOnly(top: 8, bottom: 2),
|
||||
).marginOnly(top: 8, bottom: marginBottom),
|
||||
TextField(
|
||||
controller: aliasController,
|
||||
),
|
||||
@@ -274,8 +374,9 @@ class _AddressBookState extends State<AddressBook> {
|
||||
translate('Tags'),
|
||||
style: style,
|
||||
),
|
||||
).marginOnly(top: 8),
|
||||
Container(
|
||||
).marginOnly(top: 8, bottom: marginBottom),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Wrap(
|
||||
children: tags
|
||||
.map((e) => AddressBookTag(
|
||||
@@ -297,8 +398,8 @@ class _AddressBookState extends State<AddressBook> {
|
||||
const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
Offstage(
|
||||
offstage: !isInProgress, child: const LinearProgressIndicator())
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@@ -331,7 +432,7 @@ class _AddressBookState extends State<AddressBook> {
|
||||
for (final tag in tags) {
|
||||
gFFI.abModel.addTag(tag);
|
||||
}
|
||||
await gFFI.abModel.pushAb();
|
||||
gFFI.abModel.pushAb();
|
||||
// final currentPeers
|
||||
}
|
||||
close();
|
||||
@@ -363,8 +464,8 @@ class _AddressBookState extends State<AddressBook> {
|
||||
const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
Offstage(
|
||||
offstage: !isInProgress, child: const LinearProgressIndicator())
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@@ -402,31 +503,71 @@ class AddressBookTag extends StatelessWidget {
|
||||
pos = RelativeRect.fromLTRB(x, y, x, y);
|
||||
}
|
||||
|
||||
const double radius = 8;
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
onTapDown: showActionMenu ? setPosition : null,
|
||||
onSecondaryTapDown: showActionMenu ? setPosition : null,
|
||||
onSecondaryTap: showActionMenu ? () => _showMenu(context, pos) : null,
|
||||
onLongPress: showActionMenu ? () => _showMenu(context, pos) : null,
|
||||
child: Obx(
|
||||
() => Container(
|
||||
decoration: BoxDecoration(
|
||||
color: tags.contains(name)
|
||||
? Colors.blue
|
||||
: Theme.of(context).colorScheme.background,
|
||||
borderRadius: BorderRadius.circular(6)),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 8.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0),
|
||||
child: Text(name,
|
||||
style:
|
||||
TextStyle(color: tags.contains(name) ? Colors.white : null)),
|
||||
),
|
||||
),
|
||||
child: Obx(() => Container(
|
||||
decoration: BoxDecoration(
|
||||
color: tags.contains(name)
|
||||
? str2color2(name, 0xFF)
|
||||
: Theme.of(context).colorScheme.background,
|
||||
borderRadius: BorderRadius.circular(4)),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 6.0),
|
||||
child: IntrinsicWidth(
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: radius,
|
||||
height: radius,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: tags.contains(name)
|
||||
? Colors.white
|
||||
: str2color2(name)),
|
||||
).marginOnly(right: radius / 2),
|
||||
Expanded(
|
||||
child: Text(name,
|
||||
style: TextStyle(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
color: tags.contains(name) ? Colors.white : null)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
void _showMenu(BuildContext context, RelativeRect pos) {
|
||||
final items = [
|
||||
getEntry(translate("Rename"), () {
|
||||
renameDialog(
|
||||
oldName: name,
|
||||
validator: (String? newName) {
|
||||
if (newName == null || newName.isEmpty) {
|
||||
return translate('Can not be empty');
|
||||
}
|
||||
if (newName != name && gFFI.abModel.tags.contains(newName)) {
|
||||
return translate('Already exists');
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSubmit: (String newName) {
|
||||
if (name != newName) {
|
||||
gFFI.abModel.renameTag(name, newName);
|
||||
gFFI.abModel.pushAb();
|
||||
}
|
||||
Future.delayed(Duration.zero, () => Get.back());
|
||||
},
|
||||
onCancel: () {
|
||||
Future.delayed(Duration.zero, () => Get.back());
|
||||
});
|
||||
}),
|
||||
getEntry(translate("Delete"), () {
|
||||
gFFI.abModel.deleteTag(name);
|
||||
gFFI.abModel.pushAb();
|
||||
@@ -458,7 +599,6 @@ MenuEntryButton<String> getEntry(String title, VoidCallback proc) {
|
||||
style: style,
|
||||
),
|
||||
proc: proc,
|
||||
padding: kDesktopMenuPadding,
|
||||
dismissOnClicked: true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AnimatedRotationWidget extends StatefulWidget {
|
||||
final VoidCallback onPressed;
|
||||
final ValueChanged<bool>? onHover;
|
||||
final Widget child;
|
||||
final RxBool? spinning;
|
||||
const AnimatedRotationWidget(
|
||||
{super.key, required this.onPressed, required this.child, this.onHover});
|
||||
{super.key,
|
||||
required this.onPressed,
|
||||
required this.child,
|
||||
this.spinning,
|
||||
this.onHover});
|
||||
|
||||
@override
|
||||
State<AnimatedRotationWidget> createState() => AnimatedRotationWidgetState();
|
||||
@@ -14,14 +20,31 @@ class AnimatedRotationWidget extends StatefulWidget {
|
||||
class AnimatedRotationWidgetState extends State<AnimatedRotationWidget> {
|
||||
double turns = 0.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.spinning?.listen((v) {
|
||||
if (v && mounted) {
|
||||
setState(() {
|
||||
turns += 1;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedRotation(
|
||||
turns: turns,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
onEnd: () {
|
||||
if (widget.spinning?.value == true && mounted) {
|
||||
setState(() => turns += 1.0);
|
||||
}
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() => turns += 1.0);
|
||||
if (mounted) setState(() => turns += 1.0);
|
||||
widget.onPressed();
|
||||
},
|
||||
onHover: widget.onHover,
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:get/get.dart';
|
||||
import '../../common.dart';
|
||||
import '../../models/model.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import 'address_book.dart';
|
||||
|
||||
void clientClose(SessionID sessionId, OverlayDialogManager dialogManager) {
|
||||
msgBox(sessionId, 'info', 'Close', 'Are you sure to close the connection?',
|
||||
@@ -155,8 +156,8 @@ void changeIdDialog() {
|
||||
}).toList(),
|
||||
)).marginOnly(bottom: 8)
|
||||
: SizedBox.shrink(),
|
||||
Offstage(
|
||||
offstage: !isInProgress, child: const LinearProgressIndicator())
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@@ -201,8 +202,8 @@ void changeWhiteList({Function()? callback}) async {
|
||||
const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
Offstage(
|
||||
offstage: !isInProgress, child: const LinearProgressIndicator())
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@@ -947,7 +948,9 @@ showSetOSPassword(
|
||||
Function()? closeCallback,
|
||||
) async {
|
||||
final controller = TextEditingController();
|
||||
osPassword ??= await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ?? '';
|
||||
osPassword ??=
|
||||
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
|
||||
'';
|
||||
var autoLogin =
|
||||
await bind.sessionGetOption(sessionId: sessionId, arg: 'auto-login') !=
|
||||
'';
|
||||
@@ -957,6 +960,7 @@ showSetOSPassword(
|
||||
close();
|
||||
if (closeCallback != null) closeCallback();
|
||||
}
|
||||
|
||||
submit() {
|
||||
var text = controller.text.trim();
|
||||
bind.sessionPeerOption(
|
||||
@@ -1220,7 +1224,8 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
|
||||
qualityInitValue =
|
||||
quality != null && quality.isNotEmpty ? quality[0].toDouble() : 50.0;
|
||||
const qualityMinValue = 10.0;
|
||||
const qualityMaxValue = 100.0;
|
||||
const qualityMoreThresholdValue = 100.0;
|
||||
const qualityMaxValue = 2000.0;
|
||||
if (qualityInitValue < qualityMinValue) {
|
||||
qualityInitValue = qualityMinValue;
|
||||
}
|
||||
@@ -1228,6 +1233,8 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
|
||||
qualityInitValue = qualityMaxValue;
|
||||
}
|
||||
final RxDouble qualitySliderValue = RxDouble(qualityInitValue);
|
||||
final moreQualityInitValue = qualityInitValue > qualityMoreThresholdValue;
|
||||
final RxBool moreQualityChecked = RxBool(moreQualityInitValue);
|
||||
final debouncerQuality = Debouncer<double>(
|
||||
Duration(milliseconds: 1000),
|
||||
onChanged: (double v) {
|
||||
@@ -1242,7 +1249,9 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
|
||||
child: Slider(
|
||||
value: qualitySliderValue.value,
|
||||
min: qualityMinValue,
|
||||
max: qualityMaxValue,
|
||||
max: moreQualityChecked.value
|
||||
? qualityMaxValue
|
||||
: qualityMoreThresholdValue,
|
||||
divisions: 18,
|
||||
onChanged: (double value) {
|
||||
qualitySliderValue.value = value;
|
||||
@@ -1256,11 +1265,32 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
|
||||
style: const TextStyle(fontSize: 15),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: 1,
|
||||
child: Text(
|
||||
translate('Bitrate'),
|
||||
style: const TextStyle(fontSize: 15),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: moreQualityChecked.value,
|
||||
onChanged: (bool? value) {
|
||||
moreQualityChecked.value = value!;
|
||||
if (!value &&
|
||||
qualitySliderValue.value >
|
||||
qualityMoreThresholdValue) {
|
||||
qualitySliderValue.value = qualityMoreThresholdValue;
|
||||
debouncerQuality.value = qualityMoreThresholdValue;
|
||||
}
|
||||
},
|
||||
).marginOnly(right: 5),
|
||||
Expanded(
|
||||
child: Text(translate('More')),
|
||||
)
|
||||
],
|
||||
)),
|
||||
],
|
||||
));
|
||||
// fps
|
||||
@@ -1321,3 +1351,171 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
|
||||
);
|
||||
msgBoxCommon(ffi.dialogManager, 'Custom Image Quality', content, [btnClose]);
|
||||
}
|
||||
|
||||
void deletePeerConfirmDialog(Function onSubmit, String title) async {
|
||||
gFFI.dialogManager.show(
|
||||
(setState, close, context) {
|
||||
submit() async {
|
||||
await onSubmit();
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.delete_rounded,
|
||||
color: Colors.red,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(title, overflow: TextOverflow.ellipsis).paddingOnly(
|
||||
left: 10,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
content: SizedBox.shrink(),
|
||||
actions: [
|
||||
dialogButton(
|
||||
"Cancel",
|
||||
icon: Icon(Icons.close_rounded),
|
||||
onPressed: close,
|
||||
isOutline: true,
|
||||
),
|
||||
dialogButton(
|
||||
"OK",
|
||||
icon: Icon(Icons.done_rounded),
|
||||
onPressed: submit,
|
||||
),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void editAbTagDialog(
|
||||
List<dynamic> currentTags, Function(List<dynamic>) onSubmit) {
|
||||
var isInProgress = false;
|
||||
|
||||
final tags = List.of(gFFI.abModel.tags);
|
||||
var selectedTag = currentTags.obs;
|
||||
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() async {
|
||||
setState(() {
|
||||
isInProgress = true;
|
||||
});
|
||||
await onSubmit(selectedTag);
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Edit Tag")),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Wrap(
|
||||
children: tags
|
||||
.map((e) => AddressBookTag(
|
||||
name: e,
|
||||
tags: selectedTag,
|
||||
onTap: () {
|
||||
if (selectedTag.contains(e)) {
|
||||
selectedTag.remove(e);
|
||||
} else {
|
||||
selectedTag.add(e);
|
||||
}
|
||||
},
|
||||
showActionMenu: false))
|
||||
.toList(growable: false),
|
||||
),
|
||||
),
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
dialogButton("Cancel", onPressed: close, isOutline: true),
|
||||
dialogButton("OK", onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void renameDialog(
|
||||
{required String oldName,
|
||||
FormFieldValidator<String>? validator,
|
||||
required ValueChanged<String> onSubmit,
|
||||
Function? onCancel}) async {
|
||||
RxBool isInProgress = false.obs;
|
||||
var controller = TextEditingController(text: oldName);
|
||||
final formKey = GlobalKey<FormState>();
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() async {
|
||||
String text = controller.text.trim();
|
||||
if (validator != null && formKey.currentState?.validate() == false) {
|
||||
return;
|
||||
}
|
||||
isInProgress.value = true;
|
||||
onSubmit(text);
|
||||
close();
|
||||
isInProgress.value = false;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
onCancel?.call();
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.edit_rounded, color: MyTheme.accent),
|
||||
Text(translate('Rename')).paddingOnly(left: 10),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(labelText: translate('Name')),
|
||||
validator: validator,
|
||||
),
|
||||
),
|
||||
),
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
Obx(() =>
|
||||
isInProgress.value ? const LinearProgressIndicator() : Offstage())
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
dialogButton(
|
||||
"Cancel",
|
||||
icon: Icon(Icons.close_rounded),
|
||||
onPressed: cancel,
|
||||
isOutline: true,
|
||||
),
|
||||
dialogButton(
|
||||
"OK",
|
||||
icon: Icon(Icons.done_rounded),
|
||||
onPressed: submit,
|
||||
),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: cancel,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,13 +113,14 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
|
||||
}
|
||||
|
||||
void onOneFingerStartDebounce(ScaleUpdateDetails d) {
|
||||
final start = (ScaleUpdateDetails d) {
|
||||
start(ScaleUpdateDetails d) {
|
||||
_currentState = GestureState.oneFingerPan;
|
||||
if (onOneFingerPanStart != null) {
|
||||
onOneFingerPanStart!(DragStartDetails(
|
||||
localPosition: d.localFocalPoint, globalPosition: d.focalPoint));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (_currentState != GestureState.none) {
|
||||
_debounceTimer = Timer(Duration(milliseconds: 200), () {
|
||||
start(d);
|
||||
@@ -132,13 +133,14 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
|
||||
}
|
||||
|
||||
void onTwoFingerStartDebounce(ScaleUpdateDetails d) {
|
||||
final start = (ScaleUpdateDetails d) {
|
||||
start(ScaleUpdateDetails d) {
|
||||
_currentState = GestureState.twoFingerScale;
|
||||
if (onTwoFingerScaleStart != null) {
|
||||
onTwoFingerScaleStart!(ScaleStartDetails(
|
||||
localFocalPoint: d.localFocalPoint, focalPoint: d.focalPoint));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (_currentState == GestureState.threeFingerVerticalDrag) {
|
||||
_debounceTimer = Timer(Duration(milliseconds: 200), () {
|
||||
start(d);
|
||||
@@ -182,6 +184,8 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
||||
_TapTracker? _firstTap;
|
||||
_TapTracker? _secondTap;
|
||||
|
||||
PointerDownEvent? _lastPointerDownEvent;
|
||||
|
||||
final Map<int, _TapTracker> _trackers = <int, _TapTracker>{};
|
||||
|
||||
@override
|
||||
@@ -236,6 +240,7 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
||||
gestureSettings: gestureSettings,
|
||||
);
|
||||
_trackers[event.pointer] = tracker;
|
||||
_lastPointerDownEvent = event;
|
||||
tracker.startTrackingPointer(_handleEvent, event.transform);
|
||||
}
|
||||
|
||||
@@ -246,7 +251,11 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
||||
_registerFirstTap(tracker);
|
||||
} else if (_secondTap != null) {
|
||||
if (event.pointer == _secondTap!.pointer) {
|
||||
if (onHoldDragEnd != null) onHoldDragEnd!(DragEndDetails());
|
||||
if (onHoldDragEnd != null) {
|
||||
onHoldDragEnd!(DragEndDetails());
|
||||
_secondTap = null;
|
||||
_isStart = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_reject(tracker);
|
||||
@@ -266,11 +275,12 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
||||
if (!_isStart) {
|
||||
_resolve();
|
||||
}
|
||||
if (onHoldDragUpdate != null)
|
||||
if (onHoldDragUpdate != null) {
|
||||
onHoldDragUpdate!(DragUpdateDetails(
|
||||
globalPosition: event.position,
|
||||
localPosition: event.localPosition,
|
||||
delta: event.delta));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event is PointerCancelEvent) {
|
||||
@@ -300,7 +310,11 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
||||
_secondTap?.entry.resolve(GestureDisposition.accepted);
|
||||
_isStart = true;
|
||||
// TODO start details
|
||||
if (onHoldDragStart != null) onHoldDragStart!(DragStartDetails());
|
||||
if (onHoldDragStart != null) {
|
||||
onHoldDragStart!(DragStartDetails(
|
||||
kind: _lastPointerDownEvent?.kind,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _reject(_TapTracker tracker) {
|
||||
@@ -432,6 +446,8 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
||||
Timer? _firstTapTimer;
|
||||
_TapTracker? _firstTap;
|
||||
|
||||
PointerDownEvent? _lastPointerDownEvent;
|
||||
|
||||
var _isStart = false;
|
||||
|
||||
final Set<int> _upTap = {};
|
||||
@@ -473,6 +489,7 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
||||
} else {
|
||||
// first tap
|
||||
_isStart = true;
|
||||
_lastPointerDownEvent = event;
|
||||
_startFirstTapDownTimer();
|
||||
}
|
||||
_trackTap(event);
|
||||
@@ -498,8 +515,9 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
||||
debugPrint("PointerUpEvent");
|
||||
_upTap.add(tracker.pointer);
|
||||
} else if (event is PointerMoveEvent) {
|
||||
if (!tracker.isWithinGlobalTolerance(event, kDoubleTapTouchSlop))
|
||||
if (!tracker.isWithinGlobalTolerance(event, kDoubleTapTouchSlop)) {
|
||||
_reject(tracker);
|
||||
}
|
||||
} else if (event is PointerCancelEvent) {
|
||||
_reject(tracker);
|
||||
}
|
||||
@@ -587,7 +605,11 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
||||
|
||||
void _resolve() {
|
||||
// TODO tap down details
|
||||
if (onDoubleFinerTap != null) onDoubleFinerTap!(TapDownDetails());
|
||||
if (onDoubleFinerTap != null) {
|
||||
onDoubleFinerTap!(TapDownDetails(
|
||||
kind: _lastPointerDownEvent?.kind,
|
||||
));
|
||||
}
|
||||
_trackers.forEach((key, value) {
|
||||
value.entry.resolve(GestureDisposition.accepted);
|
||||
});
|
||||
@@ -12,25 +12,42 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../common.dart';
|
||||
import './dialog.dart';
|
||||
|
||||
const kOpSvgList = [
|
||||
'github',
|
||||
'google',
|
||||
'apple',
|
||||
'okta',
|
||||
'facebook',
|
||||
'azure',
|
||||
'auth0'
|
||||
];
|
||||
|
||||
class _IconOP extends StatelessWidget {
|
||||
final String icon;
|
||||
final double iconWidth;
|
||||
final String op;
|
||||
final String? icon;
|
||||
final EdgeInsets margin;
|
||||
const _IconOP(
|
||||
{Key? key,
|
||||
required this.op,
|
||||
required this.icon,
|
||||
required this.iconWidth,
|
||||
this.margin = const EdgeInsets.symmetric(horizontal: 4.0)})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final svgFile =
|
||||
kOpSvgList.contains(op.toLowerCase()) ? op.toLowerCase() : 'default';
|
||||
return Container(
|
||||
margin: margin,
|
||||
child: SvgPicture.asset(
|
||||
'assets/$icon.svg',
|
||||
width: iconWidth,
|
||||
),
|
||||
child: icon == null
|
||||
? SvgPicture.asset(
|
||||
'assets/auth-$svgFile.svg',
|
||||
width: 20,
|
||||
)
|
||||
: SvgPicture.string(
|
||||
icon!,
|
||||
width: 20,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +55,7 @@ class _IconOP extends StatelessWidget {
|
||||
class ButtonOP extends StatelessWidget {
|
||||
final String op;
|
||||
final RxString curOP;
|
||||
final double iconWidth;
|
||||
final String? icon;
|
||||
final Color primaryColor;
|
||||
final double height;
|
||||
final Function() onTap;
|
||||
@@ -47,7 +64,7 @@ class ButtonOP extends StatelessWidget {
|
||||
Key? key,
|
||||
required this.op,
|
||||
required this.curOP,
|
||||
required this.iconWidth,
|
||||
required this.icon,
|
||||
required this.primaryColor,
|
||||
required this.height,
|
||||
required this.onTap,
|
||||
@@ -61,7 +78,7 @@ class ButtonOP extends StatelessWidget {
|
||||
width: 200,
|
||||
child: Obx(() => ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: curOP.value.isEmpty || curOP.value == op
|
||||
backgroundColor: curOP.value.isEmpty || curOP.value == op
|
||||
? primaryColor
|
||||
: Colors.grey,
|
||||
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
|
||||
@@ -69,17 +86,21 @@ class ButtonOP extends StatelessWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 30,
|
||||
child: _IconOP(
|
||||
icon: op,
|
||||
iconWidth: iconWidth,
|
||||
margin: EdgeInsets.only(right: 5),
|
||||
)),
|
||||
width: 30,
|
||||
child: _IconOP(
|
||||
op: op,
|
||||
icon: icon,
|
||||
margin: EdgeInsets.only(right: 5),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Center(
|
||||
child: Text('${translate("Continue with")} $op')))),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'${translate("Continue with")} ${op.toLowerCase() == "github" ? "GitHub" : toCapitalized(op)}')),
|
||||
),
|
||||
),
|
||||
],
|
||||
))),
|
||||
),
|
||||
@@ -89,8 +110,8 @@ class ButtonOP extends StatelessWidget {
|
||||
|
||||
class ConfigOP {
|
||||
final String op;
|
||||
final double iconWidth;
|
||||
ConfigOP({required this.op, required this.iconWidth});
|
||||
final String? icon;
|
||||
ConfigOP({required this.op, required this.icon});
|
||||
}
|
||||
|
||||
class WidgetOP extends StatefulWidget {
|
||||
@@ -182,7 +203,7 @@ class _WidgetOPState extends State<WidgetOP> {
|
||||
ButtonOP(
|
||||
op: widget.config.op,
|
||||
curOP: widget.curOP,
|
||||
iconWidth: widget.config.iconWidth,
|
||||
icon: widget.config.icon,
|
||||
primaryColor: str2color(widget.config.op, 0x7f),
|
||||
height: 36,
|
||||
onTap: () async {
|
||||
@@ -333,9 +354,8 @@ class LoginWidgetUserPass extends StatelessWidget {
|
||||
autoFocus: false,
|
||||
errorText: passMsg,
|
||||
),
|
||||
Offstage(
|
||||
offstage: !isInProgress,
|
||||
child: const LinearProgressIndicator()),
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
const SizedBox(height: 12.0),
|
||||
FittedBox(
|
||||
child:
|
||||
@@ -380,7 +400,7 @@ Future<bool?> loginDialog() async {
|
||||
|
||||
final loginOptions = [].obs;
|
||||
Future.delayed(Duration.zero, () async {
|
||||
loginOptions.value = await UserModel.queryLoginOptions();
|
||||
loginOptions.value = await UserModel.queryOidcLoginOptions();
|
||||
});
|
||||
|
||||
final res = await gFFI.dialogManager.show<bool>((setState, close, context) {
|
||||
@@ -460,12 +480,8 @@ Future<bool?> loginDialog() async {
|
||||
}
|
||||
|
||||
thirdAuthWidget() => Obx(() {
|
||||
final oidcOptions = loginOptions
|
||||
.where((opt) => opt.startsWith(kAuthReqTypeOidc))
|
||||
.map((opt) => opt.substring(kAuthReqTypeOidc.length))
|
||||
.toList();
|
||||
return Offstage(
|
||||
offstage: oidcOptions.isEmpty,
|
||||
offstage: loginOptions.isEmpty,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
@@ -480,12 +496,8 @@ Future<bool?> loginDialog() async {
|
||||
height: 8.0,
|
||||
),
|
||||
LoginWidgetOP(
|
||||
ops: [
|
||||
ConfigOP(op: 'GitHub', iconWidth: 20),
|
||||
ConfigOP(op: 'Google', iconWidth: 20),
|
||||
ConfigOP(op: 'Okta', iconWidth: 38),
|
||||
]
|
||||
.where((op) => oidcOptions.contains(op.op.toLowerCase()))
|
||||
ops: loginOptions
|
||||
.map((e) => ConfigOP(op: e['name'], icon: e['icon']))
|
||||
.toList(),
|
||||
curOP: curOP,
|
||||
cbLogin: (Map<String, dynamic> authBody) {
|
||||
@@ -660,9 +672,8 @@ Future<bool?> verificationCodeDialog(UserPayload? user) async {
|
||||
},
|
||||
),
|
||||
*/
|
||||
Offstage(
|
||||
offstage: !isInProgress,
|
||||
child: const LinearProgressIndicator()),
|
||||
// NOT use Offstage to wrap LinearProgressIndicator
|
||||
if (isInProgress) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
onCancel: close,
|
||||
@@ -675,3 +686,22 @@ Future<bool?> verificationCodeDialog(UserPayload? user) async {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void logOutConfirmDialog() {
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() {
|
||||
close();
|
||||
gFFI.userModel.logOut();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
content: Text(translate("logout_tip")),
|
||||
actions: [
|
||||
dialogButton(translate("Cancel"), onPressed: close, isOutline: true),
|
||||
dialogButton(translate("OK"), onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||