Compare commits
2057 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d56717cf5 | ||
|
|
32ef5f47f8 | ||
|
|
32346c23e0 | ||
|
|
b6ebf61d6c | ||
|
|
d79efcedef | ||
|
|
18464ec570 | ||
|
|
ed5487a1fc | ||
|
|
df36580451 | ||
|
|
bd7790c1eb | ||
|
|
67d66c6750 | ||
|
|
1c00d7aa1a | ||
|
|
68cabe596d | ||
|
|
8919ea65e3 | ||
|
|
d4dda94e2a | ||
|
|
ee58b37d1e | ||
|
|
06cb49ec71 | ||
|
|
caca7e5860 | ||
|
|
3ddb4c9799 | ||
|
|
74c24caae9 | ||
|
|
48e8a25f6e | ||
|
|
fd045043a1 | ||
|
|
0e97696b47 | ||
|
|
804764d529 | ||
|
|
98a38754d4 | ||
|
|
837382349e | ||
|
|
d2f119b85e | ||
|
|
89d855d085 | ||
|
|
1bfafaf07c | ||
|
|
cf4f073153 | ||
|
|
aca9ba1a49 | ||
|
|
399e20a14a | ||
|
|
7ca5a0b977 | ||
|
|
74d4505b3d | ||
|
|
df74a38b90 | ||
|
|
e8d02905fe | ||
|
|
123a45149d | ||
|
|
72ec86b58d | ||
|
|
010b17509a | ||
|
|
278d593580 | ||
|
|
f997a1ff52 | ||
|
|
036d10cfbe | ||
|
|
b0c21e927b | ||
|
|
fcece3732c | ||
|
|
c7308dbbc9 | ||
|
|
9ce62dc584 | ||
|
|
0442f7012b | ||
|
|
e7f0f0ff8d | ||
|
|
4fd4b24fa2 | ||
|
|
17d18f1dd8 | ||
|
|
902e166f0c | ||
|
|
1efce51222 | ||
|
|
7da09f6296 | ||
|
|
b8d9c4c378 | ||
|
|
49b0630752 | ||
|
|
91f07b4b03 | ||
|
|
b2f4ba0882 | ||
|
|
1acd7bd19c | ||
|
|
534fc9c40c | ||
|
|
e192f10c56 | ||
|
|
676ee99709 | ||
|
|
6e5622a97a | ||
|
|
d8c9250aab | ||
|
|
986b9fb0e0 | ||
|
|
3c502c6fc2 | ||
|
|
72d59af7b0 | ||
|
|
d3eaa6600d | ||
|
|
96f41fcc02 | ||
|
|
c2b7810c33 | ||
|
|
44d4e13fa7 | ||
|
|
1dd7cd9384 | ||
|
|
8357d4675a | ||
|
|
3a4390e0c7 | ||
|
|
68fa688c96 | ||
|
|
42428261d7 | ||
|
|
e01b1ed04d | ||
|
|
4e5dcd827b | ||
|
|
e8003510ef | ||
|
|
da23e26a70 | ||
|
|
c5b781fb02 | ||
|
|
3bb1c22f49 | ||
|
|
53647fd58e | ||
|
|
0500bf070e | ||
|
|
d70b0cdd4f | ||
|
|
7e09809ad8 | ||
|
|
a7499c2de8 | ||
|
|
4c99b8c70e | ||
|
|
8b6913d31f | ||
|
|
97f0642a8b | ||
|
|
a04dd6ad31 | ||
|
|
9827c76514 | ||
|
|
712bfbae92 | ||
|
|
0152e937ec | ||
|
|
c066dc8c24 | ||
|
|
0b96b3f345 | ||
|
|
b5781933b6 | ||
|
|
d851bf8b69 | ||
|
|
b6d6a4360f | ||
|
|
69b11e8dc6 | ||
|
|
6e78037770 | ||
|
|
bed0375f45 | ||
|
|
42d723f82f | ||
|
|
fb0ce8c974 | ||
|
|
d55770f12b | ||
|
|
125c275623 | ||
|
|
c640f7ed12 | ||
|
|
73662ed7d9 | ||
|
|
a595d83232 | ||
|
|
6743b4f290 | ||
|
|
e8ecb738d0 | ||
|
|
9c20968e05 | ||
|
|
9f80690d8a | ||
|
|
e58a95e7d9 | ||
|
|
d9b96d2f31 | ||
|
|
bbe9017318 | ||
|
|
a31a68ba17 | ||
|
|
9d56e29a09 | ||
|
|
32fca6f9b3 | ||
|
|
72c2de575a | ||
|
|
93d4987dcc | ||
|
|
2a25034039 | ||
|
|
5ba1c2587d | ||
|
|
1b0a3e610e | ||
|
|
2820f3f798 | ||
|
|
09f3850250 | ||
|
|
35832f8f7f | ||
|
|
7466d8cb3a | ||
|
|
ea3786457b | ||
|
|
01322146c0 | ||
|
|
26adc557bf | ||
|
|
36e52d8165 | ||
|
|
4c0211fa23 | ||
|
|
a3b4dcf762 | ||
|
|
5537c525ca | ||
|
|
3746fd88b5 | ||
|
|
e373144350 | ||
|
|
3be4bfc821 | ||
|
|
2c1595d0d5 | ||
|
|
f08933f93c | ||
|
|
51813b7d7e | ||
|
|
4e30418f79 | ||
|
|
0af370d736 | ||
|
|
ac04a032ad | ||
|
|
f6223a6f71 | ||
|
|
937cea5a01 | ||
|
|
846522037f | ||
|
|
b5a88d00af | ||
|
|
7391271107 | ||
|
|
991694aca5 | ||
|
|
29b13d19d6 | ||
|
|
b0ff74c799 | ||
|
|
75c60660e7 | ||
|
|
eacc840c54 | ||
|
|
6d09c0adcf | ||
|
|
fe1cf1105a | ||
|
|
9454334ddd | ||
|
|
cc482c589c | ||
|
|
b387bc1038 | ||
|
|
890b735985 | ||
|
|
eb81e00d20 | ||
|
|
c619bfc05c | ||
|
|
b5935eb4c5 | ||
|
|
73b3023c2d | ||
|
|
4cf709fc26 | ||
|
|
b471b934f2 | ||
|
|
abbd4c8934 | ||
|
|
ed8c852d35 | ||
|
|
c3598b3513 | ||
|
|
b5f6a9c91a | ||
|
|
d18810b612 | ||
|
|
3c17d713b3 | ||
|
|
d46b2d52ce | ||
|
|
e07d0b3b25 | ||
|
|
2ff3b24b33 | ||
|
|
115fb05c85 | ||
|
|
1e7e72883d | ||
|
|
1edb7639f6 | ||
|
|
33c5ceecec | ||
|
|
a8a7f306fe | ||
|
|
9888e51b93 | ||
|
|
c3124314ef | ||
|
|
975cd183bc | ||
|
|
aa9da0b0c8 | ||
|
|
d83b106607 | ||
|
|
1a0a6cedc7 | ||
|
|
d4e1a83a5a | ||
|
|
03e93d546a | ||
|
|
a1b957b0f7 | ||
|
|
eeffb11841 | ||
|
|
860dc7dbc2 | ||
|
|
220f267976 | ||
|
|
b5bd6e008b | ||
|
|
9d20bc6441 | ||
|
|
1c36734092 | ||
|
|
9102b6e6b8 | ||
|
|
cd78fa9762 | ||
|
|
407e2d4b7b | ||
|
|
62d6ee46c4 | ||
|
|
f15bf8166f | ||
|
|
7ce0b225ef | ||
|
|
f853b29fd9 | ||
|
|
f9cc8de93e | ||
|
|
a924a876ae | ||
|
|
1f15d2c66e | ||
|
|
ffd8354208 | ||
|
|
b3b1f4664c | ||
|
|
03410ded9a | ||
|
|
09c9671376 | ||
|
|
736b3b93e9 | ||
|
|
4a71ca6b81 | ||
|
|
a828f9b1f9 | ||
|
|
7ce5f8e8b6 | ||
|
|
08b7e036b4 | ||
|
|
b1722a085e | ||
|
|
9d985585b9 | ||
|
|
de057b7234 | ||
|
|
04ec49e18e | ||
|
|
34c7c25908 | ||
|
|
f74374e759 | ||
|
|
cce74f5631 | ||
|
|
003b9e48e1 | ||
|
|
28bf73cd5a | ||
|
|
511b982dce | ||
|
|
dcd176f95c | ||
|
|
d394aa8a15 | ||
|
|
c8b35d5ce1 | ||
|
|
6cd107c3e3 | ||
|
|
a884e32816 | ||
|
|
45d2d3cbb5 | ||
|
|
382f75d249 | ||
|
|
e90010f0c0 | ||
|
|
d6aaed1d82 | ||
|
|
5082ed3b9e | ||
|
|
a858e07db0 | ||
|
|
df8f785731 | ||
|
|
332674a4a1 | ||
|
|
a686849bb6 | ||
|
|
54d041701c | ||
|
|
496eec17a1 | ||
|
|
25eb67c582 | ||
|
|
a26fab3cce | ||
|
|
7cb67cf8fb | ||
|
|
96ec1e937f | ||
|
|
b6616ed2cc | ||
|
|
7e263af75f | ||
|
|
b4c51f3d41 | ||
|
|
1dfbaa1e02 | ||
|
|
bd717349a7 | ||
|
|
99d7752e25 | ||
|
|
22e58d7623 | ||
|
|
30ad142868 | ||
|
|
e084ff4f7b | ||
|
|
3bbec4081a | ||
|
|
45137d5506 | ||
|
|
e9d9a656ab | ||
|
|
ade458b820 | ||
|
|
b022dcbb70 | ||
|
|
b403a7a25d | ||
|
|
a6632632fa | ||
|
|
b863ea51ad | ||
|
|
796b66b057 | ||
|
|
2626dcbc5f | ||
|
|
105a758914 | ||
|
|
98cce186c7 | ||
|
|
474e13f8b9 | ||
|
|
09f87238dc | ||
|
|
2b3f87d6f2 | ||
|
|
9d3c823603 | ||
|
|
7e00d70f4d | ||
|
|
0828f747e3 | ||
|
|
d7de0c2578 | ||
|
|
4dfc82f684 | ||
|
|
92748de7d4 | ||
|
|
0e7e27f99d | ||
|
|
23147f2328 | ||
|
|
3811f41076 | ||
|
|
43a0a4f8e0 | ||
|
|
66d1af63b0 | ||
|
|
bc68f400f6 | ||
|
|
67ee3a5a67 | ||
|
|
b407893db5 | ||
|
|
1b4a41b522 | ||
|
|
ac7f8a6447 | ||
|
|
da57fcb641 | ||
|
|
f11c332cb4 | ||
|
|
3b4006b821 | ||
|
|
4c62d8c1b2 | ||
|
|
4f47d4482b | ||
|
|
ad062486ff | ||
|
|
33c8bdfabf | ||
|
|
0365c94407 | ||
|
|
c81c4f9114 | ||
|
|
d920953df1 | ||
|
|
f02a2e44d8 | ||
|
|
fb1aa9c028 | ||
|
|
d4a1d4cd7e | ||
|
|
8a6d9a1496 | ||
|
|
a8eefbc9f0 | ||
|
|
75521fe363 | ||
|
|
c75778943f | ||
|
|
0e6fa37ae4 | ||
|
|
819eea9456 | ||
|
|
25eb8dc9b0 | ||
|
|
40067f5aa2 | ||
|
|
1ffc10e44f | ||
|
|
5d5547ffef | ||
|
|
e83c28bf54 | ||
|
|
a3c0911529 | ||
|
|
ae23f0de03 | ||
|
|
edb5529df3 | ||
|
|
4d3fb77786 | ||
|
|
24ac7c1626 | ||
|
|
9b2ec62be9 | ||
|
|
4252b5e273 | ||
|
|
4e8cbe3db1 | ||
|
|
bdf8bbe26f | ||
|
|
990c05fc3d | ||
|
|
7bb4e22a77 | ||
|
|
736503df1b | ||
|
|
414455a8fb | ||
|
|
bc0ab88e74 | ||
|
|
01ec539065 | ||
|
|
b9792fc17d | ||
|
|
c656c3c087 | ||
|
|
a6c1d2d486 | ||
|
|
44bce59777 | ||
|
|
9b5e5aa474 | ||
|
|
a5d02998ad | ||
|
|
1d4c129e9c | ||
|
|
e9a6ca8ebc | ||
|
|
28340c80dd | ||
|
|
05f6fde467 | ||
|
|
56d353cb64 | ||
|
|
260d0cdc67 | ||
|
|
cdd92303b8 | ||
|
|
0dba37f4f7 | ||
|
|
7f3775a061 | ||
|
|
a7a10f4eaa | ||
|
|
5166083406 | ||
|
|
5c4d95ac0f | ||
|
|
71c4d74759 | ||
|
|
725e8221a5 | ||
|
|
92ae41cc13 | ||
|
|
333b9130fe | ||
|
|
60ae903cf3 | ||
|
|
24ea55b010 | ||
|
|
8231d07706 | ||
|
|
98df2b111e | ||
|
|
d8875f381b | ||
|
|
6e3d16173a | ||
|
|
a88b189664 | ||
|
|
48da00eb66 | ||
|
|
5322332c5d | ||
|
|
c92cfbb20a | ||
|
|
f673647072 | ||
|
|
7ea5a9bba3 | ||
|
|
aa002c5d60 | ||
|
|
64020758d9 | ||
|
|
a4f357fd80 | ||
|
|
4c6fdfd76a | ||
|
|
c972452310 | ||
|
|
6ba6a16836 | ||
|
|
c63f1dfc53 | ||
|
|
ac79c45529 | ||
|
|
7f58737f1f | ||
|
|
ead8a48436 | ||
|
|
178d33155f | ||
|
|
07ab8e508c | ||
|
|
ea1d4adfa6 | ||
|
|
f34a8ef0e5 | ||
|
|
0df4b39bcc | ||
|
|
07eca00bd5 | ||
|
|
cf8386aa50 | ||
|
|
44de6a5549 | ||
|
|
a41a9bcbf7 | ||
|
|
a679fae9c0 | ||
|
|
0f906f3937 | ||
|
|
c907daa741 | ||
|
|
df579de147 | ||
|
|
e884bdbbc4 | ||
|
|
84fc70e9a9 | ||
|
|
4fc5d3f03b | ||
|
|
9402516acd | ||
|
|
65f7541ec7 | ||
|
|
22da14e3f7 | ||
|
|
fddad09167 | ||
|
|
f36f065508 | ||
|
|
0c294eefae | ||
|
|
5a0333ddaf | ||
|
|
e0b9a9a82f | ||
|
|
ab07eb6f4a | ||
|
|
bddd800769 | ||
|
|
5533ebf86a | ||
|
|
2397fdc495 | ||
|
|
129548764e | ||
|
|
ed257e39d0 | ||
|
|
33eaf2e05c | ||
|
|
41d99d5108 | ||
|
|
edefa5f786 | ||
|
|
d7b47b49d2 | ||
|
|
74af7ef8b2 | ||
|
|
1cfc9b6139 | ||
|
|
db6bf547a9 | ||
|
|
2b20714f50 | ||
|
|
cfa72ad7d1 | ||
|
|
2e11a8b458 | ||
|
|
58fe95d6fd | ||
|
|
de65c8b2cf | ||
|
|
57510980ed | ||
|
|
26a7f9dd46 | ||
|
|
7fb2464d84 | ||
|
|
9e7137ce09 | ||
|
|
80747fc306 | ||
|
|
0d75f71d16 | ||
|
|
46c2288f50 | ||
|
|
d76c9ad1db | ||
|
|
3faa18c020 | ||
|
|
d699496a52 | ||
|
|
19bf5f1a23 | ||
|
|
080b56a0cb | ||
|
|
82d9b033f2 | ||
|
|
bf6e465970 | ||
|
|
3ef9824d8e | ||
|
|
4b0e88ce46 | ||
|
|
0c32a889a9 | ||
|
|
6186b41e3f | ||
|
|
6e44a91d0b | ||
|
|
810b980e6b | ||
|
|
22356940d9 | ||
|
|
cc30f7aa02 | ||
|
|
6e689400b6 | ||
|
|
50fbf8833b | ||
|
|
d7137990b9 | ||
|
|
8ecc107c06 | ||
|
|
1fa3837bb0 | ||
|
|
5aec5b084a | ||
|
|
b77add97db | ||
|
|
b306d808fb | ||
|
|
1729c3f76d | ||
|
|
2eb591391e | ||
|
|
075194fea8 | ||
|
|
28b376d2d2 | ||
|
|
4f3de4cf54 | ||
|
|
85f387bfb9 | ||
|
|
81aec8402b | ||
|
|
d407dfed0a | ||
|
|
dcd4d0886e | ||
|
|
9ad240951e | ||
|
|
e86d4657da | ||
|
|
d36e33a7cf | ||
|
|
376bcefc14 | ||
|
|
c0c110fe7e | ||
|
|
3dc6e576df | ||
|
|
49f717fcf8 | ||
|
|
00152e0db4 | ||
|
|
1964203848 | ||
|
|
495444abd0 | ||
|
|
09ec0b6325 | ||
|
|
cad0f15a83 | ||
|
|
b087dcd328 | ||
|
|
8dff263a0c | ||
|
|
d546b23bd8 | ||
|
|
bb9400745e | ||
|
|
30f84e78e1 | ||
|
|
30af020ba8 | ||
|
|
ef27cd6c5c | ||
|
|
770289cd67 | ||
|
|
25b5c96648 | ||
|
|
85cafda168 | ||
|
|
96e1b5b0f6 | ||
|
|
dd90e84f6a | ||
|
|
05969c2f99 | ||
|
|
05ef1c3924 | ||
|
|
8018920a64 | ||
|
|
dcb7e389eb | ||
|
|
a15cd62fd4 | ||
|
|
1c3a2e475d | ||
|
|
83c45d772f | ||
|
|
96c8d4de6a | ||
|
|
9558974080 | ||
|
|
285e298a8b | ||
|
|
57b17b1798 | ||
|
|
7e13642098 | ||
|
|
26b5f53b12 | ||
|
|
896b321cdc | ||
|
|
4115a5936c | ||
|
|
0e0cf7df09 | ||
|
|
0c232be0c4 | ||
|
|
67bc26ed57 | ||
|
|
f421a14659 | ||
|
|
81b74cf46c | ||
|
|
b1a3ce323b | ||
|
|
1f58826444 | ||
|
|
2ea853b1e6 | ||
|
|
a2e1647faa | ||
|
|
4e060203ad | ||
|
|
0540e2cf6c | ||
|
|
21e4679b6c | ||
|
|
8b9728b40b | ||
|
|
e0739709e7 | ||
|
|
41da6d552f | ||
|
|
ecb70b43df | ||
|
|
b2290f5b4c | ||
|
|
c6f415e9df | ||
|
|
3f7d622512 | ||
|
|
794d3ffcac | ||
|
|
ee2f87ef32 | ||
|
|
87da2a165d | ||
|
|
130deb8e22 | ||
|
|
b65d65cb12 | ||
|
|
3caa5776c8 | ||
|
|
6cbbb6498f | ||
|
|
fb12ee7f2a | ||
|
|
48842b6f2a | ||
|
|
fc90526258 | ||
|
|
efd1f24ab2 | ||
|
|
0808672b6e | ||
|
|
fe0de47805 | ||
|
|
ccf5b0ef53 | ||
|
|
218f4872b8 | ||
|
|
077569dd5d | ||
|
|
a3f79065c5 | ||
|
|
fbfcf862cb | ||
|
|
7307b84dad | ||
|
|
6b15a9b6d2 | ||
|
|
e3420fd563 | ||
|
|
31120f51c9 | ||
|
|
3d279ec127 | ||
|
|
48cd76b938 | ||
|
|
8e5fbc8480 | ||
|
|
cdea968c24 | ||
|
|
a6aabed6a1 | ||
|
|
cde235896f | ||
|
|
ca48aaf5ee | ||
|
|
8a705a6a9a | ||
|
|
b3adbc1110 | ||
|
|
2bbc13ccf6 | ||
|
|
411384f0e7 | ||
|
|
a9b0bc0409 | ||
|
|
228582296c | ||
|
|
d67108cd20 | ||
|
|
175f185cb1 | ||
|
|
56f27ec356 | ||
|
|
5253d67e04 | ||
|
|
a314f59db9 | ||
|
|
da4e268e63 | ||
|
|
c186378d43 | ||
|
|
482bb5f64f | ||
|
|
3c1492e9bc | ||
|
|
be301b825f | ||
|
|
fc875f7ad6 | ||
|
|
f644053811 | ||
|
|
c0e5e78d2b | ||
|
|
d103872c61 | ||
|
|
d47104f3f3 | ||
|
|
d4288f89d3 | ||
|
|
7060257051 | ||
|
|
866ec097c0 | ||
|
|
dcbe2805e6 | ||
|
|
262814391a | ||
|
|
b32cf403e6 | ||
|
|
921ee34779 | ||
|
|
75a871c437 | ||
|
|
b5a47efe8e | ||
|
|
8ff24d876c | ||
|
|
dd44bb2a0c | ||
|
|
f3686b23c7 | ||
|
|
fccdc8ca1f | ||
|
|
fc149666d9 | ||
|
|
4292838e80 | ||
|
|
befac94473 | ||
|
|
c0128d86f4 | ||
|
|
794636e208 | ||
|
|
eff6ac254f | ||
|
|
fa575be289 | ||
|
|
060ad68570 | ||
|
|
1620394736 | ||
|
|
1e6e91e4bd | ||
|
|
b0cbe2ae70 | ||
|
|
1391202985 | ||
|
|
d9ad24f563 | ||
|
|
61279752e2 | ||
|
|
1794b65182 | ||
|
|
6bb5629bb4 | ||
|
|
0f3db29e75 | ||
|
|
c6cdf77a68 | ||
|
|
48682faf71 | ||
|
|
49d396538c | ||
|
|
30802820b0 | ||
|
|
7fca0ba588 | ||
|
|
50d080d098 | ||
|
|
96792bec78 | ||
|
|
e6953c8883 | ||
|
|
1d9b1781d4 | ||
|
|
6720bb9f6b | ||
|
|
2217e5303d | ||
|
|
c8392a714c | ||
|
|
749a1d2da2 | ||
|
|
2920e33d71 | ||
|
|
1bc11a207a | ||
|
|
ddbd4e79a2 | ||
|
|
49c107bb5f | ||
|
|
1b99d28c9b | ||
|
|
7b8e983412 | ||
|
|
f1373234dd | ||
|
|
b511a52e09 | ||
|
|
4c8c2aa323 | ||
|
|
a28c9f8f36 | ||
|
|
9ff1dfe019 | ||
|
|
3ae52dacfc | ||
|
|
aa6f879504 | ||
|
|
1dde5c5689 | ||
|
|
913b422d74 | ||
|
|
2459bcd206 | ||
|
|
cce1ce0ee0 | ||
|
|
8518513aff | ||
|
|
ce5e28c543 | ||
|
|
9b7a8203f6 | ||
|
|
fd8f2422ea | ||
|
|
09325fadaf | ||
|
|
d7d7be9366 | ||
|
|
25afdda2b2 | ||
|
|
c690d5e940 | ||
|
|
243a8b60b1 | ||
|
|
7b317619ac | ||
|
|
c987bed965 | ||
|
|
ada4bafb94 | ||
|
|
27f5d0fd54 | ||
|
|
914da2b86f | ||
|
|
582db9d542 | ||
|
|
9a1fd1aa4f | ||
|
|
58ddac63d2 | ||
|
|
a8eff641b2 | ||
|
|
d723c10a3b | ||
|
|
bf5abdb520 | ||
|
|
0f44de7dc3 | ||
|
|
4f1a4dc6a5 | ||
|
|
8c108065eb | ||
|
|
5fdcc748e1 | ||
|
|
bf03156dd9 | ||
|
|
964c2ed2b5 | ||
|
|
e942c80afb | ||
|
|
d7dcb5feab | ||
|
|
39d41486d6 | ||
|
|
b85526ce54 | ||
|
|
2a0c081380 | ||
|
|
1db4236f23 | ||
|
|
6749595afe | ||
|
|
e65c43a292 | ||
|
|
00b13bf918 | ||
|
|
f7f3bc8bee | ||
|
|
51c603a3a6 | ||
|
|
5fb026b8d5 | ||
|
|
f7530b16b8 | ||
|
|
db47209362 | ||
|
|
f375cbd871 | ||
|
|
0474c8fb03 | ||
|
|
c00d23846a | ||
|
|
a3d5ea8fb8 | ||
|
|
7525a6ed6a | ||
|
|
dd93416cf7 | ||
|
|
73d429d064 | ||
|
|
4bf3764b5d | ||
|
|
236687ae53 | ||
|
|
0d708f64b9 | ||
|
|
222c9de19f | ||
|
|
72fc34cd40 | ||
|
|
3f7244f23f | ||
|
|
dc24868800 | ||
|
|
1f557888f5 | ||
|
|
16db977fd8 | ||
|
|
a19d4d6686 | ||
|
|
633076ddd4 | ||
|
|
5581248a1e | ||
|
|
a4393b8f90 | ||
|
|
406d8469d8 | ||
|
|
0cf4711515 | ||
|
|
a2ba50c4ff | ||
|
|
c97cc15c0e | ||
|
|
750f1a1884 | ||
|
|
2cf83b41cc | ||
|
|
1f16b5236b | ||
|
|
dd4b5349cb | ||
|
|
46b4e21e8c | ||
|
|
3899e4e12e | ||
|
|
f016281e30 | ||
|
|
1d755c705b | ||
|
|
a0d79dd26d | ||
|
|
e6734af64e | ||
|
|
0d8e3dc24f | ||
|
|
0e44aa1ada | ||
|
|
9f40a0b490 | ||
|
|
23430bee97 | ||
|
|
04691a3b6c | ||
|
|
db0f65eedd | ||
|
|
2118b6dd7d | ||
|
|
71d7398ae7 | ||
|
|
2e16a2be56 | ||
|
|
ed24f432c3 | ||
|
|
669e8d5f8e | ||
|
|
016f4abb32 | ||
|
|
b1a946ec20 | ||
|
|
2576b46f34 | ||
|
|
a42df9a27b | ||
|
|
48102e9c53 | ||
|
|
5770aeee26 | ||
|
|
cb102a5a61 | ||
|
|
28f01784c1 | ||
|
|
29eefbcc25 | ||
|
|
8679e55f6a | ||
|
|
846db4e689 | ||
|
|
68afb89b99 | ||
|
|
804f035a87 | ||
|
|
267342e7e6 | ||
|
|
9e3633f1e4 | ||
|
|
06b3894249 | ||
|
|
d39129887b | ||
|
|
e5379bb073 | ||
|
|
c8dded1108 | ||
|
|
44e6b7dbb0 | ||
|
|
80857c22c9 | ||
|
|
6548f9f0ed | ||
|
|
58fd8780e5 | ||
|
|
0cccbc438b | ||
|
|
558e7cb5ac | ||
|
|
286181ca04 | ||
|
|
ce0fc14a8a | ||
|
|
ebfbc8ce61 | ||
|
|
fdb038c7c9 | ||
|
|
467e6dfd16 | ||
|
|
8c40c28fe0 | ||
|
|
9e25049fe8 | ||
|
|
e170153090 | ||
|
|
99e8753629 | ||
|
|
d5b0829065 | ||
|
|
2c8a60e0ea | ||
|
|
352de75fdd | ||
|
|
f7b35defc9 | ||
|
|
e471c01269 | ||
|
|
5dfaa10709 | ||
|
|
7506f94a53 | ||
|
|
a2d08fa40d | ||
|
|
159c883bf3 | ||
|
|
396d7680d3 | ||
|
|
7e93a5d3cf | ||
|
|
955c55b6cc | ||
|
|
b2b30b0cf5 | ||
|
|
6352b3a594 | ||
|
|
5be684d2e5 | ||
|
|
8dda17d546 | ||
|
|
0f5aaac1f5 | ||
|
|
35fa75f9c9 | ||
|
|
19d43b3f62 | ||
|
|
2b4a72897e | ||
|
|
cdc31b7fc7 | ||
|
|
f4ef1455c4 | ||
|
|
fe94512dd1 | ||
|
|
ae25542ce9 | ||
|
|
6c030a5230 | ||
|
|
a145d6ebcc | ||
|
|
14676e9618 | ||
|
|
72e8476ded | ||
|
|
5888b051d9 | ||
|
|
215cf73072 | ||
|
|
7f7d4a77b6 | ||
|
|
7e3a0c4ded | ||
|
|
89150317e1 | ||
|
|
f47faa548b | ||
|
|
36ed8f3f73 | ||
|
|
ca1ca21cf8 | ||
|
|
c7df539b31 | ||
|
|
e873188775 | ||
|
|
6953efc2d8 | ||
|
|
3e78aacc7e | ||
|
|
20b4ce3213 | ||
|
|
4b581c385c | ||
|
|
bdf6f5c3b9 | ||
|
|
6d0953dca4 | ||
|
|
fc0fc5ea10 | ||
|
|
f7f2d84e1f | ||
|
|
57acadd52a | ||
|
|
26cebd2aeb | ||
|
|
9a652e789d | ||
|
|
f6509e3fd6 | ||
|
|
445fe6e714 | ||
|
|
dc8a70bb26 | ||
|
|
adf9b82d6b | ||
|
|
be212b5186 | ||
|
|
59ba461d83 | ||
|
|
004c2e069c | ||
|
|
c168b7e979 | ||
|
|
79411430a5 | ||
|
|
853d655a92 | ||
|
|
2d5fa9ebbf | ||
|
|
b2deab08ab | ||
|
|
8452a17d79 | ||
|
|
19851c8a47 | ||
|
|
6b8ec6ae16 | ||
|
|
d648e67eaf | ||
|
|
ebb14af488 | ||
|
|
80afa98d66 | ||
|
|
2797a28c0d | ||
|
|
03c8d94024 | ||
|
|
c061eddf2a | ||
|
|
2e146190e1 | ||
|
|
fc110c4988 | ||
|
|
6003003228 | ||
|
|
70e5bee519 | ||
|
|
4062d1920c | ||
|
|
50b81c2356 | ||
|
|
00fe3a76c8 | ||
|
|
d11a3b9683 | ||
|
|
7934fa24a2 | ||
|
|
f0d9dee6ce | ||
|
|
3a82bddcd3 | ||
|
|
ebe044aee8 | ||
|
|
674305ce29 | ||
|
|
b9a5c6ff31 | ||
|
|
bcb0a7822a | ||
|
|
93aac0bc99 | ||
|
|
7fe58afa9c | ||
|
|
9d0f8d9886 | ||
|
|
aa7d0471db | ||
|
|
6cd9227e8d | ||
|
|
213ef58959 | ||
|
|
2fa1124752 | ||
|
|
d00a0d6c75 | ||
|
|
2e225eb84f | ||
|
|
3c57ee89c4 | ||
|
|
b6f870ac5f | ||
|
|
570ce7d28d | ||
|
|
3958090e0f | ||
|
|
99ed1b729e | ||
|
|
d16db77b52 | ||
|
|
56c176add4 | ||
|
|
42a856c24a | ||
|
|
b662090d64 | ||
|
|
29e50a5f91 | ||
|
|
7885e07eed | ||
|
|
65fd682f2a | ||
|
|
cdecbb0857 | ||
|
|
68ee781f26 | ||
|
|
0f307e7ca2 | ||
|
|
7ac49287df | ||
|
|
83faf6025b | ||
|
|
4faf5e6d3e | ||
|
|
d300596ac1 | ||
|
|
a30dc5988e | ||
|
|
e43a0da9a6 | ||
|
|
83b74c0930 | ||
|
|
0d2a39267f | ||
|
|
f87f380bb0 | ||
|
|
ab28acd709 | ||
|
|
04b53f8e1e | ||
|
|
eb0e5c2de3 | ||
|
|
8cb9b910a6 | ||
|
|
bdac79c91b | ||
|
|
88081fc3c4 | ||
|
|
6be451e9f3 | ||
|
|
64ed25879c | ||
|
|
d66e087d94 | ||
|
|
b7b0a44c52 | ||
|
|
44cba7adf7 | ||
|
|
5a8a64d284 | ||
|
|
eac6835982 | ||
|
|
7992ca4c85 | ||
|
|
ead200ea5d | ||
|
|
e146c2606f | ||
|
|
db158e1ffe | ||
|
|
72ef3c3394 | ||
|
|
e17378c6b3 | ||
|
|
0e05f5305c | ||
|
|
58f43da23e | ||
|
|
4a9e7f29da | ||
|
|
1589209567 | ||
|
|
5c6017b0a9 | ||
|
|
4246fe5b92 | ||
|
|
c441d2f03f | ||
|
|
6c21529594 | ||
|
|
6fc4253d46 | ||
|
|
7a2590d1f9 | ||
|
|
4cbbb5b64f | ||
|
|
f11104fcb5 | ||
|
|
19e8ca6c06 | ||
|
|
13005e8242 | ||
|
|
d0dde6e572 | ||
|
|
5e103a5ccb | ||
|
|
0c4e6f0a8c | ||
|
|
03a89a5cdd | ||
|
|
e22d13be1f | ||
|
|
ef9c4d96b7 | ||
|
|
bb7300a055 | ||
|
|
2d456fd1fc | ||
|
|
97108e788f | ||
|
|
b8f7259fbd | ||
|
|
2de1c62daf | ||
|
|
f5d2eff8d3 | ||
|
|
dbcf1fdb6f | ||
|
|
bd81e4d0fb | ||
|
|
80786f692c | ||
|
|
177edfea3e | ||
|
|
b4b08db778 | ||
|
|
8abf2f768c | ||
|
|
8b14cd5aea | ||
|
|
84a21d72b9 | ||
|
|
fa8e0ed27b | ||
|
|
b6e403a3fb | ||
|
|
3d368f9aca | ||
|
|
414ac950e0 | ||
|
|
34fa82f72c | ||
|
|
4d5fdc4725 | ||
|
|
1c4f28e708 | ||
|
|
7bf555ce4c | ||
|
|
bb388628a7 | ||
|
|
a2920578a1 | ||
|
|
b41a73f08d | ||
|
|
c6ace470e3 | ||
|
|
cdbe79d3c1 | ||
|
|
493ec07ff2 | ||
|
|
ec15412755 | ||
|
|
191b6d5b4e | ||
|
|
8718152dba | ||
|
|
c585db7516 | ||
|
|
515c91a407 | ||
|
|
b615029304 | ||
|
|
3b0f4b1f82 | ||
|
|
4a2bf7a0c3 | ||
|
|
79212f8ef7 | ||
|
|
c57a596156 | ||
|
|
948db1451f | ||
|
|
06aa18bfab | ||
|
|
f076afb6e1 | ||
|
|
582402f4d9 | ||
|
|
0e04ff506b | ||
|
|
e9f757dccb | ||
|
|
f02d858646 | ||
|
|
3727cd401c | ||
|
|
f0c9deca4b | ||
|
|
f41a8bc355 | ||
|
|
3100930136 | ||
|
|
9abafafcdd | ||
|
|
0d127dff3b | ||
|
|
83dbf88ffb | ||
|
|
3a6f56ebbc | ||
|
|
3e8c5d3b79 | ||
|
|
2aaca0c54a | ||
|
|
c6d587f0c7 | ||
|
|
c85682de8d | ||
|
|
9c12c3ee4e | ||
|
|
2c432dbf4d | ||
|
|
0c8643837f | ||
|
|
3fd97f7e60 | ||
|
|
5064696480 | ||
|
|
6f0fbd1088 | ||
|
|
b535722421 | ||
|
|
60e96b637d | ||
|
|
7f29c7a601 | ||
|
|
060dfedb74 | ||
|
|
2907ed6029 | ||
|
|
5649fcc9ca | ||
|
|
85ddfc0739 | ||
|
|
7c98bfd363 | ||
|
|
c23f377039 | ||
|
|
af89fb52f1 | ||
|
|
98f56fd506 | ||
|
|
88ea1ea85b | ||
|
|
2a1e33f95c | ||
|
|
2fe55e2b55 | ||
|
|
d6f5887b1d | ||
|
|
dce045461a | ||
|
|
4ab0324bc9 | ||
|
|
b2bb69fe42 | ||
|
|
ad96f9aacd | ||
|
|
9847fc5c77 | ||
|
|
3f3bca753c | ||
|
|
c223d6a87d | ||
|
|
14a428467c | ||
|
|
efc84e53ec | ||
|
|
f9ee0189f0 | ||
|
|
d90580943f | ||
|
|
f6484b4e2b | ||
|
|
0b5f48b926 | ||
|
|
f2f649319d | ||
|
|
35eaa94228 | ||
|
|
e09a050d41 | ||
|
|
38182ba020 | ||
|
|
7960b2ca10 | ||
|
|
722c789448 | ||
|
|
faa4c36956 | ||
|
|
d3a33d786d | ||
|
|
1a2d60dbfc | ||
|
|
2aa5e685b8 | ||
|
|
512c7df37d | ||
|
|
57fddf1c85 | ||
|
|
afe4206782 | ||
|
|
02bc5e3111 | ||
|
|
5a51284550 | ||
|
|
2d995826ad | ||
|
|
92f3bf2999 | ||
|
|
bfe282c2db | ||
|
|
2d0b013af3 | ||
|
|
3df938ed61 | ||
|
|
d4b6cab742 | ||
|
|
8d327af0ac | ||
|
|
f135fbee26 | ||
|
|
d65977bd59 | ||
|
|
1e0242ede9 | ||
|
|
839d3365f8 | ||
|
|
182ee8f233 | ||
|
|
24eb6f8c38 | ||
|
|
13bade262f | ||
|
|
d2ff675fbc | ||
|
|
1905a81f9a | ||
|
|
e2382a1465 | ||
|
|
ec00cd2ae0 | ||
|
|
e0fad4eaa5 | ||
|
|
882b39b067 | ||
|
|
d15a641d88 | ||
|
|
90ac8b7b0b | ||
|
|
d64afdcff1 | ||
|
|
eb58a39f57 | ||
|
|
d12352d568 | ||
|
|
217a9808b2 | ||
|
|
1b08adb178 | ||
|
|
f113fda6d4 | ||
|
|
5a6a773583 | ||
|
|
627d21a00a | ||
|
|
44e13c84bc | ||
|
|
b96067cf2e | ||
|
|
b2fe5cce5e | ||
|
|
55775adba6 | ||
|
|
0500f56163 | ||
|
|
52e5d519ab | ||
|
|
bdfbb97bf8 | ||
|
|
cff117cb40 | ||
|
|
cf71adc7e1 | ||
|
|
0582f2a168 | ||
|
|
2721af3052 | ||
|
|
f9950639e8 | ||
|
|
8f8c9ddc25 | ||
|
|
58596ad1ab | ||
|
|
b17ea991a3 | ||
|
|
45d70f73bd | ||
|
|
7a6e483171 | ||
|
|
1792dd8d2c | ||
|
|
a4ea4b138f | ||
|
|
e2c6aedddd | ||
|
|
b91a03b602 | ||
|
|
27716f077e | ||
|
|
eaa054e599 | ||
|
|
e57d07f7d6 | ||
|
|
895831f46f | ||
|
|
6b16d7ee8a | ||
|
|
45dbea57f1 | ||
|
|
6ea0dbc70f | ||
|
|
30a5041799 | ||
|
|
35083724f6 | ||
|
|
959d5dd9c2 | ||
|
|
a24a261c36 | ||
|
|
75feb90b19 | ||
|
|
fd3cb1b0eb | ||
|
|
1902134f03 | ||
|
|
cce48c5030 | ||
|
|
0654b8e427 | ||
|
|
7df10b20a4 | ||
|
|
dbde5af545 | ||
|
|
85b4f0638f | ||
|
|
94f2751902 | ||
|
|
ffdfef0adc | ||
|
|
de7652836b | ||
|
|
59913bc6f3 | ||
|
|
d77a684b64 | ||
|
|
529c075fe1 | ||
|
|
5190589653 | ||
|
|
cb9a1b4bef | ||
|
|
a0beba4e20 | ||
|
|
d794425f2c | ||
|
|
1ba11fc3ef | ||
|
|
0dfb1ae776 | ||
|
|
c8a054f997 | ||
|
|
30c4e9cf00 | ||
|
|
c9fd2fc1c2 | ||
|
|
e9e3a436eb | ||
|
|
b9bd79895f | ||
|
|
36b574a5f8 | ||
|
|
fe90372b2f | ||
|
|
d47ddac94c | ||
|
|
854c374e2f | ||
|
|
7bafe142ca | ||
|
|
14ec8c4bea | ||
|
|
e9f2a77bf6 | ||
|
|
dcb4ce8d9a | ||
|
|
2702466cdf | ||
|
|
2016000d37 | ||
|
|
be0516c06c | ||
|
|
332a3635de | ||
|
|
9df4fa6a0e | ||
|
|
ddcb9ff819 | ||
|
|
7e9f5509ca | ||
|
|
c596d75e8c | ||
|
|
a0337d399c | ||
|
|
f0f52d7244 | ||
|
|
d55d796c00 | ||
|
|
6da36b27aa | ||
|
|
b4d3fc393e | ||
|
|
c4b68280fd | ||
|
|
97aeee7172 | ||
|
|
8bf57f1293 | ||
|
|
4584cebad5 | ||
|
|
557773144b | ||
|
|
32a29a5556 | ||
|
|
9f4a844c9b | ||
|
|
82b7650458 | ||
|
|
b7121c4447 | ||
|
|
b522de3b56 | ||
|
|
eb94caf4b6 | ||
|
|
0f59e0c950 | ||
|
|
05a254c682 | ||
|
|
576ba2c745 | ||
|
|
3dafda6ace | ||
|
|
2d048a3295 | ||
|
|
f2d345e7b1 | ||
|
|
6a0db02230 | ||
|
|
93f271912e | ||
|
|
55b78727ab | ||
|
|
69b555c059 | ||
|
|
07f327d641 | ||
|
|
c69f4ba4a2 | ||
|
|
d7e8d4d5c3 | ||
|
|
679a026e72 | ||
|
|
0db180a54f | ||
|
|
6c2de53e07 | ||
|
|
af132aa62e | ||
|
|
d528fd3762 | ||
|
|
663d355a48 | ||
|
|
27112e3480 | ||
|
|
482d3ff352 | ||
|
|
a444d4af94 | ||
|
|
6f77fda6fa | ||
|
|
8f7d653e80 | ||
|
|
e474b595ad | ||
|
|
b4c6292397 | ||
|
|
4aa994827c | ||
|
|
a521ccde47 | ||
|
|
03d280054b | ||
|
|
c0a3279856 | ||
|
|
e8643632bf | ||
|
|
6d8272472a | ||
|
|
409d5b124a | ||
|
|
0c1f3d056a | ||
|
|
0e702d8693 | ||
|
|
b155cd9a5a | ||
|
|
6a281fb7ba | ||
|
|
203891c957 | ||
|
|
1365df898f | ||
|
|
a2bc02b4c5 | ||
|
|
0d01aa4eea | ||
|
|
017c73132c | ||
|
|
534bfad50f | ||
|
|
429f44eb6a | ||
|
|
346c88b661 | ||
|
|
c49853e7b4 | ||
|
|
11232c6f23 | ||
|
|
9aa788f086 | ||
|
|
c35268c493 | ||
|
|
df0ad4486e | ||
|
|
d369385657 | ||
|
|
059e067bdc | ||
|
|
050759c1c2 | ||
|
|
6d264b4394 | ||
|
|
284330ed5f | ||
|
|
49205b604c | ||
|
|
c14c27970f | ||
|
|
b1682d5794 | ||
|
|
d0b9dd9ae7 | ||
|
|
0a94b7473d | ||
|
|
587a928b84 | ||
|
|
48dbc06b29 | ||
|
|
967515a34f | ||
|
|
8e0bce4da4 | ||
|
|
01078bd7b2 | ||
|
|
a97fbb2d48 | ||
|
|
6782f92703 | ||
|
|
9096c29fef | ||
|
|
100967c57b | ||
|
|
c871af2711 | ||
|
|
faf99ffe14 | ||
|
|
58d073b516 | ||
|
|
52a4d41c6f | ||
|
|
0805b00c50 | ||
|
|
c8f8bfd6f0 | ||
|
|
1f51d37ae6 | ||
|
|
f8a4b8de51 | ||
|
|
eaa64d7b70 | ||
|
|
4480fbf787 | ||
|
|
c2287033e3 | ||
|
|
0a0fb5287a | ||
|
|
52acbd7d2c | ||
|
|
af4f84a84b | ||
|
|
633241fcee | ||
|
|
f1f3d288cd | ||
|
|
7c98da85a0 | ||
|
|
36f7d64352 | ||
|
|
a4bbcbe5ff | ||
|
|
cbb4ec5aa1 | ||
|
|
84fc5f7d67 | ||
|
|
a4d84cdc21 | ||
|
|
1a422f318c | ||
|
|
8f202fd70d | ||
|
|
dfe96eb30c | ||
|
|
3d7c6c14b3 | ||
|
|
85a4e361d2 | ||
|
|
05b2fa97d3 | ||
|
|
47d57ddf70 | ||
|
|
9521ac6adb | ||
|
|
c2703d215b | ||
|
|
f5c1133fc5 | ||
|
|
f63d81826a | ||
|
|
fa39982a8f | ||
|
|
4b52414e03 | ||
|
|
29b0a7659f | ||
|
|
e69183ce12 | ||
|
|
009c088a64 | ||
|
|
2c1f948832 | ||
|
|
b83e007405 | ||
|
|
1d3ce2c029 | ||
|
|
5ad0730a26 | ||
|
|
52f1383903 | ||
|
|
12b8cbf3e0 | ||
|
|
de44f8565d | ||
|
|
7480ead76a | ||
|
|
e96ae7a650 | ||
|
|
ae524c4d0e | ||
|
|
5adce88c37 | ||
|
|
06dda24431 | ||
|
|
fa046df923 | ||
|
|
2432eb39b1 | ||
|
|
c211a2517f | ||
|
|
73ea0a57a0 | ||
|
|
f05f86dc80 | ||
|
|
e44b25c80f | ||
|
|
bc3acc2826 | ||
|
|
007fb34ca5 | ||
|
|
46a363cce4 | ||
|
|
3047ce57a3 | ||
|
|
7b9ce072d9 | ||
|
|
4d3e3f3aed | ||
|
|
62563ad8a1 | ||
|
|
6fdce63359 | ||
|
|
fdc4d6dda9 | ||
|
|
a3b06ee83f | ||
|
|
43aa62e212 | ||
|
|
70dd3f323e | ||
|
|
803509d952 | ||
|
|
30e85c8654 | ||
|
|
7b24835c9e | ||
|
|
7aee76f5de | ||
|
|
80200a9983 | ||
|
|
79f6b5c181 | ||
|
|
dc02ce3f97 | ||
|
|
845d5a548f | ||
|
|
14a8cf69ef | ||
|
|
c8a6e8005e | ||
|
|
e6bb2bfaae | ||
|
|
8ba2d1cf72 | ||
|
|
a168fc3719 | ||
|
|
fd1dc15576 | ||
|
|
0b82874a52 | ||
|
|
434242858f | ||
|
|
3dfa0525bd | ||
|
|
36d4baaa8e | ||
|
|
7880cba0f9 | ||
|
|
f8d64528b5 | ||
|
|
f6ee61f29e | ||
|
|
2bb1310094 | ||
|
|
f6a137cd43 | ||
|
|
a575fe4934 | ||
|
|
4cd8d8a4a5 | ||
|
|
7a802726fb | ||
|
|
251245d315 | ||
|
|
fbf5a84c4a | ||
|
|
55412b94d2 | ||
|
|
f61fd02ac7 | ||
|
|
dc96b473cd | ||
|
|
abe40c84b0 | ||
|
|
9976fc9723 | ||
|
|
f8092f924a | ||
|
|
075a877284 | ||
|
|
f748395bda | ||
|
|
12018360fd | ||
|
|
821b2fda85 | ||
|
|
4cb2b29187 | ||
|
|
bb59778313 | ||
|
|
ed0ded33b7 | ||
|
|
db19528c24 | ||
|
|
7d1fb0a238 | ||
|
|
11956d9e16 | ||
|
|
cef782c388 | ||
|
|
e87e371c14 | ||
|
|
877a455ae0 | ||
|
|
a47618e986 | ||
|
|
2bbd759c25 | ||
|
|
4dd19884e0 | ||
|
|
5ab0f499ce | ||
|
|
053723647b | ||
|
|
725a44abd8 | ||
|
|
625f2d2410 | ||
|
|
e32748daf2 | ||
|
|
8a2bd1cac3 | ||
|
|
9076f213e6 | ||
|
|
e77edc56fd | ||
|
|
de356304c7 | ||
|
|
8cc9e30f86 | ||
|
|
384323031b | ||
|
|
b40a7b24d4 | ||
|
|
67b2a433a8 | ||
|
|
07bdf02af4 | ||
|
|
35b470dbac | ||
|
|
42eb49b84c | ||
|
|
9d3d11755f | ||
|
|
0fbc546696 | ||
|
|
220422ba0d | ||
|
|
2c9bae8111 | ||
|
|
320f6ddc6e | ||
|
|
0da6d51150 | ||
|
|
65e3170cd9 | ||
|
|
ee3750121c | ||
|
|
9736a4ddd0 | ||
|
|
53e310ff77 | ||
|
|
17285720f1 | ||
|
|
aa690cb9ab | ||
|
|
6d3596087a | ||
|
|
0fe80e8e1f | ||
|
|
f853f20b0c | ||
|
|
39e6fa35e1 | ||
|
|
23b911297e | ||
|
|
6113d1e3eb | ||
|
|
55f3b93958 | ||
|
|
c522987b6f | ||
|
|
8fe64755ec | ||
|
|
cc35328f28 | ||
|
|
a824a7fb73 | ||
|
|
075d7e52df | ||
|
|
cadbae31e4 | ||
|
|
39b5a67040 | ||
|
|
30580b2c57 | ||
|
|
00ab830ad1 | ||
|
|
fcf3577f67 | ||
|
|
2cdfeb8dd0 | ||
|
|
ce300aa75f | ||
|
|
a52caaec75 | ||
|
|
3f3489b292 | ||
|
|
1e059c5649 | ||
|
|
d9e1b2df7f | ||
|
|
94e51a8041 | ||
|
|
81fe90f605 | ||
|
|
69f643447d | ||
|
|
d8355371e3 | ||
|
|
cbe9b9c455 | ||
|
|
dd33c0e582 | ||
|
|
009b0aa361 | ||
|
|
f438176544 | ||
|
|
be8e8a0521 | ||
|
|
1a8b31bdb4 | ||
|
|
8a47055273 | ||
|
|
feb6f7930e | ||
|
|
0271ea7dad | ||
|
|
505b73d20e | ||
|
|
dcad8a9f79 | ||
|
|
9ce58115ab | ||
|
|
1c9d139ff5 | ||
|
|
70794c8eb5 | ||
|
|
c90c4a2e78 | ||
|
|
6797e8af52 | ||
|
|
5109802dfb | ||
|
|
935297b9e8 | ||
|
|
dad209d1cd | ||
|
|
e1072cc8ca | ||
|
|
1a1ba80188 | ||
|
|
c878c91e11 | ||
|
|
c518521d74 | ||
|
|
ce9c9078e5 | ||
|
|
9fe525bca1 | ||
|
|
352865ddaa | ||
|
|
bc950ee40a | ||
|
|
5c23dfd633 | ||
|
|
4633a0450c | ||
|
|
842255766f | ||
|
|
827c32fafd | ||
|
|
f531cd23ee | ||
|
|
2408758360 | ||
|
|
4c792f6f17 | ||
|
|
802ab90d87 | ||
|
|
c268a0ab14 | ||
|
|
b12c7f21b3 | ||
|
|
b3948910ff | ||
|
|
9ee1261204 | ||
|
|
8e3aa0e9ce | ||
|
|
db62a01224 | ||
|
|
d900f2c47c | ||
|
|
82e1fe3f8b | ||
|
|
85eb82e69d | ||
|
|
c529f8099d | ||
|
|
aa3c58917b | ||
|
|
bc591a2399 | ||
|
|
11d996bb56 | ||
|
|
088a78455c | ||
|
|
869d9d487b | ||
|
|
db3978fd4e | ||
|
|
ae7e46fe5e | ||
|
|
4bd85e1804 | ||
|
|
01f4434f6b | ||
|
|
d8f808bf38 | ||
|
|
807dc7d220 | ||
|
|
b14d0c9f60 | ||
|
|
738a1a330c | ||
|
|
676b02c8de | ||
|
|
7136400a33 | ||
|
|
4651d9df68 | ||
|
|
00555a8e9e | ||
|
|
e8c4615ff6 | ||
|
|
763467058b | ||
|
|
c055ba2985 | ||
|
|
7666541905 | ||
|
|
f4b0b39beb | ||
|
|
cfc0925e75 | ||
|
|
4dcc368378 | ||
|
|
8207908d9e | ||
|
|
e08da096dd | ||
|
|
9a903a1ca3 | ||
|
|
1b22bf0e08 | ||
|
|
fc3187a781 | ||
|
|
7fbb4045e2 | ||
|
|
d0dc22794e | ||
|
|
0f235a80e0 | ||
|
|
2a28046382 | ||
|
|
169bbfd2db | ||
|
|
1f52bb35ba | ||
|
|
4a03b3d7d9 | ||
|
|
2544a7e4ea | ||
|
|
26e77ba2c3 | ||
|
|
28c11801f3 | ||
|
|
b3e2ab0f3b | ||
|
|
fb12ba8a2b | ||
|
|
7a5bc864fa | ||
|
|
2e85d4b55a | ||
|
|
80951a8e6e | ||
|
|
9acddede65 | ||
|
|
22165ec1a5 | ||
|
|
d7036aae48 | ||
|
|
fe3924b432 | ||
|
|
510cffb305 | ||
|
|
05c789ae50 | ||
|
|
5d95d61aef | ||
|
|
c61fa71a70 | ||
|
|
3145269f65 | ||
|
|
2d00a1e265 | ||
|
|
f7f178d6e3 | ||
|
|
18c591e0d0 | ||
|
|
749241f4e5 | ||
|
|
997c368604 | ||
|
|
ed28928c84 | ||
|
|
b55c916e77 | ||
|
|
4d537b2a9a | ||
|
|
21f7d6c9b9 | ||
|
|
c1b865d00e | ||
|
|
a32e740242 | ||
|
|
c4f09b5598 | ||
|
|
5a89aa3b32 | ||
|
|
149d57150c | ||
|
|
bbc241748b | ||
|
|
74ecea6307 | ||
|
|
2e829956f4 | ||
|
|
9e2c9cbba9 | ||
|
|
1ad740800b | ||
|
|
c00d4c1a7b | ||
|
|
e0985ebb1c | ||
|
|
d5706442de | ||
|
|
ad5a173f3f | ||
|
|
fbb1d9247f | ||
|
|
63591941b8 | ||
|
|
fdfeec54d7 | ||
|
|
b2404809fc | ||
|
|
f9f463e799 | ||
|
|
f1d3a553d1 | ||
|
|
e997b148e1 | ||
|
|
af906fac03 | ||
|
|
19945df0b3 | ||
|
|
bf83d552f8 | ||
|
|
f5d8e99fc7 | ||
|
|
975037c5a0 | ||
|
|
8b0b45e089 | ||
|
|
182f2ae26e | ||
|
|
26982787ee | ||
|
|
4a42e3ef1b | ||
|
|
4f4498666e | ||
|
|
8f9ba44c2c | ||
|
|
1f91d4fa7b | ||
|
|
cf97d090f3 | ||
|
|
9cd96a65d6 | ||
|
|
5fc75cb4cd | ||
|
|
27fe566412 | ||
|
|
a68c7bf019 | ||
|
|
11388849de | ||
|
|
aa8fb55b30 | ||
|
|
472bea2baa | ||
|
|
0a7a6c64ce | ||
|
|
fde8196874 | ||
|
|
ea8576d344 | ||
|
|
9adda25e00 | ||
|
|
2cc0bf22cb | ||
|
|
892ebc2e03 | ||
|
|
5c9ee03389 | ||
|
|
3702b0c694 | ||
|
|
451d662af4 | ||
|
|
7b8e0a2755 | ||
|
|
63ba4f4f91 | ||
|
|
5f92465d0f | ||
|
|
64c8c5a014 | ||
|
|
2d6322f799 | ||
|
|
8127ce18a3 | ||
|
|
7b5801920b | ||
|
|
c18c1e59df | ||
|
|
4959e664a9 | ||
|
|
fb5ba257ef | ||
|
|
0ed1c0aa6b | ||
|
|
a12fac780b | ||
|
|
0b16e13597 | ||
|
|
45a9e54631 | ||
|
|
b969307c5e | ||
|
|
20325e87be | ||
|
|
fc48d9047a | ||
|
|
16b4db5083 | ||
|
|
4c7487cd2e | ||
|
|
271033e79d | ||
|
|
d2ddcf2d38 | ||
|
|
8a2ab30302 | ||
|
|
3070b0019e | ||
|
|
68ef1fc9e0 | ||
|
|
c13d67dea5 | ||
|
|
b52cf070f5 | ||
|
|
e363cd9813 | ||
|
|
c10fc26cce | ||
|
|
3bb7123dd5 | ||
|
|
2f2a7d1f89 | ||
|
|
013d307bcd | ||
|
|
5e616dd502 | ||
|
|
f200bd2198 | ||
|
|
bd36ee4f67 | ||
|
|
e0e5cc076d | ||
|
|
95e3fb24f3 | ||
|
|
83d47aed2d | ||
|
|
bbd7cf306a | ||
|
|
f6b5c752f4 | ||
|
|
ff20acc367 | ||
|
|
46c2720fc7 | ||
|
|
cf0e3ec303 | ||
|
|
c6bb3d6ae2 | ||
|
|
b39ba92cfe | ||
|
|
deb1c190c9 | ||
|
|
5d0384f580 | ||
|
|
d3ce8203be | ||
|
|
6e80f0d93b | ||
|
|
c9a923decf | ||
|
|
1be5f2d647 | ||
|
|
a38bba80ee | ||
|
|
b15d84359b | ||
|
|
a3670b731e | ||
|
|
b89546de37 | ||
|
|
fad4314538 | ||
|
|
a331961ef3 | ||
|
|
e6f62dc95e | ||
|
|
bd6d863921 | ||
|
|
c11117b070 | ||
|
|
f387ccb9e4 | ||
|
|
fd49830c35 | ||
|
|
578ca6975f | ||
|
|
c0442edb8d | ||
|
|
1416197b62 | ||
|
|
e1dd53f146 | ||
|
|
73abd0f8b8 | ||
|
|
ab982e86c3 | ||
|
|
20a4cd49de | ||
|
|
387d712b67 | ||
|
|
3d9ec91b35 | ||
|
|
8892c8c883 | ||
|
|
c51c98d682 | ||
|
|
3f4ac84cfb | ||
|
|
c5a864e86b | ||
|
|
e945dceab9 | ||
|
|
f176832851 | ||
|
|
ab195ea520 | ||
|
|
e4b861e766 | ||
|
|
ead6d8d3a1 | ||
|
|
796e2ec825 | ||
|
|
a597c3f835 | ||
|
|
c14cb29334 | ||
|
|
a233d28efc | ||
|
|
c7bc2ca82d | ||
|
|
bd6323ccae | ||
|
|
4326bfa504 | ||
|
|
b7a4c0664b | ||
|
|
da7bcf89d4 | ||
|
|
3907cc679a | ||
|
|
8cc5aee528 | ||
|
|
d0b5c4de28 | ||
|
|
431150c262 | ||
|
|
ee994ea393 | ||
|
|
53cd259ffa | ||
|
|
c0ed44abf9 | ||
|
|
0807eec4cc | ||
|
|
aec7271f50 | ||
|
|
a723518346 | ||
|
|
5d6d8e68ed | ||
|
|
197a9330df | ||
|
|
8b807d7b50 | ||
|
|
03c0111017 | ||
|
|
e55752869b | ||
|
|
94830cffca | ||
|
|
8d4319ba5f | ||
|
|
06987c4ca9 | ||
|
|
70c0edcbe7 | ||
|
|
7a482fd22a | ||
|
|
022b8ec13a | ||
|
|
b02f169764 | ||
|
|
6c0254b5f4 | ||
|
|
0a60d7016d | ||
|
|
315a2a695f | ||
|
|
863c8de28e | ||
|
|
92213f9228 | ||
|
|
253c8118a2 | ||
|
|
290c980d5f | ||
|
|
6ead1f4bd9 | ||
|
|
6e4a5b64b7 | ||
|
|
6e3e60a44d | ||
|
|
b88fafe5ff | ||
|
|
17a56bbf48 | ||
|
|
d8e51c6b14 | ||
|
|
44554cb54b | ||
|
|
0bd86a8211 | ||
|
|
7fcb3d70bb | ||
|
|
563cd828ad | ||
|
|
3581e0beed | ||
|
|
da04de7b2d | ||
|
|
661ce29519 | ||
|
|
56bed3f297 | ||
|
|
79a8715c8b | ||
|
|
69062dca16 | ||
|
|
40d3085cc2 | ||
|
|
5e444de031 | ||
|
|
3e61b89499 | ||
|
|
76e9d749c9 | ||
|
|
3e47c352a3 | ||
|
|
6028cfc1a3 | ||
|
|
20f1a85e69 | ||
|
|
00d3d0f094 | ||
|
|
8756ae0fe6 | ||
|
|
bdb1fc2ed7 | ||
|
|
34d64fbcaf | ||
|
|
3eeb0628f5 | ||
|
|
3ed71fa21e | ||
|
|
731ecfda64 | ||
|
|
230eb76532 | ||
|
|
93f2b288b5 | ||
|
|
d9ee9ba238 | ||
|
|
e000fdfb50 | ||
|
|
4e97d2503b | ||
|
|
f21f793343 | ||
|
|
c470f2734d | ||
|
|
28ddf6cf07 | ||
|
|
e0302d1f09 | ||
|
|
a536f79f6d | ||
|
|
5c48fb9e66 | ||
|
|
994ba1edd9 | ||
|
|
ed90979417 | ||
|
|
4dc2172426 | ||
|
|
daa41f8664 | ||
|
|
4e93ffb924 | ||
|
|
f29363f56d | ||
|
|
23680ccb14 | ||
|
|
986e58aeec | ||
|
|
13da75c2b6 | ||
|
|
28b28cfef6 | ||
|
|
167bf70cd6 | ||
|
|
5236dcfe52 | ||
|
|
a437524c8f | ||
|
|
fcbd48648c | ||
|
|
3f29273f6e | ||
|
|
b78ffdad02 | ||
|
|
fd4cd3ed04 | ||
|
|
d8001fcaea | ||
|
|
9771c652c5 | ||
|
|
a0c7bbe213 | ||
|
|
6b43042828 | ||
|
|
73f0b1e8a3 | ||
|
|
fa1b61b3e3 | ||
|
|
c116e94cba | ||
|
|
7229652e31 | ||
|
|
03acf7a05c | ||
|
|
d83d8c18fc | ||
|
|
2080e56f87 | ||
|
|
90f0f27fca | ||
|
|
5837026e83 | ||
|
|
edc67e5da2 | ||
|
|
55b43f4612 | ||
|
|
32a32e4a72 | ||
|
|
0eae0da781 | ||
|
|
51b62ea467 | ||
|
|
462fa5999f | ||
|
|
82b730c5b8 | ||
|
|
492ea7264a | ||
|
|
a1c910e3aa | ||
|
|
bf5f58e0ce | ||
|
|
428bc9b419 | ||
|
|
a2742caa87 | ||
|
|
d2a5edda46 | ||
|
|
38f8956bd0 | ||
|
|
ec8deab454 | ||
|
|
cdc92fc552 | ||
|
|
53fb48fe7d | ||
|
|
73e4006447 | ||
|
|
c2ff269b5f | ||
|
|
c7310b64ad | ||
|
|
83daa702f9 | ||
|
|
cb1a06270e | ||
|
|
fd34f97120 | ||
|
|
2dc8f3b3e4 | ||
|
|
7e5b81ff4d | ||
|
|
f5b945c09b | ||
|
|
6014dd05a0 | ||
|
|
0c6aa381c5 | ||
|
|
0246f050e2 | ||
|
|
5f222c4df2 | ||
|
|
800f3f765f | ||
|
|
635f346b12 | ||
|
|
abe79dbf64 | ||
|
|
2b72622fe8 | ||
|
|
201c7a7e49 | ||
|
|
ef21283a61 | ||
|
|
4eb76cdc30 | ||
|
|
3b68f598b1 | ||
|
|
31db43dbb0 | ||
|
|
1efc4a03cc | ||
|
|
607c818879 | ||
|
|
6d5f044948 | ||
|
|
f24a8b3918 | ||
|
|
2e402098a2 | ||
|
|
3389c798f6 | ||
|
|
738ad474c1 | ||
|
|
86e2ac1497 | ||
|
|
b2a4f11e0b | ||
|
|
09d380ba8f | ||
|
|
12bfa72f31 | ||
|
|
b0990ac6ec | ||
|
|
6f1f07a1c4 | ||
|
|
f55fdae9eb | ||
|
|
b0225880de | ||
|
|
74be6af3e6 | ||
|
|
72f5fbd6ad | ||
|
|
ae3efa1151 | ||
|
|
348ed268c3 | ||
|
|
df19ccf998 | ||
|
|
db2e4f30a7 | ||
|
|
a1e1f5aab6 | ||
|
|
7ffe11b000 | ||
|
|
eb5ea17610 | ||
|
|
8657381dce | ||
|
|
55114082e3 | ||
|
|
64051e9cfa | ||
|
|
780d64a349 | ||
|
|
bcd1827d8a | ||
|
|
0097f5fc8d | ||
|
|
3766d2b97b | ||
|
|
f2b7bfc561 | ||
|
|
4d3484002d | ||
|
|
34f20f914a | ||
|
|
19444353b4 | ||
|
|
b4f0a13779 | ||
|
|
fa815af798 | ||
|
|
f1e2aa8c96 | ||
|
|
9fd24db257 | ||
|
|
73414f2ee1 | ||
|
|
7b37e5183c | ||
|
|
bb8438c770 | ||
|
|
3dd329a999 | ||
|
|
ab2672777e | ||
|
|
45aea4176f | ||
|
|
f8dfbbb0b9 | ||
|
|
48a348c4d1 | ||
|
|
870ff56629 | ||
|
|
b2ed8d8560 | ||
|
|
e8510ddc58 | ||
|
|
97f7575409 | ||
|
|
5220157b01 | ||
|
|
900f9ec9a9 | ||
|
|
52ec2c2538 | ||
|
|
31101221e0 | ||
|
|
ae37c2ab2a | ||
|
|
e8d014d80d | ||
|
|
b88f1dc79a | ||
|
|
dccc791c99 | ||
|
|
474d2402b7 | ||
|
|
7a9f1e9c6c | ||
|
|
98364e83b6 | ||
|
|
bf65f033dd | ||
|
|
2d9b430327 | ||
|
|
ec54443674 | ||
|
|
0fb84ccc49 | ||
|
|
0b4aad4931 | ||
|
|
ab470d4a4c | ||
|
|
88e1245d10 | ||
|
|
bc4dbd6194 | ||
|
|
b35df54c81 | ||
|
|
c53c7b1aaa | ||
|
|
0a0653358c | ||
|
|
e2ccaf2c91 | ||
|
|
75f5212661 | ||
|
|
1e548af987 | ||
|
|
2c2c828b47 | ||
|
|
19e49a7de7 | ||
|
|
18c9ad25be | ||
|
|
9e3f0304de | ||
|
|
55dbcb646b | ||
|
|
db0ab2e4a9 | ||
|
|
c254eebea2 | ||
|
|
45b0e7dc01 | ||
|
|
4c4c62c7e5 | ||
|
|
cb2038442c | ||
|
|
1d219eb8f2 | ||
|
|
7d33563010 | ||
|
|
e3d34c46c7 | ||
|
|
9129e82804 | ||
|
|
d4f4a64937 | ||
|
|
2b4a51ba24 | ||
|
|
6a8d755b27 | ||
|
|
754fea538a | ||
|
|
4d0b660c73 | ||
|
|
d0173fbdc5 | ||
|
|
62ae4aeac9 | ||
|
|
e98aa81794 | ||
|
|
a5dcac137f | ||
|
|
96215d32b7 | ||
|
|
4a20989028 | ||
|
|
f5fe6a36eb | ||
|
|
852bab6e0b | ||
|
|
52ec27f785 | ||
|
|
c6d617f190 | ||
|
|
1a6ef23ee7 | ||
|
|
759bbeac06 | ||
|
|
15c72fe7d3 | ||
|
|
f6973f9a70 | ||
|
|
f1d5afe72a | ||
|
|
e1f2cd21e7 | ||
|
|
ea5c60af7a | ||
|
|
558567d399 | ||
|
|
0c1899a0af | ||
|
|
28d8ad1e61 | ||
|
|
eb0a0662a3 | ||
|
|
3a21efbaae | ||
|
|
405363da59 | ||
|
|
e5bcfeaad5 | ||
|
|
8b8cfa7a1b | ||
|
|
af131cd1e5 | ||
|
|
a7bb90e7e6 | ||
|
|
25cf36a948 | ||
|
|
cc3ff284f7 | ||
|
|
0af6f271c6 | ||
|
|
441cddbde6 | ||
|
|
1ab09c65f0 | ||
|
|
b9892fc2d0 | ||
|
|
14bf3056de | ||
|
|
b3b9555daa | ||
|
|
db66ffc868 | ||
|
|
91decea302 | ||
|
|
065c19cbbc | ||
|
|
296ebd0341 | ||
|
|
5293e3b277 | ||
|
|
78f5b1e607 | ||
|
|
17af5622ec | ||
|
|
2afce3f1f4 | ||
|
|
dc29b4afa1 | ||
|
|
55fc0cb63b | ||
|
|
5e1eda9e97 | ||
|
|
d582af8cb2 | ||
|
|
0931341a7f | ||
|
|
92916d9820 | ||
|
|
12fbbbb5b3 | ||
|
|
0a603d022f | ||
|
|
2ada9fbee3 | ||
|
|
6e2132c65e | ||
|
|
71dbf0fab2 | ||
|
|
048e97e1ee | ||
|
|
f1c0f1d0a4 | ||
|
|
7242d03f56 | ||
|
|
58bbc33aa6 | ||
|
|
85e82d0bd5 | ||
|
|
d6c23bb5f3 | ||
|
|
8235bca664 | ||
|
|
cd2541a9d2 | ||
|
|
4f7036a405 | ||
|
|
227c9594db | ||
|
|
ea41a60057 | ||
|
|
eee47eae61 | ||
|
|
b6c1816833 | ||
|
|
4e359848d1 | ||
|
|
9cce56caf8 | ||
|
|
f5f0bae2ef | ||
|
|
4fc65aac84 | ||
|
|
bf32477f89 | ||
|
|
969eeff636 | ||
|
|
958607ba9b | ||
|
|
dcfcc1f271 | ||
|
|
bc3c6af95d | ||
|
|
701220246d | ||
|
|
e3b0cdaf69 | ||
|
|
c61cbfc581 | ||
|
|
58073484fe | ||
|
|
8ce1bb1b0b | ||
|
|
3fab42b8d1 | ||
|
|
5b802e9edd | ||
|
|
a9308dd992 | ||
|
|
937a3e7fd6 | ||
|
|
c9caa5687a | ||
|
|
d6950c680f | ||
|
|
4fe33db4f3 | ||
|
|
96d9604fe1 | ||
|
|
0c6eacb141 | ||
|
|
e83a97349f | ||
|
|
6c5f0aecb4 | ||
|
|
d9160f9126 | ||
|
|
1d93de8628 | ||
|
|
54de5b0300 | ||
|
|
b7145959a7 | ||
|
|
1d32a96b01 | ||
|
|
9cc02d6fcb | ||
|
|
5d18c04661 | ||
|
|
e88e17a4b0 | ||
|
|
a75d73b8ac | ||
|
|
bbac6b55d2 | ||
|
|
3eeed39f52 | ||
|
|
7356b7a104 | ||
|
|
54310b925d | ||
|
|
85b5c60d60 | ||
|
|
ab48ae6ca6 | ||
|
|
7a62eb0ebf | ||
|
|
c9423509a9 | ||
|
|
0c77d6d918 | ||
|
|
a0cc6afa7e | ||
|
|
8a08a0211f | ||
|
|
2c044d7262 | ||
|
|
9ff3160808 | ||
|
|
7671ed857d | ||
|
|
b9bbe7a432 | ||
|
|
76a18f5ed3 | ||
|
|
0ee2b02700 | ||
|
|
173984ffd4 | ||
|
|
f309ae0c67 | ||
|
|
26ef2539df | ||
|
|
bc7df4c841 | ||
|
|
26c95bab66 | ||
|
|
95b588f58e | ||
|
|
15e8f6ffb7 | ||
|
|
10cdd7640e | ||
|
|
f216287aee | ||
|
|
38871a98b4 | ||
|
|
9158bdfcf9 | ||
|
|
4dd694ab05 | ||
|
|
553e3ee758 | ||
|
|
a470bf127e | ||
|
|
52adf51d33 | ||
|
|
d688e34521 | ||
|
|
50b8744f24 | ||
|
|
3e6faf8364 | ||
|
|
720de651f3 | ||
|
|
3d382d0354 | ||
|
|
8fea5585e5 | ||
|
|
3f12a17246 | ||
|
|
087ff278aa | ||
|
|
301abcaa49 | ||
|
|
e33b8cc8e5 | ||
|
|
d1bc8a7202 | ||
|
|
77fa3bd7fc | ||
|
|
3162fcf154 | ||
|
|
c618bdfe91 | ||
|
|
dd5c9939a0 | ||
|
|
80082b0880 | ||
|
|
b7aa115bd2 | ||
|
|
0e9950638c | ||
|
|
a957acd893 | ||
|
|
a9244333fb | ||
|
|
63a19bc0a1 | ||
|
|
c25d648321 | ||
|
|
2f6711dd2d | ||
|
|
c450b41e8f | ||
|
|
9937650062 | ||
|
|
56ff88934f | ||
|
|
c1a577797a | ||
|
|
257227920d | ||
|
|
461633cd83 | ||
|
|
a0887e9285 | ||
|
|
23354d371f | ||
|
|
0e838d59d5 | ||
|
|
f305c9d96a | ||
|
|
226665403f | ||
|
|
88d0460e3c | ||
|
|
e09b4f878e | ||
|
|
a7ef3ce58a | ||
|
|
256f33b720 | ||
|
|
e17002c6da | ||
|
|
f2d96b895f | ||
|
|
dade589075 | ||
|
|
0d9cd25a71 | ||
|
|
cb73490107 | ||
|
|
535405521c | ||
|
|
8785c08861 | ||
|
|
0020a37029 | ||
|
|
33cbed592a | ||
|
|
28c0e15058 | ||
|
|
a316411f76 | ||
|
|
66ad519dbd | ||
|
|
2a8dc1d34a | ||
|
|
228b670b4f | ||
|
|
da9fb46b6a | ||
|
|
f4d120b11f | ||
|
|
bc954b75ce | ||
|
|
b787734913 | ||
|
|
fb5a6c20de | ||
|
|
3fda085cbb | ||
|
|
d87ea854bc | ||
|
|
f41cb0d81c | ||
|
|
8427b03a39 | ||
|
|
9cb7786182 | ||
|
|
6666dece5d | ||
|
|
efdd17fa9a | ||
|
|
7f7d5d9f4c | ||
|
|
9b542f7653 | ||
|
|
b27c3ff169 | ||
|
|
115221098a | ||
|
|
5a6a7e8d82 | ||
|
|
9adac5686b | ||
|
|
fad88c2718 | ||
|
|
e205577145 | ||
|
|
6368ab691c | ||
|
|
5b2358c97f | ||
|
|
072430cef5 | ||
|
|
5f7055e282 | ||
|
|
be982d95ea | ||
|
|
b9c8df7019 | ||
|
|
e89ae475f6 | ||
|
|
9476d7fdbb | ||
|
|
da16a799fa | ||
|
|
9e0feb0b64 | ||
|
|
93a600a0a8 | ||
|
|
06ee68f836 | ||
|
|
d6f1abad95 | ||
|
|
933c99110c | ||
|
|
8999bbf297 | ||
|
|
200fc56a4a |
20
.github/ISSUE_TEMPLATE/task.yaml
vendored
@@ -1,20 +0,0 @@
|
|||||||
name: 📝 Task
|
|
||||||
description: Create a task for the team to work on, used internally only. We will delete tasks created by non-team members.
|
|
||||||
title: "[Task]: "
|
|
||||||
labels: [Task]
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Are you our team member?
|
|
||||||
description: If you are not our team member, please go to discussions.
|
|
||||||
options:
|
|
||||||
- label: Yes, I am?
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: SubTasks
|
|
||||||
placeholder: |
|
|
||||||
- Sub Task 1
|
|
||||||
- Sub Task 2
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
41
.github/workflows/bridge.yml
vendored
@@ -1,14 +1,15 @@
|
|||||||
# This yaml shares the build bridge steps with ci and nightly.
|
# This yaml shares the build bridge steps with ci and nightly.
|
||||||
name: Build flutter-rust-bridge
|
name: Build flutter-rust-bridge
|
||||||
# 2023-04-19 15:48:00+00:00
|
# 2023-11-23 18:00:00+00:00
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FLUTTER_VERSION: "3.10.6"
|
FLUTTER_VERSION: "3.16.9"
|
||||||
FLUTTER_RUST_BRIDGE_VERSION: "1.75.3"
|
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
|
||||||
|
RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
generate_bridge:
|
generate_bridge:
|
||||||
runs-on: ${{ matrix.job.os }}
|
runs-on: ${{ matrix.job.os }}
|
||||||
@@ -23,21 +24,33 @@ jobs:
|
|||||||
}
|
}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install prerequisites
|
- name: Install prerequisites
|
||||||
run: |
|
run: |
|
||||||
sudo apt install ca-certificates -y
|
sudo apt-get install ca-certificates -y
|
||||||
sudo apt update -y
|
sudo apt-get update -y
|
||||||
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang cmake libclang-dev ninja-build llvm-dev libclang-10-dev llvm-10-dev pkg-config
|
sudo apt-get install -y \
|
||||||
|
clang \
|
||||||
|
cmake \
|
||||||
|
curl \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
g++ \
|
||||||
|
libclang-10-dev \
|
||||||
|
libgtk-3-dev \
|
||||||
|
llvm-10-dev \
|
||||||
|
nasm \
|
||||||
|
ninja-build \
|
||||||
|
pkg-config \
|
||||||
|
wget
|
||||||
|
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: ${{ env.RUST_VERSION }}
|
||||||
target: ${{ matrix.job.target }}
|
targets: ${{ matrix.job.target }}
|
||||||
override: true
|
components: "rustfmt"
|
||||||
profile: minimal # minimal component installation (ie, no documentation)
|
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
@@ -74,5 +87,5 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
./src/bridge_generated.rs
|
./src/bridge_generated.rs
|
||||||
./src/bridge_generated.io.rs
|
./src/bridge_generated.io.rs
|
||||||
./flutter/lib/generated_bridge.dart
|
./flutter/lib/generated_bridge.dart
|
||||||
./flutter/lib/generated_bridge.freezed.dart
|
./flutter/lib/generated_bridge.freezed.dart
|
||||||
|
|||||||
230
.github/workflows/build-macos-arm64.yml
vendored
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
name: Flutter Nightly MacOS Arm64 Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
#schedule:
|
||||||
|
# schedule build every night
|
||||||
|
# - cron: "0/6 * * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503
|
||||||
|
CARGO_NDK_VERSION: "3.1.2"
|
||||||
|
LLVM_VERSION: "15.0.6"
|
||||||
|
FLUTTER_VERSION: "3.19.6"
|
||||||
|
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
|
||||||
|
# for arm64 linux because official Dart SDK does not work
|
||||||
|
FLUTTER_ELINUX_VERSION: "3.16.9"
|
||||||
|
TAG_NAME: "nightly"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||||
|
# vcpkg version: 2024.03.25
|
||||||
|
VCPKG_COMMIT_ID: "a34c873a9717a888f58dc05268dea15592c2f0ff"
|
||||||
|
VERSION: "1.2.5"
|
||||||
|
NDK_VERSION: "r26d"
|
||||||
|
#signing keys env variable checks
|
||||||
|
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||||
|
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
||||||
|
# To make a custom build with your own servers set the below secret values
|
||||||
|
RS_PUB_KEY: "${{ secrets.RS_PUB_KEY }}"
|
||||||
|
RENDEZVOUS_SERVER: "${{ secrets.RENDEZVOUS_SERVER }}"
|
||||||
|
API_SERVER: "${{ secrets.API_SERVER }}"
|
||||||
|
UPLOAD_ARTIFACT: "${{ inputs.upload-artifact }}"
|
||||||
|
SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-appimage:
|
||||||
|
name: Build image ${{ matrix.job.target }}
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- {
|
||||||
|
target: x86_64-unknown-linux-gnu,
|
||||||
|
arch: x86_64,
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
target: aarch64-unknown-linux-gnu,
|
||||||
|
arch: aarch64,
|
||||||
|
}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Rename Binary
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y wget libarchive-tools
|
||||||
|
wget https://github.com/rustdesk/rustdesk/releases/download/nightly/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb
|
||||||
|
mv rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb rustdesk-${{ env.VERSION }}.deb
|
||||||
|
|
||||||
|
- name: Patch archlinux PKGBUILD
|
||||||
|
if: matrix.job.arch == 'x86_64'
|
||||||
|
run: |
|
||||||
|
sed -i "s/x86_64/${{ matrix.job.arch }}/g" res/PKGBUILD
|
||||||
|
if [[ "${{ matrix.job.arch }}" == "aarch64" ]]; then
|
||||||
|
sed -i "s/linux\/x64/linux\/arm64/g" ./res/PKGBUILD
|
||||||
|
fi
|
||||||
|
bsdtar -zxvf rustdesk-${{ env.VERSION }}.deb
|
||||||
|
tar -xvf ./data.tar.xz
|
||||||
|
case ${{ matrix.job.arch }} in
|
||||||
|
aarch64)
|
||||||
|
mkdir -p flutter/build/linux/arm64/release/bundle
|
||||||
|
cp -rf usr/lib/rustdesk/* flutter/build/linux/arm64/release/bundle/
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
mkdir -p flutter/build/linux/x64/release/bundle
|
||||||
|
cp -rf usr/lib/rustdesk/* flutter/build/linux/x64/release/bundle/
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
- name: Build archlinux package
|
||||||
|
if: matrix.job.arch == 'x86_64'
|
||||||
|
uses: rustdesk-org/arch-makepkg-action@master
|
||||||
|
with:
|
||||||
|
packages: >
|
||||||
|
llvm
|
||||||
|
clang
|
||||||
|
libva
|
||||||
|
libvdpau
|
||||||
|
rust
|
||||||
|
gstreamer
|
||||||
|
unzip
|
||||||
|
git
|
||||||
|
cmake
|
||||||
|
gcc
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
nasm
|
||||||
|
zip
|
||||||
|
make
|
||||||
|
pkg-config
|
||||||
|
clang
|
||||||
|
gtk3
|
||||||
|
xdotool
|
||||||
|
libxcb
|
||||||
|
libxfixes
|
||||||
|
alsa-lib
|
||||||
|
pipewire
|
||||||
|
python
|
||||||
|
ttf-arphic-uming
|
||||||
|
libappindicator-gtk3
|
||||||
|
pam
|
||||||
|
gst-plugins-base
|
||||||
|
gst-plugin-pipewire
|
||||||
|
scripts: |
|
||||||
|
cd res && HBB=`pwd`/.. FLUTTER=1 makepkg -f
|
||||||
|
|
||||||
|
- name: Publish archlinux package
|
||||||
|
if: matrix.job.arch == 'x86_64'
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
prerelease: true
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
res/rustdesk-${{ env.VERSION }}*.zst
|
||||||
|
|
||||||
|
- name: Build appimage package
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# set-up appimage-builder
|
||||||
|
pushd /tmp
|
||||||
|
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
|
||||||
|
chmod +x appimage-builder-x86_64.AppImage
|
||||||
|
sudo mv appimage-builder-x86_64.AppImage /usr/local/bin/appimage-builder
|
||||||
|
popd
|
||||||
|
# run appimage-builder
|
||||||
|
pushd appimage
|
||||||
|
sudo appimage-builder --skip-tests --recipe ./AppImageBuilder-${{ matrix.job.arch }}.yml
|
||||||
|
|
||||||
|
- name: Publish appimage package
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
prerelease: true
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
./appimage/rustdesk-${{ env.VERSION }}-*.AppImage
|
||||||
|
|
||||||
|
build-flatpak:
|
||||||
|
name: Build Flatpak ${{ matrix.job.target }}
|
||||||
|
runs-on: ${{ matrix.job.on }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- {
|
||||||
|
target: x86_64-unknown-linux-gnu,
|
||||||
|
distro: ubuntu18.04,
|
||||||
|
on: ubuntu-20.04,
|
||||||
|
arch: x86_64,
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
target: aarch64-unknown-linux-gnu,
|
||||||
|
# try out newer flatpak since error of "error: Nothing matches org.freedesktop.Platform in remote flathub"
|
||||||
|
distro: ubuntu22.04,
|
||||||
|
on: [self-hosted, Linux, ARM64],
|
||||||
|
arch: aarch64,
|
||||||
|
}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Rename Binary
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y wget
|
||||||
|
wget https://github.com/rustdesk/rustdesk/releases/download/nightly/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb
|
||||||
|
mv rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb rustdesk-${{ env.VERSION }}.deb
|
||||||
|
|
||||||
|
- uses: rustdesk-org/run-on-arch-action@amd64-support
|
||||||
|
name: Build rustdesk flatpak package for ${{ matrix.job.arch }}
|
||||||
|
id: rpm
|
||||||
|
with:
|
||||||
|
arch: ${{ matrix.job.arch }}
|
||||||
|
distro: ${{ matrix.job.distro }}
|
||||||
|
githubToken: ${{ github.token }}
|
||||||
|
setup: |
|
||||||
|
ls -l "${PWD}"
|
||||||
|
dockerRunArgs: |
|
||||||
|
--volume "${PWD}:/workspace"
|
||||||
|
shell: /bin/bash
|
||||||
|
install: |
|
||||||
|
apt-get update -y
|
||||||
|
apt-get install -y \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
rpm \
|
||||||
|
wget
|
||||||
|
run: |
|
||||||
|
# disable git safe.directory
|
||||||
|
git config --global --add safe.directory "*"
|
||||||
|
pushd /workspace
|
||||||
|
# install
|
||||||
|
apt-get update -y
|
||||||
|
apt-get install -y \
|
||||||
|
cmake \
|
||||||
|
curl \
|
||||||
|
flatpak \
|
||||||
|
flatpak-builder \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
g++ \
|
||||||
|
libgtk-3-dev \
|
||||||
|
nasm \
|
||||||
|
wget
|
||||||
|
# flatpak deps
|
||||||
|
flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
|
flatpak --user install -y flathub org.freedesktop.Platform/${{ matrix.job.arch }}/23.08
|
||||||
|
flatpak --user install -y flathub org.freedesktop.Sdk/${{ matrix.job.arch }}/23.08
|
||||||
|
# package
|
||||||
|
pushd flatpak
|
||||||
|
git clone https://github.com/flathub/shared-modules.git --depth=1
|
||||||
|
flatpak-builder --user --force-clean --repo=repo ./build ./rustdesk.json
|
||||||
|
flatpak build-bundle ./repo rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.flatpak com.rustdesk.RustDesk
|
||||||
|
|
||||||
|
- name: Publish flatpak package
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
prerelease: true
|
||||||
|
tag_name: ${{ env.TAG_NAME }}
|
||||||
|
files: |
|
||||||
|
flatpak/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.flatpak
|
||||||
77
.github/workflows/ci.yml
vendored
@@ -1,8 +1,12 @@
|
|||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
# env:
|
env:
|
||||||
# MIN_SUPPORTED_RUST_VERSION: "1.46.0"
|
# MIN_SUPPORTED_RUST_VERSION: "1.46.0"
|
||||||
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
|
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||||
|
# vcpkg version: 2023.10.19
|
||||||
|
# for multiarch gcc compatibility
|
||||||
|
VCPKG_COMMIT_ID: "8eb57355a4ffb410a2e94c07b4dca2dffbee8e50"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -17,6 +21,9 @@ on:
|
|||||||
- ".github/**"
|
- ".github/**"
|
||||||
- "docs/**"
|
- "docs/**"
|
||||||
- "README.md"
|
- "README.md"
|
||||||
|
- "res/**"
|
||||||
|
- "appimage/**"
|
||||||
|
- "flatpak/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ensure_cargo_fmt:
|
# ensure_cargo_fmt:
|
||||||
@@ -67,45 +74,73 @@ jobs:
|
|||||||
# - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
# - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||||
# - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
|
# - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
|
||||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
# - { target: i686-pc-windows-msvc , os: windows-2022 }
|
||||||
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||||
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||||
# - { target: x86_64-apple-darwin , os: macos-10.15 }
|
# - { target: x86_64-apple-darwin , os: macos-10.15 }
|
||||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
# - { target: x86_64-pc-windows-gnu , os: windows-2022 }
|
||||||
# - { target: x86_64-pc-windows-msvc , os: windows-2019 }
|
# - { target: x86_64-pc-windows-msvc , os: windows-2022 }
|
||||||
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 }
|
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 }
|
||||||
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||||
steps:
|
steps:
|
||||||
|
- name: Export GitHub Actions cache environment variables
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||||
|
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||||
|
|
||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install prerequisites
|
- name: Install prerequisites
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
case ${{ matrix.job.target }} in
|
case ${{ matrix.job.target }} in
|
||||||
x86_64-unknown-linux-gnu) sudo apt-get -y update ; 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 libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev;;
|
x86_64-unknown-linux-gnu)
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
clang \
|
||||||
|
cmake \
|
||||||
|
curl \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
g++ \
|
||||||
|
libpam0g-dev \
|
||||||
|
libasound2-dev \
|
||||||
|
libgstreamer1.0-dev \
|
||||||
|
libgstreamer-plugins-base1.0-dev \
|
||||||
|
libgtk-3-dev \
|
||||||
|
libpulse-dev \
|
||||||
|
libxcb-randr0-dev \
|
||||||
|
libxcb-shape0-dev \
|
||||||
|
libxcb-xfixes0-dev \
|
||||||
|
libxdo-dev \
|
||||||
|
libxfixes-dev \
|
||||||
|
nasm \
|
||||||
|
wget
|
||||||
|
;;
|
||||||
# arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
|
# arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
|
||||||
# aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
|
# aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
- name: Restore from cache and install vcpkg
|
- name: Setup vcpkg with Github Actions binary cache
|
||||||
uses: lukka/run-vcpkg@v7
|
uses: lukka/run-vcpkg@v11
|
||||||
with:
|
with:
|
||||||
setupOnly: true
|
vcpkgDirectory: /opt/artifacts/vcpkg
|
||||||
vcpkgGitCommitId: '501db0f17ef6df184fcdbfbe0f87cde2313b6ab1' #2023.04.15
|
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||||
|
|
||||||
- name: Install vcpkg dependencies
|
- name: Install vcpkg dependencies
|
||||||
run: |
|
run: |
|
||||||
$VCPKG_ROOT/vcpkg install libvpx libyuv opus aom
|
$VCPKG_ROOT/vcpkg install --x-install-root="$VCPKG_ROOT/installed"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
target: ${{ matrix.job.target }}
|
targets: ${{ matrix.job.target }}
|
||||||
override: true
|
components: ''
|
||||||
profile: minimal # minimal component installation (ie, no documentation)
|
|
||||||
|
|
||||||
- name: Show version information (Rust, cargo, GCC)
|
- name: Show version information (Rust, cargo, GCC)
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -117,8 +152,8 @@ jobs:
|
|||||||
cargo -V
|
cargo -V
|
||||||
rustc -V
|
rustc -V
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
@@ -183,7 +218,9 @@ jobs:
|
|||||||
;;
|
;;
|
||||||
esac;
|
esac;
|
||||||
|
|
||||||
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
#deprecated echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
||||||
|
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_ENV
|
||||||
|
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
|||||||
37
.github/workflows/clear-cache.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: Clear cache
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clear-cache:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Clear cache
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
console.log("About to clear")
|
||||||
|
const caches = await github.rest.actions.getActionsCacheList({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
})
|
||||||
|
for (const cache of caches.data.actions_caches) {
|
||||||
|
console.log(cache)
|
||||||
|
github.rest.actions.deleteActionsCacheById({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
cache_id: cache.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log("Clear completed")
|
||||||
|
|
||||||
|
- name: Purge cache # Above seems not clear thouroughly, so add this to double clear
|
||||||
|
uses: MyAlbum/purge-cache@v2
|
||||||
|
with:
|
||||||
|
accessed: true # Purge caches by their last accessed time (default)
|
||||||
|
created: false # Purge caches by their created time (default)
|
||||||
|
max-age: 1 # in seconds
|
||||||
2054
.github/workflows/flutter-build.yml
vendored
4
.github/workflows/flutter-ci.yml
vendored
@@ -13,10 +13,12 @@ on:
|
|||||||
- ".github/**"
|
- ".github/**"
|
||||||
- "docs/**"
|
- "docs/**"
|
||||||
- "README.md"
|
- "README.md"
|
||||||
|
- "res/**"
|
||||||
|
- "appimage/**"
|
||||||
|
- "flatpak/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-ci:
|
run-ci:
|
||||||
uses: ./.github/workflows/flutter-build.yml
|
uses: ./.github/workflows/flutter-build.yml
|
||||||
with:
|
with:
|
||||||
upload-artifact: false
|
upload-artifact: false
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/flutter-nightly.yml
vendored
@@ -12,4 +12,4 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
upload-artifact: true
|
upload-artifact: true
|
||||||
upload-tag: "nightly"
|
upload-tag: "nightly"
|
||||||
|
|||||||
2
.github/workflows/flutter-tag.yml
vendored
@@ -15,4 +15,4 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
upload-artifact: true
|
upload-artifact: true
|
||||||
upload-tag: "1.2.2"
|
upload-tag: ${{ github.ref_name }}
|
||||||
34
.github/workflows/history.yml
vendored
@@ -4,13 +4,11 @@ on: [workflow_dispatch]
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
LLVM_VERSION: "10.0"
|
LLVM_VERSION: "10.0"
|
||||||
FLUTTER_VERSION: "3.10.6"
|
FLUTTER_VERSION: "3.16.9"
|
||||||
TAG_NAME: "tmp"
|
TAG_NAME: "tmp"
|
||||||
FLUTTER_RUST_BRIDGE_VERSION: "1.75.3"
|
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
|
||||||
# vcpkg version: 2022.05.10
|
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||||
# for multiarch gcc compatibility
|
VERSION: "1.2.5"
|
||||||
VCPKG_COMMIT_ID: "501db0f17ef6df184fcdbfbe0f87cde2313b6ab1"
|
|
||||||
VERSION: "1.2.2"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-for-history-windows:
|
build-for-history-windows:
|
||||||
@@ -20,10 +18,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
job:
|
job:
|
||||||
- { target: x86_64-pc-windows-msvc, os: windows-2019, arch: x86_64, date: 2023-08-04, ref: 72c198a1e94cc1e0242fce88f92b3f3caedcd0c3 }
|
- { target: x86_64-pc-windows-msvc, os: windows-2022, arch: x86_64, date: 2023-08-04, ref: 72c198a1e94cc1e0242fce88f92b3f3caedcd0c3 }
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ matrix.job.ref }}
|
ref: ${{ matrix.job.ref }}
|
||||||
|
|
||||||
@@ -33,7 +31,7 @@ jobs:
|
|||||||
version: ${{ env.LLVM_VERSION }}
|
version: ${{ env.LLVM_VERSION }}
|
||||||
|
|
||||||
- name: Install flutter
|
- name: Install flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2.12.0 #https://github.com/subosito/flutter-action/issues/277
|
||||||
with:
|
with:
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
@@ -54,15 +52,19 @@ jobs:
|
|||||||
Push-Location flutter ; flutter pub get ; 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
|
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
|
||||||
|
|
||||||
|
- name: Setup vcpkg with Github Actions binary cache
|
||||||
|
uses: lukka/run-vcpkg@v11
|
||||||
|
with:
|
||||||
|
vcpkgDirectory: C:\vcpkg
|
||||||
|
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||||
|
|
||||||
- name: Install vcpkg dependencies
|
- name: Install vcpkg dependencies
|
||||||
run: |
|
run: |
|
||||||
cd C:\
|
$VCPKG_ROOT/vcpkg install --x-install-root="$VCPKG_ROOT/installed"
|
||||||
git clone https://github.com/Kingtous/rustdesk_thirdpary_lib --depth=1
|
shell: bash
|
||||||
|
|
||||||
- name: Build rustdesk
|
- name: Build rustdesk
|
||||||
env:
|
run: python3 .\build.py --portable --hwcodec --flutter
|
||||||
VCPKG_ROOT: C:\rustdesk_thirdpary_lib\vcpkg
|
|
||||||
run: python3 .\build.py --portable --hwcodec --flutter --feature IddDriver
|
|
||||||
|
|
||||||
- name: Build self-extracted executable
|
- name: Build self-extracted executable
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -72,7 +74,7 @@ jobs:
|
|||||||
popd
|
popd
|
||||||
mkdir -p ./SignOutput
|
mkdir -p ./SignOutput
|
||||||
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-${{ matrix.job.date }}-${{ matrix.job.target }}.exe
|
mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-${{ matrix.job.date }}-${{ matrix.job.target }}.exe
|
||||||
|
|
||||||
- name: Publish Release
|
- name: Publish Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
60
.github/workflows/third-party-RustDeskTempTopMostWindow.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
name: build RustDeskTempTopMostWindow
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
upload-artifact:
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
target:
|
||||||
|
description: 'Target'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'windows-2022'
|
||||||
|
configuration:
|
||||||
|
description: 'Configuration'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'Release'
|
||||||
|
platform:
|
||||||
|
description: 'Platform'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'x64'
|
||||||
|
target_version:
|
||||||
|
description: 'TargetVersion'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'Windows10'
|
||||||
|
|
||||||
|
env:
|
||||||
|
project_path: WindowInjection/WindowInjection.vcxproj
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-RustDeskTempTopMostWindow:
|
||||||
|
runs-on: ${{ inputs.target }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
env:
|
||||||
|
build_output_dir: RustDeskTempTopMostWindow/WindowInjection/${{ inputs.platform }}/${{ inputs.configuration }}
|
||||||
|
steps:
|
||||||
|
- name: Add MSBuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
|
- name: Download the source code
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/rustdesk-org/RustDeskTempTopMostWindow RustDeskTempTopMostWindow
|
||||||
|
|
||||||
|
# Build. commit 53b548a5398624f7149a382000397993542ad796 is tag v0.3
|
||||||
|
- name: Build the project
|
||||||
|
run: |
|
||||||
|
cd RustDeskTempTopMostWindow && git checkout 53b548a5398624f7149a382000397993542ad796
|
||||||
|
msbuild ${{ env.project_path }} -p:Configuration=${{ inputs.configuration }} -p:Platform=${{ inputs.platform }} /p:TargetVersion=${{ inputs.target_version }}
|
||||||
|
|
||||||
|
- name: Archive build artifacts
|
||||||
|
uses: actions/upload-artifact@master
|
||||||
|
if: ${{ inputs.upload-artifact }}
|
||||||
|
with:
|
||||||
|
name: topmostwindow-artifacts
|
||||||
|
path: |
|
||||||
|
./${{ env.build_output_dir }}/WindowInjection.dll
|
||||||
88
.github/workflows/vcpkg-deps-linux.yml
vendored
@@ -1,88 +0,0 @@
|
|||||||
name: Build vcpkg dependencies for linux clients
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-vcpkg-deps-linux:
|
|
||||||
runs-on: ${{ matrix.job.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: true
|
|
||||||
matrix:
|
|
||||||
job:
|
|
||||||
- { arch: armv7, os: ubuntu-20.04 }
|
|
||||||
- { arch: x86_64, os: ubuntu-20.04 }
|
|
||||||
- { arch: aarch64, os: ubuntu-20.04 }
|
|
||||||
steps:
|
|
||||||
- name: Create vcpkg artifacts folder
|
|
||||||
run: mkdir -p /opt/artifacts
|
|
||||||
|
|
||||||
- name: Cache Vcpkg
|
|
||||||
id: cache-vcpkg
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: /opt/artifacts
|
|
||||||
key: vcpkg-${{ matrix.job.arch }}
|
|
||||||
|
|
||||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
|
||||||
name: Run vcpkg install on ${{ matrix.job.arch }}
|
|
||||||
id: vcpkg
|
|
||||||
with:
|
|
||||||
arch: ${{ matrix.job.arch }}
|
|
||||||
distro: ubuntu18.04
|
|
||||||
githubToken: ${{ github.token }}
|
|
||||||
setup: |
|
|
||||||
ls -l "/opt/artifacts"
|
|
||||||
dockerRunArgs: |
|
|
||||||
--volume "/opt/artifacts:/artifacts"
|
|
||||||
shell: /bin/bash
|
|
||||||
install: |
|
|
||||||
apt update -y
|
|
||||||
case "${{ matrix.job.arch }}" in
|
|
||||||
x86_64)
|
|
||||||
# CMake 3.15+
|
|
||||||
apt install -y gpg wget ca-certificates
|
|
||||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
|
||||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
|
||||||
apt update -y
|
|
||||||
apt install -y curl zip unzip tar git cmake g++ gcc build-essential pkg-config wget nasm yasm ninja-build libjpeg8-dev
|
|
||||||
cmake --version
|
|
||||||
gcc -v
|
|
||||||
;;
|
|
||||||
aarch64|armv7)
|
|
||||||
apt install -y curl zip unzip git
|
|
||||||
esac
|
|
||||||
run: |
|
|
||||||
# disable git safe.directory
|
|
||||||
git config --global --add safe.directory "*"
|
|
||||||
case "${{ matrix.job.arch }}" in
|
|
||||||
x86_64)
|
|
||||||
export VCPKG_FORCE_SYSTEM_BINARIES=1
|
|
||||||
pushd /artifacts
|
|
||||||
git clone https://github.com/microsoft/vcpkg.git || true
|
|
||||||
pushd vcpkg
|
|
||||||
git reset --hard ${{ env.VCPKG_COMMIT_ID }}
|
|
||||||
./bootstrap-vcpkg.sh
|
|
||||||
./vcpkg install libvpx libyuv opus aom
|
|
||||||
;;
|
|
||||||
aarch64)
|
|
||||||
pushd /artifacts
|
|
||||||
rm -rf rustdesk_thirdparty_lib
|
|
||||||
git clone https://github.com/Kingtous/rustdesk_thirdparty_lib.git --depth=1
|
|
||||||
mkdir -p /artifacts/vcpkg/installed
|
|
||||||
mv ./rustdesk_thirdparty_lib/vcpkg/installed/arm64-linux /artifacts/vcpkg/installed/arm64-linux
|
|
||||||
;;
|
|
||||||
armv7)
|
|
||||||
pushd /artifacts
|
|
||||||
rm -rf rustdesk_thirdparty_lib
|
|
||||||
git clone https://github.com/Kingtous/rustdesk_thirdparty_lib.git --depth=1
|
|
||||||
mkdir -p /artifacts/vcpkg/installed
|
|
||||||
mv ./rustdesk_thirdparty_lib/vcpkg/installed/arm-linux /artifacts/vcpkg/installed/arm-linux
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@master
|
|
||||||
with:
|
|
||||||
name: vcpkg-artifact-${{ matrix.job.arch }}
|
|
||||||
path: |
|
|
||||||
/opt/artifacts/vcpkg/installed
|
|
||||||
6
.gitignore
vendored
@@ -49,4 +49,8 @@ lib/generated_bridge.dart
|
|||||||
.ssh
|
.ssh
|
||||||
.devcontainer/.*
|
.devcontainer/.*
|
||||||
# build cache in examples
|
# build cache in examples
|
||||||
examples/**/target/
|
examples/**/target/
|
||||||
|
# ===
|
||||||
|
vcpkg_installed
|
||||||
|
flutter/lib/generated_plugin_registrant.dart
|
||||||
|
libsciter.dylib
|
||||||
|
|||||||
3762
Cargo.lock
generated
90
Cargo.toml
@@ -1,11 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rustdesk"
|
name = "rustdesk"
|
||||||
version = "1.2.2"
|
version = "1.2.5"
|
||||||
authors = ["rustdesk <info@rustdesk.com>"]
|
authors = ["rustdesk <info@rustdesk.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
build= "build.rs"
|
build= "build.rs"
|
||||||
description = "A remote control software."
|
description = "RustDesk Remote Desktop"
|
||||||
default-run = "rustdesk"
|
default-run = "rustdesk"
|
||||||
|
rust-version = "1.75"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "librustdesk"
|
name = "librustdesk"
|
||||||
@@ -18,25 +19,29 @@ path = "src/naming.rs"
|
|||||||
[features]
|
[features]
|
||||||
inline = []
|
inline = []
|
||||||
cli = []
|
cli = []
|
||||||
flutter_texture_render = []
|
|
||||||
appimage = []
|
|
||||||
flatpak = []
|
|
||||||
use_samplerate = ["samplerate"]
|
use_samplerate = ["samplerate"]
|
||||||
use_rubato = ["rubato"]
|
use_rubato = ["rubato"]
|
||||||
use_dasp = ["dasp"]
|
use_dasp = ["dasp"]
|
||||||
flutter = ["flutter_rust_bridge"]
|
flutter = ["flutter_rust_bridge"]
|
||||||
default = ["use_dasp"]
|
default = ["use_dasp"]
|
||||||
hwcodec = ["scrap/hwcodec"]
|
hwcodec = ["scrap/hwcodec"]
|
||||||
|
vram = ["scrap/vram"]
|
||||||
mediacodec = ["scrap/mediacodec"]
|
mediacodec = ["scrap/mediacodec"]
|
||||||
linux_headless = ["pam" ]
|
|
||||||
virtual_display_driver = ["virtual_display"]
|
|
||||||
plugin_framework = []
|
plugin_framework = []
|
||||||
linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"]
|
linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"]
|
||||||
|
unix-file-copy-paste = [
|
||||||
|
"dep:x11-clipboard",
|
||||||
|
"dep:x11rb",
|
||||||
|
"dep:percent-encoding",
|
||||||
|
"dep:once_cell",
|
||||||
|
"clipboard/unix-file-copy-paste",
|
||||||
|
]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
whoami = "1.4"
|
async-trait = "0.1"
|
||||||
|
whoami = "1.5.0"
|
||||||
scrap = { path = "libs/scrap", features = ["wayland"] }
|
scrap = { path = "libs/scrap", features = ["wayland"] }
|
||||||
hbb_common = { path = "libs/hbb_common" }
|
hbb_common = { path = "libs/hbb_common" }
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
@@ -47,33 +52,31 @@ cfg-if = "1.0"
|
|||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
repng = "0.2"
|
repng = "0.2"
|
||||||
parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" }
|
parity-tokio-ipc = { git = "https://github.com/rustdesk-org/parity-tokio-ipc" }
|
||||||
runas = "=1.0" # https://github.com/mitsuhiko/rust-runas/issues/13
|
magnum-opus = { git = "https://github.com/rustdesk-org/magnum-opus" }
|
||||||
magnum-opus = { git = "https://github.com/rustdesk/magnum-opus" }
|
|
||||||
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true }
|
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true }
|
||||||
rubato = { version = "0.12", optional = true }
|
rubato = { version = "0.12", optional = true }
|
||||||
samplerate = { version = "0.2", optional = true }
|
samplerate = { version = "0.2", optional = true }
|
||||||
async-trait = "0.1"
|
|
||||||
uuid = { version = "1.3", features = ["v4"] }
|
uuid = { version = "1.3", features = ["v4"] }
|
||||||
clap = "4.2"
|
clap = "4.2"
|
||||||
rpassword = "7.2"
|
rpassword = "7.2"
|
||||||
base64 = "0.21"
|
|
||||||
num_cpus = "1.15"
|
num_cpus = "1.15"
|
||||||
bytes = { version = "1.4", features = ["serde"] }
|
bytes = { version = "1.4", features = ["serde"] }
|
||||||
default-net = "0.14"
|
default-net = "0.14"
|
||||||
wol-rs = "1.0"
|
wol-rs = "1.0"
|
||||||
flutter_rust_bridge = { version = "1.75", features = ["uuid"], optional = true}
|
flutter_rust_bridge = { version = "=1.80", features = ["uuid"], optional = true}
|
||||||
errno = "0.3"
|
errno = "0.3"
|
||||||
rdev = { git = "https://github.com/fufesou/rdev" }
|
rdev = { git = "https://github.com/fufesou/rdev" }
|
||||||
url = { version = "2.3", features = ["serde"] }
|
url = { version = "2.3", features = ["serde"] }
|
||||||
crossbeam-queue = "0.3"
|
crossbeam-queue = "0.3"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "json", "rustls-tls"], default-features=false }
|
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
cidr-utils = "0.5"
|
cidr-utils = "0.5"
|
||||||
libloading = "0.8"
|
libloading = "0.8"
|
||||||
fon = "0.6"
|
fon = "0.6"
|
||||||
zip = "0.6"
|
zip = "0.6"
|
||||||
|
shutdown_hooks = "0.1"
|
||||||
|
totp-rs = { version = "5.4", default-features = false, features = ["gen_secret", "otpauth"] }
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
|
||||||
cpal = "0.15"
|
cpal = "0.15"
|
||||||
@@ -86,17 +89,32 @@ sys-locale = "0.3"
|
|||||||
enigo = { path = "libs/enigo", features = [ "with_serde" ] }
|
enigo = { path = "libs/enigo", features = [ "with_serde" ] }
|
||||||
clipboard = { path = "libs/clipboard" }
|
clipboard = { path = "libs/clipboard" }
|
||||||
ctrlc = "3.2"
|
ctrlc = "3.2"
|
||||||
arboard = "3.2"
|
arboard = { git = "https://github.com/fufesou/arboard", branch = "feat/x11_set_conn_timeout", features = ["wayland-data-control"] }
|
||||||
system_shutdown = "4.0"
|
system_shutdown = "4.0"
|
||||||
|
qrcode-generator = "4.1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi"] }
|
winapi = { version = "0.3", features = [
|
||||||
|
"winuser",
|
||||||
|
"wincrypt",
|
||||||
|
"shellscalingapi",
|
||||||
|
"pdh",
|
||||||
|
"synchapi",
|
||||||
|
"memoryapi",
|
||||||
|
"shellapi",
|
||||||
|
"devguid",
|
||||||
|
"setupapi",
|
||||||
|
"cguid",
|
||||||
|
"cfgmgr32",
|
||||||
|
"ioapiset",
|
||||||
|
] }
|
||||||
winreg = "0.11"
|
winreg = "0.11"
|
||||||
windows-service = "0.6"
|
windows-service = "0.6"
|
||||||
virtual_display = { path = "libs/virtual_display", optional = true }
|
virtual_display = { path = "libs/virtual_display" }
|
||||||
impersonate_system = { git = "https://github.com/21pages/impersonate-system" }
|
impersonate_system = { git = "https://github.com/21pages/impersonate-system" }
|
||||||
shared_memory = "0.12"
|
shared_memory = "0.12"
|
||||||
shutdown_hooks = "0.1"
|
tauri-winrt-notification = "0.1.2"
|
||||||
|
runas = "1.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
objc = "0.2"
|
objc = "0.2"
|
||||||
@@ -105,18 +123,27 @@ dispatch = "0.2"
|
|||||||
core-foundation = "0.9"
|
core-foundation = "0.9"
|
||||||
core-graphics = "0.22"
|
core-graphics = "0.22"
|
||||||
include_dir = "0.7"
|
include_dir = "0.7"
|
||||||
dark-light = "1.0"
|
|
||||||
fruitbasket = "0.10"
|
fruitbasket = "0.10"
|
||||||
objc_id = "0.1"
|
objc_id = "0.1"
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
||||||
tray-icon = { git = "https://github.com/rustdesk-org/tray-icon" }
|
tray-icon = { git = "https://github.com/tauri-apps/tray-icon" }
|
||||||
tao = { git = "https://github.com/rustdesk-org/tao", branch = "dev" }
|
tao = { git = "https://github.com/rustdesk-org/tao", branch = "dev" }
|
||||||
image = "0.24"
|
image = "0.24"
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies]
|
[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies]
|
||||||
keepawake = { git = "https://github.com/rustdesk-org/keepawake-rs" }
|
keepawake = { git = "https://github.com/rustdesk-org/keepawake-rs" }
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
|
||||||
|
wallpaper = { git = "https://github.com/21pages/wallpaper.rs" }
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
|
||||||
|
# https://github.com/rustdesk/rustdesk-server-pro/issues/189, using native-tls for better tls support
|
||||||
|
reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "socks", "json", "native-tls", "gzip"], default-features=false }
|
||||||
|
|
||||||
|
[target.'cfg(not(any(target_os = "macos", target_os = "windows")))'.dependencies]
|
||||||
|
reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "socks", "json", "rustls-tls", "rustls-tls-native-roots", "gzip"], default-features=false }
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
psimple = { package = "libpulse-simple-binding", version = "2.27" }
|
psimple = { package = "libpulse-simple-binding", version = "2.27" }
|
||||||
pulse = { package = "libpulse-binding", version = "2.27" }
|
pulse = { package = "libpulse-binding", version = "2.27" }
|
||||||
@@ -126,30 +153,35 @@ mouce = { git="https://github.com/fufesou/mouce.git" }
|
|||||||
evdev = { git="https://github.com/fufesou/evdev" }
|
evdev = { git="https://github.com/fufesou/evdev" }
|
||||||
dbus = "0.9"
|
dbus = "0.9"
|
||||||
dbus-crossroads = "0.5"
|
dbus-crossroads = "0.5"
|
||||||
pam = { git="https://github.com/fufesou/pam", optional = true }
|
pam = { git="https://github.com/fufesou/pam" }
|
||||||
users = { version = "0.11" }
|
users = { version = "0.11" }
|
||||||
|
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true}
|
||||||
|
x11rb = {version = "0.12", features = ["all-extensions"], optional = true}
|
||||||
|
percent-encoding = {version = "2.3", optional = true}
|
||||||
|
once_cell = {version = "1.18", optional = true}
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
android_logger = "0.13"
|
android_logger = "0.13"
|
||||||
jni = "0.21"
|
jni = "0.21"
|
||||||
|
android-wakelock = { git = "https://github.com/21pages/android-wakelock" }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable"]
|
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable"]
|
||||||
exclude = ["vdi/host", "examples/custom_plugin"]
|
exclude = ["vdi/host", "examples/custom_plugin"]
|
||||||
|
|
||||||
[package.metadata.winres]
|
[package.metadata.winres]
|
||||||
LegalCopyright = "Copyright © 2023 Purslane, Inc."
|
LegalCopyright = "Copyright © 2024 Purslane Ltd. All rights reserved."
|
||||||
# this FileDescription overrides package.description
|
ProductName = "RustDesk"
|
||||||
FileDescription = "RustDesk"
|
FileDescription = "RustDesk Remote Desktop"
|
||||||
|
OriginalFilename = "rustdesk.exe"
|
||||||
|
|
||||||
[target.'cfg(target_os="windows")'.build-dependencies]
|
[target.'cfg(target_os="windows")'.build-dependencies]
|
||||||
winres = "0.1"
|
winres = "0.1"
|
||||||
winapi = { version = "0.3", features = [ "winnt" ] }
|
winapi = { version = "0.3", features = [ "winnt", "pdh", "synchapi" ] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
hbb_common = { path = "libs/hbb_common" }
|
hbb_common = { path = "libs/hbb_common" }
|
||||||
flutter_rust_bridge_codegen = "1.75"
|
|
||||||
os-version = "0.2"
|
os-version = "0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@@ -169,3 +201,7 @@ panic = 'abort'
|
|||||||
strip = true
|
strip = true
|
||||||
#opt-level = 'z' # only have smaller size after strip
|
#opt-level = 'z' # only have smaller size after strip
|
||||||
rpath = true
|
rpath = true
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
split-debuginfo = '...' # Platform-specific.
|
||||||
|
#strip = "debuginfo"
|
||||||
|
|||||||
56
Dockerfile
@@ -1,21 +1,55 @@
|
|||||||
FROM debian
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
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/*
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt update -y && \
|
||||||
|
apt install --yes --no-install-recommends \
|
||||||
|
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 \
|
||||||
|
libpam0g-dev \
|
||||||
|
libpulse-dev \
|
||||||
|
make \
|
||||||
|
cmake \
|
||||||
|
unzip \
|
||||||
|
zip \
|
||||||
|
sudo \
|
||||||
|
libgstreamer1.0-dev \
|
||||||
|
libgstreamer-plugins-base1.0-dev \
|
||||||
|
ca-certificates \
|
||||||
|
ninja-build && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN git clone --branch 2023.04.15 --depth=1 https://github.com/microsoft/vcpkg
|
RUN git clone --branch 2023.04.15 --depth=1 https://github.com/microsoft/vcpkg && \
|
||||||
RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics
|
/vcpkg/bootstrap-vcpkg.sh -disableMetrics && \
|
||||||
RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus aom
|
/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/rustdesk && \
|
||||||
|
chown -R user: /home/user && \
|
||||||
|
echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user
|
||||||
|
|
||||||
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
|
WORKDIR /home/user
|
||||||
RUN curl -LO 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
|
USER user
|
||||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh && \
|
||||||
RUN chmod +x rustup.sh
|
chmod +x rustup.sh && \
|
||||||
RUN ./rustup.sh -y
|
./rustup.sh -y
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
ENV HOME=/home/user
|
ENV HOME=/home/user
|
||||||
COPY ./entrypoint /
|
COPY ./entrypoint.sh /
|
||||||
ENTRYPOINT ["/entrypoint"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|||||||
66
README.md
@@ -5,7 +5,7 @@
|
|||||||
<a href="#how-to-build-with-docker">Docker</a> •
|
<a href="#how-to-build-with-docker">Docker</a> •
|
||||||
<a href="#file-structure">Structure</a> •
|
<a href="#file-structure">Structure</a> •
|
||||||
<a href="#snapshot">Snapshot</a><br>
|
<a href="#snapshot">Snapshot</a><br>
|
||||||
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>]<br>
|
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>]<br>
|
||||||
<b>We need your help to translate this README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> and <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> to your native language</b>
|
<b>We need your help to translate this README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> and <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> to your native language</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -29,25 +29,9 @@ RustDesk welcomes contribution from everyone. See [CONTRIBUTING.md](docs/CONTRIB
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Free Public Servers
|
|
||||||
|
|
||||||
Below are the servers you are using for free, they may change over time. If you are not close to one of these, your network may be slow.
|
|
||||||
| Location | Vendor | Specification |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| 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)
|
|
||||||
|
|
||||||
If you already have VS Code and Docker installed, you can click the badge above to get started. Clicking will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use.
|
|
||||||
|
|
||||||
Go through [DEVCONTAINER.md](docs/DEVCONTAINER.md) for more info.
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Desktop versions use [Sciter](https://sciter.com/) or Flutter for GUI, this tutorial is for Sciter only.
|
Desktop versions use Flutter or Sciter (deprecated) for GUI, this tutorial is for Sciter only, since it is easier and more friendly to start. Check out our [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for building Flutter version.
|
||||||
|
|
||||||
Please download Sciter dynamic library yourself.
|
Please download Sciter dynamic library yourself.
|
||||||
|
|
||||||
@@ -78,11 +62,12 @@ sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxc
|
|||||||
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### openSUSE Tumbleweed
|
### openSUSE Tumbleweed
|
||||||
|
|
||||||
```sh
|
```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
|
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)
|
### Fedora 28 (CentOS 8)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -133,34 +118,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Change Wayland to X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session.
|
|
||||||
|
|
||||||
## Wayland support
|
|
||||||
|
|
||||||
Wayland does not seem to provide any API for sending keypresses to other windows. Therefore, the RustDesk uses an API from a lower level, namely the `/dev/uinput` device (Linux kernel level).
|
|
||||||
|
|
||||||
When Wayland is the controlled side, you have to start in the following way:
|
|
||||||
```bash
|
|
||||||
# Start uinput service
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Notice**: Wayland screen recording uses different interfaces. RustDesk currently only supports 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## How to build with Docker
|
## How to build with Docker
|
||||||
|
|
||||||
Begin by cloning the repository and building the Docker container:
|
Begin by cloning the repository and building the Docker container:
|
||||||
@@ -196,20 +153,21 @@ Please ensure that you are running these commands from the root of the RustDesk
|
|||||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions
|
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions
|
||||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: screen capture
|
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: screen capture
|
||||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control
|
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control
|
||||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: file copy and paste implementation for Windows, Linux, macOS.
|
||||||
|
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: obsolete Sciter UI (deprecated)
|
||||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections
|
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections
|
||||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection
|
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection
|
||||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
|
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
|
||||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
|
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
|
||||||
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for mobile
|
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for desktop and mobile
|
||||||
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter web client
|
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter web client
|
||||||
|
|
||||||
## Snapshots
|
## Screenshots
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
script:
|
script:
|
||||||
- rm -rf ./AppDir || true
|
- rm -rf ./AppDir || true
|
||||||
- bsdtar -zxvf ../rustdesk-1.2.2.deb
|
- bsdtar -zxvf rustdesk.deb
|
||||||
- tar -xvf ./data.tar.xz
|
- tar -xvf ./data.tar.xz
|
||||||
- mkdir ./AppDir
|
- mkdir ./AppDir
|
||||||
- mv ./usr ./AppDir/usr
|
- mv ./usr ./AppDir/usr
|
||||||
@@ -18,7 +18,7 @@ AppDir:
|
|||||||
id: rustdesk
|
id: rustdesk
|
||||||
name: rustdesk
|
name: rustdesk
|
||||||
icon: rustdesk
|
icon: rustdesk
|
||||||
version: 1.2.2
|
version: 1.2.5
|
||||||
exec: usr/lib/rustdesk/rustdesk
|
exec: usr/lib/rustdesk/rustdesk
|
||||||
exec_args: $@
|
exec_args: $@
|
||||||
apt:
|
apt:
|
||||||
@@ -26,18 +26,18 @@ AppDir:
|
|||||||
- arm64
|
- arm64
|
||||||
allow_unauthenticated: true
|
allow_unauthenticated: true
|
||||||
sources:
|
sources:
|
||||||
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe multiverse
|
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ focal main restricted universe multiverse
|
||||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
||||||
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe multiverse
|
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ focal-updates main restricted universe multiverse
|
||||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
||||||
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
|
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ focal-backports main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
||||||
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted
|
- sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ focal-security main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32'
|
||||||
include:
|
include:
|
||||||
- libc6
|
- libc6:arm64
|
||||||
- libgtk-3-0
|
- libgtk-3-0
|
||||||
- libxcb-randr0
|
- libxcb-randr0
|
||||||
- libxdo3
|
- libxdo3
|
||||||
@@ -51,9 +51,15 @@ AppDir:
|
|||||||
- libva-x11-2
|
- libva-x11-2
|
||||||
- libvdpau1
|
- libvdpau1
|
||||||
- libgstreamer-plugins-base1.0-0
|
- libgstreamer-plugins-base1.0-0
|
||||||
|
- gstreamer1.0-pipewire
|
||||||
|
- libwayland-client0
|
||||||
- libwayland-cursor0
|
- libwayland-cursor0
|
||||||
- libwayland-egl1
|
- libwayland-egl1
|
||||||
- libpulse0
|
- libpulse0
|
||||||
|
- packagekit-gtk3-module
|
||||||
|
- libcanberra-gtk3-module
|
||||||
|
- libpam0g
|
||||||
|
- libdrm2
|
||||||
exclude:
|
exclude:
|
||||||
- humanity-icon-theme
|
- humanity-icon-theme
|
||||||
- hicolor-icon-theme
|
- hicolor-icon-theme
|
||||||
@@ -69,8 +75,11 @@ AppDir:
|
|||||||
- usr/share/doc/*/TODO.*
|
- usr/share/doc/*/TODO.*
|
||||||
runtime:
|
runtime:
|
||||||
env:
|
env:
|
||||||
GIO_MODULE_DIR: $APPDIR/usr/lib/x86_64-linux-gnu/gio/modules/
|
GIO_MODULE_DIR: /lib64/gio/modules:/usr/lib/aarch64-linux-gnu/gio/modules:$APPDIR/usr/lib/aarch64-linux-gnu/gio/modules
|
||||||
GDK_BACKEND: x11
|
GDK_BACKEND: x11
|
||||||
|
APPDIR_LIBRARY_PATH: /lib64:/usr/lib/aarch64-linux-gnu:$APPDIR/lib/aarch64-linux-gnu:$APPDIR/lib/aarch64-linux-gnu/security:$APPDIR/lib/systemd:$APPDIR/usr/lib/aarch64-linux-gnu:$APPDIR/usr/lib/aarch64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders:$APPDIR/usr/lib/aarch64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/aarch64-linux-gnu/gtk-3.0/3.0.0/immodules:$APPDIR/usr/lib/aarch64-linux-gnu/gtk-3.0/3.0.0/printbackends:$APPDIR/usr/lib/aarch64-linux-gnu/krb5/plugins/preauth:$APPDIR/usr/lib/aarch64-linux-gnu/libcanberra-0.30:$APPDIR/usr/lib/aarch64-linux-gnu/pulseaudio:$APPDIR/usr/lib/aarch64-linux-gnu/sasl2:$APPDIR/usr/lib/aarch64-linux-gnu/vdpau:$APPDIR/usr/lib/rustdesk/lib:$APPDIR/lib/aarch64
|
||||||
|
GST_PLUGIN_PATH: /lib64/gstreamer-1.0:/usr/lib/aarch64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/aarch64-linux-gnu/gstreamer-1.0
|
||||||
|
GST_PLUGIN_SYSTEM_PATH: /lib64/gstreamer-1.0:/usr/lib/aarch64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/aarch64-linux-gnu/gstreamer-1.0
|
||||||
test:
|
test:
|
||||||
fedora-30:
|
fedora-30:
|
||||||
image: appimagecrafters/tests-env:fedora-30
|
image: appimagecrafters/tests-env:fedora-30
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
script:
|
script:
|
||||||
- rm -rf ./AppDir || true
|
- rm -rf ./AppDir || true
|
||||||
- bsdtar -zxvf ../rustdesk-1.2.2.deb
|
- bsdtar -zxvf rustdesk.deb
|
||||||
- tar -xvf ./data.tar.xz
|
- tar -xvf ./data.tar.xz
|
||||||
- mkdir ./AppDir
|
- mkdir ./AppDir
|
||||||
- mv ./usr ./AppDir/usr
|
- mv ./usr ./AppDir/usr
|
||||||
@@ -18,7 +18,7 @@ AppDir:
|
|||||||
id: rustdesk
|
id: rustdesk
|
||||||
name: rustdesk
|
name: rustdesk
|
||||||
icon: rustdesk
|
icon: rustdesk
|
||||||
version: 1.2.2
|
version: 1.2.5
|
||||||
exec: usr/lib/rustdesk/rustdesk
|
exec: usr/lib/rustdesk/rustdesk
|
||||||
exec_args: $@
|
exec_args: $@
|
||||||
apt:
|
apt:
|
||||||
@@ -26,18 +26,16 @@ AppDir:
|
|||||||
- amd64
|
- amd64
|
||||||
allow_unauthenticated: true
|
allow_unauthenticated: true
|
||||||
sources:
|
sources:
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal main restricted
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic universe
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal universe
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates universe
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates universe
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic multiverse
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal multiverse
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates multiverse
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates multiverse
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
- sourceline: deb http://ppa.launchpad.net/pipewire-debian/pipewire-upstream/ubuntu
|
|
||||||
bionic main
|
|
||||||
include:
|
include:
|
||||||
- libc6:amd64
|
- libc6:amd64
|
||||||
- libgtk-3-0
|
- libgtk-3-0
|
||||||
@@ -54,9 +52,14 @@ AppDir:
|
|||||||
- libvdpau1
|
- libvdpau1
|
||||||
- libgstreamer-plugins-base1.0-0
|
- libgstreamer-plugins-base1.0-0
|
||||||
- gstreamer1.0-pipewire
|
- gstreamer1.0-pipewire
|
||||||
|
- libwayland-client0
|
||||||
- libwayland-cursor0
|
- libwayland-cursor0
|
||||||
- libwayland-egl1
|
- libwayland-egl1
|
||||||
- libpulse0
|
- libpulse0
|
||||||
|
- packagekit-gtk3-module
|
||||||
|
- libcanberra-gtk3-module
|
||||||
|
- libpam0g
|
||||||
|
- libdrm2
|
||||||
exclude:
|
exclude:
|
||||||
- humanity-icon-theme
|
- humanity-icon-theme
|
||||||
- hicolor-icon-theme
|
- hicolor-icon-theme
|
||||||
@@ -72,8 +75,11 @@ AppDir:
|
|||||||
- usr/share/doc/*/TODO.*
|
- usr/share/doc/*/TODO.*
|
||||||
runtime:
|
runtime:
|
||||||
env:
|
env:
|
||||||
GIO_MODULE_DIR: $APPDIR/usr/lib/x86_64-linux-gnu/gio/modules/
|
GIO_MODULE_DIR: /lib64/gio/modules:/usr/lib/x86_64-linux-gnu/gio/modules:$APPDIR/usr/lib/x86_64-linux-gnu/gio/modules
|
||||||
GDK_BACKEND: x11
|
GDK_BACKEND: x11
|
||||||
|
APPDIR_LIBRARY_PATH: /lib64:/usr/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu/security:$APPDIR/lib/systemd:$APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules:$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/printbackends:$APPDIR/usr/lib/x86_64-linux-gnu/krb5/plugins/preauth:$APPDIR/usr/lib/x86_64-linux-gnu/libcanberra-0.30:$APPDIR/usr/lib/x86_64-linux-gnu/pulseaudio:$APPDIR/usr/lib/x86_64-linux-gnu/sasl2:$APPDIR/usr/lib/x86_64-linux-gnu/vdpau:$APPDIR/usr/lib/rustdesk/lib:$APPDIR/lib/x86_64
|
||||||
|
GST_PLUGIN_PATH: /lib64/gstreamer-1.0:/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0
|
||||||
|
GST_PLUGIN_SYSTEM_PATH: /lib64/gstreamer-1.0:/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0
|
||||||
test:
|
test:
|
||||||
fedora-30:
|
fedora-30:
|
||||||
image: appimagecrafters/tests-env:fedora-30
|
image: appimagecrafters/tests-env:fedora-30
|
||||||
|
|||||||
96
build.py
@@ -16,7 +16,7 @@ osx = platform.platform().startswith(
|
|||||||
hbb_name = 'rustdesk' + ('.exe' if windows else '')
|
hbb_name = 'rustdesk' + ('.exe' if windows else '')
|
||||||
exe_path = 'target/release/' + hbb_name
|
exe_path = 'target/release/' + hbb_name
|
||||||
if windows:
|
if windows:
|
||||||
flutter_build_dir = 'build/windows/runner/Release/'
|
flutter_build_dir = 'build/windows/x64/runner/Release/'
|
||||||
elif osx:
|
elif osx:
|
||||||
flutter_build_dir = 'build/macos/Build/Products/Release/'
|
flutter_build_dir = 'build/macos/Build/Products/Release/'
|
||||||
else:
|
else:
|
||||||
@@ -24,18 +24,21 @@ else:
|
|||||||
flutter_build_dir_2 = f'flutter/{flutter_build_dir}'
|
flutter_build_dir_2 = f'flutter/{flutter_build_dir}'
|
||||||
skip_cargo = False
|
skip_cargo = False
|
||||||
|
|
||||||
|
|
||||||
def get_arch() -> str:
|
def get_arch() -> str:
|
||||||
custom_arch = os.environ.get("ARCH")
|
custom_arch = os.environ.get("ARCH")
|
||||||
if custom_arch is None:
|
if custom_arch is None:
|
||||||
return "amd64"
|
return "amd64"
|
||||||
return custom_arch
|
return custom_arch
|
||||||
|
|
||||||
|
|
||||||
def system2(cmd):
|
def system2(cmd):
|
||||||
err = os.system(cmd)
|
exit_code = os.system(cmd)
|
||||||
if err != 0:
|
if exit_code != 0:
|
||||||
print(f"Error occurred when executing: {cmd}. Exiting.")
|
sys.stderr.write(f"Error occurred when executing: `{cmd}`. Exiting.\n")
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
with open("Cargo.toml", encoding="utf-8") as fh:
|
with open("Cargo.toml", encoding="utf-8") as fh:
|
||||||
for line in fh:
|
for line in fh:
|
||||||
@@ -46,17 +49,11 @@ def get_version():
|
|||||||
|
|
||||||
def parse_rc_features(feature):
|
def parse_rc_features(feature):
|
||||||
available_features = {
|
available_features = {
|
||||||
'IddDriver': {
|
|
||||||
'platform': ['windows'],
|
|
||||||
'zip_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.3/RustDeskIddDriver_x64.zip',
|
|
||||||
'checksum_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.3/checksum_md5',
|
|
||||||
'exclude': ['README.md', 'certmgr.exe', 'install_cert_runas_admin.bat', 'RustDeskIddApp.exe'],
|
|
||||||
},
|
|
||||||
'PrivacyMode': {
|
'PrivacyMode': {
|
||||||
'platform': ['windows'],
|
'platform': ['windows'],
|
||||||
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.1'
|
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3'
|
||||||
'/TempTopMostWindow_x64_pic_en.zip',
|
'/TempTopMostWindow_x64.zip',
|
||||||
'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.1/checksum_md5',
|
'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3/checksum_md5',
|
||||||
'include': ['WindowInjection.dll'],
|
'include': ['WindowInjection.dll'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,8 +80,10 @@ def parse_rc_features(feature):
|
|||||||
return get_all_features()
|
return get_all_features()
|
||||||
elif isinstance(feature, list):
|
elif isinstance(feature, list):
|
||||||
if windows:
|
if windows:
|
||||||
|
# download third party is deprecated, we use github ci instead.
|
||||||
# force add PrivacyMode
|
# force add PrivacyMode
|
||||||
feature.append('PrivacyMode')
|
# feature.append('PrivacyMode')
|
||||||
|
pass
|
||||||
for feat in feature:
|
for feat in feature:
|
||||||
if isinstance(feat, str) and feat.upper() == 'ALL':
|
if isinstance(feat, str) and feat.upper() == 'ALL':
|
||||||
return get_all_features()
|
return get_all_features()
|
||||||
@@ -109,7 +108,7 @@ def make_parser():
|
|||||||
nargs='+',
|
nargs='+',
|
||||||
default='',
|
default='',
|
||||||
help='Integrate features, windows only.'
|
help='Integrate features, windows only.'
|
||||||
'Available: IddDriver, PrivacyMode. Special value is "ALL" and empty "". Default is empty.')
|
'Available: PrivacyMode. Special value is "ALL" and empty "". Default is empty.')
|
||||||
parser.add_argument('--flutter', action='store_true',
|
parser.add_argument('--flutter', action='store_true',
|
||||||
help='Build flutter package', default=False)
|
help='Build flutter package', default=False)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -118,26 +117,32 @@ def make_parser():
|
|||||||
help='Enable feature hwcodec' + (
|
help='Enable feature hwcodec' + (
|
||||||
'' if windows or osx else ', need libva-dev, libvdpau-dev.')
|
'' if windows or osx else ', need libva-dev, libvdpau-dev.')
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--vram',
|
||||||
|
action='store_true',
|
||||||
|
help='Enable feature vram, only available on windows now.'
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--portable',
|
'--portable',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Build windows portable'
|
help='Build windows portable'
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--flatpak',
|
'--unix-file-copy-paste',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Build rustdesk libs with the flatpak feature enabled'
|
help='Build with unix file copy paste feature'
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'--appimage',
|
|
||||||
action='store_true',
|
|
||||||
help='Build rustdesk libs with the appimage feature enabled'
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--skip-cargo',
|
'--skip-cargo',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Skip cargo build process, only flutter version + Linux supported currently'
|
help='Skip cargo build process, only flutter version + Linux supported currently'
|
||||||
)
|
)
|
||||||
|
if windows:
|
||||||
|
parser.add_argument(
|
||||||
|
'--skip-portable-pack',
|
||||||
|
action='store_true',
|
||||||
|
help='Skip packing, only flutter version + Windows supported'
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--package",
|
"--package",
|
||||||
type=str
|
type=str
|
||||||
@@ -172,8 +177,8 @@ def generate_build_script_for_docker():
|
|||||||
export VCPKG_ROOT=`pwd`/vcpkg
|
export VCPKG_ROOT=`pwd`/vcpkg
|
||||||
git clone https://github.com/microsoft/vcpkg
|
git clone https://github.com/microsoft/vcpkg
|
||||||
vcpkg/bootstrap-vcpkg.sh
|
vcpkg/bootstrap-vcpkg.sh
|
||||||
vcpkg/vcpkg install libvpx libyuv opus
|
|
||||||
popd
|
popd
|
||||||
|
$VCPKG_ROOT/vcpkg install --x-install-root="$VCPKG_ROOT/installed"
|
||||||
# build rustdesk
|
# build rustdesk
|
||||||
./build.py --flutter --hwcodec
|
./build.py --flutter --hwcodec
|
||||||
''')
|
''')
|
||||||
@@ -181,10 +186,14 @@ def generate_build_script_for_docker():
|
|||||||
system2("bash /tmp/build.sh")
|
system2("bash /tmp/build.sh")
|
||||||
|
|
||||||
|
|
||||||
|
# Downloading third party resources is deprecated.
|
||||||
|
# We can use this function in an offline build environment.
|
||||||
|
# Even in an online environment, we recommend building third-party resources yourself.
|
||||||
def download_extract_features(features, res_dir):
|
def download_extract_features(features, res_dir):
|
||||||
import re
|
import re
|
||||||
|
|
||||||
proxy = ''
|
proxy = ''
|
||||||
|
|
||||||
def req(url):
|
def req(url):
|
||||||
if not proxy:
|
if not proxy:
|
||||||
return url
|
return url
|
||||||
@@ -196,9 +205,9 @@ def download_extract_features(features, res_dir):
|
|||||||
|
|
||||||
for (feat, feat_info) in features.items():
|
for (feat, feat_info) in features.items():
|
||||||
includes = feat_info['include'] if 'include' in feat_info and feat_info['include'] else []
|
includes = feat_info['include'] if 'include' in feat_info and feat_info['include'] else []
|
||||||
includes = [ re.compile(p) for p in includes ]
|
includes = [re.compile(p) for p in includes]
|
||||||
excludes = feat_info['exclude'] if 'exclude' in feat_info and feat_info['exclude'] else []
|
excludes = feat_info['exclude'] if 'exclude' in feat_info and feat_info['exclude'] else []
|
||||||
excludes = [ re.compile(p) for p in excludes ]
|
excludes = [re.compile(p) for p in excludes]
|
||||||
|
|
||||||
print(f'{feat} download begin')
|
print(f'{feat} download begin')
|
||||||
download_filename = feat_info['zip_url'].split('/')[-1]
|
download_filename = feat_info['zip_url'].split('/')[-1]
|
||||||
@@ -261,17 +270,14 @@ def external_resources(flutter, args, res_dir):
|
|||||||
|
|
||||||
def get_features(args):
|
def get_features(args):
|
||||||
features = ['inline'] if not args.flutter else []
|
features = ['inline'] if not args.flutter else []
|
||||||
if windows:
|
|
||||||
features.append('virtual_display_driver')
|
|
||||||
if args.hwcodec:
|
if args.hwcodec:
|
||||||
features.append('hwcodec')
|
features.append('hwcodec')
|
||||||
|
if args.vram:
|
||||||
|
features.append('vram')
|
||||||
if args.flutter:
|
if args.flutter:
|
||||||
features.append('flutter')
|
features.append('flutter')
|
||||||
features.append('flutter_texture_render')
|
if args.unix_file_copy_paste:
|
||||||
if args.flatpak:
|
features.append('unix-file-copy-paste')
|
||||||
features.append('flatpak')
|
|
||||||
if args.appimage:
|
|
||||||
features.append('appimage')
|
|
||||||
print("features:", features)
|
print("features:", features)
|
||||||
return features
|
return features
|
||||||
|
|
||||||
@@ -350,6 +356,7 @@ def build_flutter_deb(version, features):
|
|||||||
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
|
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def build_deb_from_folder(version, binary_folder):
|
def build_deb_from_folder(version, binary_folder):
|
||||||
os.chdir('flutter')
|
os.chdir('flutter')
|
||||||
system2('mkdir -p tmpdeb/usr/bin/')
|
system2('mkdir -p tmpdeb/usr/bin/')
|
||||||
@@ -388,18 +395,22 @@ def build_deb_from_folder(version, binary_folder):
|
|||||||
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
|
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def build_flutter_dmg(version, features):
|
def build_flutter_dmg(version, features):
|
||||||
if not skip_cargo:
|
if not skip_cargo:
|
||||||
# set minimum osx build target, now is 10.14, which is the same as the flutter xcode project
|
# set minimum osx build target, now is 10.14, which is the same as the flutter xcode project
|
||||||
system2(f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release')
|
system2(
|
||||||
|
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release')
|
||||||
# copy dylib
|
# copy dylib
|
||||||
system2(
|
system2(
|
||||||
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
|
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
|
||||||
os.chdir('flutter')
|
os.chdir('flutter')
|
||||||
system2('flutter build macos --release')
|
system2('flutter build macos --release')
|
||||||
|
'''
|
||||||
system2(
|
system2(
|
||||||
"create-dmg --volname \"RustDesk Installer\" --window-pos 200 120 --window-size 800 400 --icon-size 100 --app-drop-link 600 185 --icon RustDesk.app 200 190 --hide-extension RustDesk.app rustdesk.dmg ./build/macos/Build/Products/Release/RustDesk.app")
|
"create-dmg --volname \"RustDesk Installer\" --window-pos 200 120 --window-size 800 400 --icon-size 100 --app-drop-link 600 185 --icon RustDesk.app 200 190 --hide-extension RustDesk.app rustdesk.dmg ./build/macos/Build/Products/Release/RustDesk.app")
|
||||||
os.rename("rustdesk.dmg", f"../rustdesk-{version}.dmg")
|
os.rename("rustdesk.dmg", f"../rustdesk-{version}.dmg")
|
||||||
|
'''
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
@@ -414,7 +425,7 @@ def build_flutter_arch_manjaro(version, features):
|
|||||||
system2('HBB=`pwd`/.. FLUTTER=1 makepkg -f')
|
system2('HBB=`pwd`/.. FLUTTER=1 makepkg -f')
|
||||||
|
|
||||||
|
|
||||||
def build_flutter_windows(version, features):
|
def build_flutter_windows(version, features, skip_portable_pack):
|
||||||
if not skip_cargo:
|
if not skip_cargo:
|
||||||
system2(f'cargo build --features {features} --lib --release')
|
system2(f'cargo build --features {features} --lib --release')
|
||||||
if not os.path.exists("target/release/librustdesk.dll"):
|
if not os.path.exists("target/release/librustdesk.dll"):
|
||||||
@@ -425,6 +436,8 @@ def build_flutter_windows(version, features):
|
|||||||
os.chdir('..')
|
os.chdir('..')
|
||||||
shutil.copy2('target/release/deps/dylib_virtual_display.dll',
|
shutil.copy2('target/release/deps/dylib_virtual_display.dll',
|
||||||
flutter_build_dir_2)
|
flutter_build_dir_2)
|
||||||
|
if skip_portable_pack:
|
||||||
|
return
|
||||||
os.chdir('libs/portable')
|
os.chdir('libs/portable')
|
||||||
system2('pip3 install -r requirements.txt')
|
system2('pip3 install -r requirements.txt')
|
||||||
system2(
|
system2(
|
||||||
@@ -474,13 +487,14 @@ def main():
|
|||||||
os.chdir('../../..')
|
os.chdir('../../..')
|
||||||
|
|
||||||
if flutter:
|
if flutter:
|
||||||
build_flutter_windows(version, features)
|
build_flutter_windows(version, features, args.skip_portable_pack)
|
||||||
return
|
return
|
||||||
system2('cargo build --release --features ' + features)
|
system2('cargo build --release --features ' + features)
|
||||||
# system2('upx.exe target/release/rustdesk.exe')
|
# system2('upx.exe target/release/rustdesk.exe')
|
||||||
system2('mv target/release/rustdesk.exe target/release/RustDesk.exe')
|
system2('mv target/release/rustdesk.exe target/release/RustDesk.exe')
|
||||||
pa = os.environ.get('P')
|
pa = os.environ.get('P')
|
||||||
if pa:
|
if pa:
|
||||||
|
# https://certera.com/kb/tutorial-guide-for-safenet-authentication-client-for-code-signing/
|
||||||
system2(
|
system2(
|
||||||
f'signtool sign /a /v /p {pa} /debug /f .\\cert.pfx /t http://timestamp.digicert.com '
|
f'signtool sign /a /v /p {pa} /debug /f .\\cert.pfx /t http://timestamp.digicert.com '
|
||||||
'target\\release\\rustdesk.exe')
|
'target\\release\\rustdesk.exe')
|
||||||
@@ -545,13 +559,6 @@ def main():
|
|||||||
'cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS/')
|
'cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS/')
|
||||||
# https://github.com/sindresorhus/create-dmg
|
# https://github.com/sindresorhus/create-dmg
|
||||||
system2('/bin/rm -rf *.dmg')
|
system2('/bin/rm -rf *.dmg')
|
||||||
plist = "target/release/bundle/osx/RustDesk.app/Contents/Info.plist"
|
|
||||||
txt = open(plist).read()
|
|
||||||
with open(plist, "wt") as fh:
|
|
||||||
fh.write(txt.replace("</dict>", """
|
|
||||||
<key>LSUIElement</key>
|
|
||||||
<string>1</string>
|
|
||||||
</dict>"""))
|
|
||||||
pa = os.environ.get('P')
|
pa = os.environ.get('P')
|
||||||
if pa:
|
if pa:
|
||||||
system2('''
|
system2('''
|
||||||
@@ -564,7 +571,8 @@ 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/Contents/MacOS/*
|
||||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app
|
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app
|
||||||
'''.format(pa))
|
'''.format(pa))
|
||||||
system2('create-dmg "RustDesk %s.dmg" "target/release/bundle/osx/RustDesk.app"' % version)
|
system2(
|
||||||
|
'create-dmg "RustDesk %s.dmg" "target/release/bundle/osx/RustDesk.app"' % version)
|
||||||
os.rename('RustDesk %s.dmg' %
|
os.rename('RustDesk %s.dmg' %
|
||||||
version, 'rustdesk-%s.dmg' % version)
|
version, 'rustdesk-%s.dmg' % version)
|
||||||
if pa:
|
if pa:
|
||||||
@@ -584,7 +592,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print('Not signed')
|
print('Not signed')
|
||||||
else:
|
else:
|
||||||
# buid deb package
|
# build deb package
|
||||||
system2(
|
system2(
|
||||||
'mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb')
|
'mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb')
|
||||||
system2('dpkg-deb -R rustdesk.deb tmpdeb')
|
system2('dpkg-deb -R rustdesk.deb tmpdeb')
|
||||||
|
|||||||
60
build.rs
@@ -1,9 +1,11 @@
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn build_windows() {
|
fn build_windows() {
|
||||||
let file = "src/platform/windows.cc";
|
let file = "src/platform/windows.cc";
|
||||||
cc::Build::new().file(file).compile("windows");
|
let file2 = "src/platform/windows_delete_test_cert.cc";
|
||||||
|
cc::Build::new().file(file).file(file2).compile("windows");
|
||||||
println!("cargo:rustc-link-lib=WtsApi32");
|
println!("cargo:rustc-link-lib=WtsApi32");
|
||||||
println!("cargo:rerun-if-changed={}", file);
|
println!("cargo:rerun-if-changed={}", file);
|
||||||
|
println!("cargo:rerun-if-changed={}", file2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -41,7 +43,7 @@ fn build_manifest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_oboe() {
|
fn install_android_deps() {
|
||||||
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||||
if target_os != "android" {
|
if target_os != "android" {
|
||||||
return;
|
return;
|
||||||
@@ -49,6 +51,8 @@ fn install_oboe() {
|
|||||||
let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||||
if target_arch == "x86_64" {
|
if target_arch == "x86_64" {
|
||||||
target_arch = "x64".to_owned();
|
target_arch = "x64".to_owned();
|
||||||
|
} else if target_arch == "x86" {
|
||||||
|
target_arch = "x86".to_owned();
|
||||||
} else if target_arch == "aarch64" {
|
} else if target_arch == "aarch64" {
|
||||||
target_arch = "arm64".to_owned();
|
target_arch = "arm64".to_owned();
|
||||||
} else {
|
} else {
|
||||||
@@ -66,62 +70,16 @@ fn install_oboe() {
|
|||||||
path.join("lib").to_str().unwrap()
|
path.join("lib").to_str().unwrap()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
println!("cargo:rustc-link-lib=ndk_compat");
|
||||||
println!("cargo:rustc-link-lib=oboe");
|
println!("cargo:rustc-link-lib=oboe");
|
||||||
|
println!("cargo:rustc-link-lib=oboe_wrapper");
|
||||||
println!("cargo:rustc-link-lib=c++");
|
println!("cargo:rustc-link-lib=c++");
|
||||||
println!("cargo:rustc-link-lib=OpenSLES");
|
println!("cargo:rustc-link-lib=OpenSLES");
|
||||||
// I always got some strange link error with oboe, so as workaround, put oboe.cc into oboe src: src/common/AudioStreamBuilder.cpp
|
|
||||||
// also to avoid libc++_shared not found issue, cp ndk's libc++_shared.so to jniLibs, e.g.
|
|
||||||
// ./flutter_hbb/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
|
|
||||||
// let include = path.join("include");
|
|
||||||
//cc::Build::new().file("oboe.cc").include(include).compile("oboe_wrapper");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
fn gen_flutter_rust_bridge() {
|
|
||||||
if !std::env::var("RUN_FFIGEN").is_ok() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
use lib_flutter_rust_bridge_codegen::{
|
|
||||||
config_parse, frb_codegen, get_symbols_if_no_duplicates, RawOpts,
|
|
||||||
};
|
|
||||||
let llvm_path = match std::env::var("LLVM_HOME") {
|
|
||||||
Ok(path) => Some(vec![path]),
|
|
||||||
Err(_) => None,
|
|
||||||
};
|
|
||||||
// Tell Cargo that if the given file changes, to rerun this build script.
|
|
||||||
println!("cargo:rerun-if-changed=src/flutter_ffi.rs");
|
|
||||||
// Options for frb_codegen
|
|
||||||
let raw_opts = RawOpts {
|
|
||||||
// Path of input Rust code
|
|
||||||
rust_input: vec!["src/flutter_ffi.rs".to_string()],
|
|
||||||
// Path of output generated Dart code
|
|
||||||
dart_output: vec!["flutter/lib/generated_bridge.dart".to_string()],
|
|
||||||
// Path of output generated C header
|
|
||||||
c_output: Some(vec!["flutter/macos/Runner/bridge_generated.h".to_string()]),
|
|
||||||
/// Path to the installed LLVM
|
|
||||||
llvm_path,
|
|
||||||
// for other options use defaults
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
// get opts from raw opts
|
|
||||||
let configs = config_parse(raw_opts);
|
|
||||||
// generation of rust api for ffi
|
|
||||||
let all_symbols = get_symbols_if_no_duplicates(&configs).unwrap();
|
|
||||||
for config in configs.iter() {
|
|
||||||
frb_codegen(config, &all_symbols).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
hbb_common::gen_version();
|
hbb_common::gen_version();
|
||||||
install_oboe();
|
install_android_deps();
|
||||||
// there is problem with cfg(target_os) in build.rs, so use our workaround
|
|
||||||
// let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
||||||
// if target_os == "android" || target_os == "ios" {
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
gen_flutter_rust_bridge();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
#[cfg(all(windows, feature = "inline"))]
|
#[cfg(all(windows, feature = "inline"))]
|
||||||
build_manifest();
|
build_manifest();
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|||||||
101
docs/CODE_OF_CONDUCT-JP.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
# コントリビューター規約 行動規範
|
||||||
|
|
||||||
|
## 私たちの誓い
|
||||||
|
|
||||||
|
私たちは、メンバー、貢献者、リーダーとして、年齢、体格、目に見える・見えない障害、
|
||||||
|
民族性、性の特徴、性自認と表現、経験のレベル、教育、社会経済的地位、国籍、個人の外見、
|
||||||
|
人種、宗教、性的自認と指向に関係なく、誰もがハラスメントのないコミュニティに参加できるようにすることを誓います。
|
||||||
|
|
||||||
|
私たちは、開かれた、歓迎された、多様で、包容力のある、健全な地域社会に貢献するように行動し、交流することを誓います。
|
||||||
|
|
||||||
|
## 私たちの基準
|
||||||
|
|
||||||
|
地域社会にとって好ましい環境にコントリビュートする行動の例には、以下のようなものがある:
|
||||||
|
|
||||||
|
* 他者への共感と優しさ
|
||||||
|
* 異なる意見、視点、経験を尊重すること
|
||||||
|
* 建設的なフィードバックを与え、潔く受け入れること
|
||||||
|
* 私たちの過ちによって影響を受けた人々に責任を受け入れ、謝罪し、経験から学ぶこと
|
||||||
|
* 私たち個人にとってだけでなく、地域社会全体にとって何が最善であるかに焦点を合わせること
|
||||||
|
|
||||||
|
許されない行為の例:
|
||||||
|
|
||||||
|
* 性的な言葉やイメージの使用、性的な注目や誘いかけ
|
||||||
|
* 荒らし、侮辱的または軽蔑的なコメント、個人的または政治的な攻撃
|
||||||
|
* 公的または私的な嫌がらせ
|
||||||
|
* 明示的な許可なく、他人の住所や電子メールアドレスなどの個人情報を公開すること
|
||||||
|
* 職業上不適切と見なされるその他の行為
|
||||||
|
|
||||||
|
## 執行責任
|
||||||
|
|
||||||
|
コミュニティリーダーは、許容される行動の基準を明確にし、実施する責任があり、
|
||||||
|
不適切、脅迫的、攻撃的、または有害と判断される行動に対しては、適切かつ公正な是正措置をとります
|
||||||
|
|
||||||
|
コミュニティリーダーは、本行動規範に沿わないコメント、コミット、コード、ウィキ編集、
|
||||||
|
課題、その他の貢献を削除、編集、拒否する権利と責任を有し、適切な場合にはモデレーション決定の理由を伝えます。
|
||||||
|
|
||||||
|
## スコープ
|
||||||
|
|
||||||
|
この行動規範は、すべてのコミュニティスペースで適用され、また個人が公的なスペースでコミュニティを公式に代表している場合にも適用されます。
|
||||||
|
当コミュニティを代表する例としては、公式 E メールアドレスの使用、公式ソーシャルメディアアカウントによる投稿、
|
||||||
|
オンラインまたはオフラインのイベントでの任命された代表としての行動などが挙げられます。
|
||||||
|
|
||||||
|
## 施行
|
||||||
|
|
||||||
|
虐待、ハラスメント、その他容認できない行為があった場合は、[info@rustdesk.com](mailto:info@rustdesk.com) の
|
||||||
|
執行担当コミュニティリーダーに報告することができる。
|
||||||
|
すべての苦情は、迅速かつ公正に検討・調査されます。
|
||||||
|
|
||||||
|
すべての地域社会の指導者は、いかなる事件の報告者のプライバシーと安全を尊重する義務がある。
|
||||||
|
|
||||||
|
## 執行ガイドライン
|
||||||
|
|
||||||
|
コミュニティリーダーは、本行動規範に違反すると判断した行為に対する結果を決定する際、
|
||||||
|
以下の「コミュニティへの影響に関するガイドライン」に従います:
|
||||||
|
|
||||||
|
### 1. 修正
|
||||||
|
|
||||||
|
**コミュニティへの影響**: 不適切な言葉の使用、またはプロフェッショナルでない、あるいは地域社会で歓迎されないとみなされるその他の行動。
|
||||||
|
|
||||||
|
**結果**: コミュニティリーダーからの私的な書面による警告。違反の性質と、
|
||||||
|
なぜその行為が不適切であったのかについての説明を明確にする。公的な謝罪が要求される場合もある。
|
||||||
|
|
||||||
|
### 2. 警告
|
||||||
|
|
||||||
|
**コミュニティへの影響**: 単一の出来事または一連の行動による違反。
|
||||||
|
|
||||||
|
**結果**: 行動を続けた場合の結果を伴う警告。一定期間、行動規範の実施者との勝手な交流を含め、
|
||||||
|
関係者と交流しないこと。これには、ソーシャルメディアなどの外部チャンネルだけでなく、
|
||||||
|
コミュニティスペースでの交流を避けることも含まれます。これらの条件に違反した場合、一時的または恒久的に追放される可能性があります。
|
||||||
|
|
||||||
|
### 3. 一時的な禁止
|
||||||
|
|
||||||
|
**コミュニティへの影響**: 継続的な不適切な行動を含む、コミュニティ基準に対する重大な違反。
|
||||||
|
|
||||||
|
**結果**: 一定期間、地域社会とのあらゆる交流や公的なコミュニケーションを一時的に禁止すること。
|
||||||
|
この期間中は、行動規範を執行する人々との未承諾の交流を含め、関係者との公私にわたる交流は許されない。
|
||||||
|
これらの条件に違反した場合、永久禁止となる可能性があります。
|
||||||
|
|
||||||
|
### 4. 永久禁止
|
||||||
|
|
||||||
|
**コミュニティへの影響**: 継続的な不適切な行動、個人に対する嫌がらせ、
|
||||||
|
または個人クラスに対する攻撃や中傷など、地域社会の基準に対する違反のパターンを示すこと。
|
||||||
|
|
||||||
|
**結果**: コミュニティ内でのあらゆる公的交流の永久禁止。
|
||||||
|
|
||||||
|
## 帰属
|
||||||
|
|
||||||
|
この行動規範は、[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0] に掲載されている
|
||||||
|
[コントリビューター規約][ホームページ]、バージョン 2.0 から引用したものです。
|
||||||
|
|
||||||
|
コミュニティインパクトガイドラインは、[Mozilla's code of conduct enforcement ladder][Mozilla CoC] に触発されました。
|
||||||
|
|
||||||
|
この行動規範に関するよくある質問については、[https://www.contributor-covenant.org/faq][FAQ] の FAQ をご覧ください。
|
||||||
|
翻訳は [https://www.contributor-covenant.org/translations][翻訳] にあります。
|
||||||
|
|
||||||
|
[ホームページ]: https://www.contributor-covenant.org
|
||||||
|
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||||
|
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||||
|
[FAQ]: https://www.contributor-covenant.org/faq
|
||||||
|
[翻訳]: https://www.contributor-covenant.org/translations
|
||||||
89
docs/CODE_OF_CONDUCT-TR.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# Katkıda Bulunanların Davranış Kuralları
|
||||||
|
|
||||||
|
## Taahhüdümüz
|
||||||
|
|
||||||
|
Biz üyeler, katkıda bulunanlar ve liderler olarak, yaş, beden büyüklüğü, görünür veya görünmez engellilik, etnik köken, cinsiyet özellikleri, cinsiyet kimliği ve ifadesi, deneyim seviyesi, eğitim, sosyo-ekonomik durum, milliyet, kişisel görünüm, ırk, din veya cinsel kimlik ve yönelim ayrımı gözetmeksizin herkes için topluluğumuzdaki katılımı taciz içermeyen bir deneyim haline getirmeyi taahhüt ederiz.
|
||||||
|
|
||||||
|
Açık, hoşgörülü, çeşitli, kapsayıcı ve sağlıklı bir topluluğa katkıda bulunacak şekillerde hareket etmeyi ve etkileşimde bulunmayı taahhüt ederiz.
|
||||||
|
|
||||||
|
## Standartlarımız
|
||||||
|
|
||||||
|
Topluluğumuz için olumlu bir ortam yaratmaya katkıda bulunan davranış örnekleri şunlardır:
|
||||||
|
|
||||||
|
* Diğer insanlara empati ve nezaket göstermek
|
||||||
|
* Farklı görüşlere, bakış açılarına ve deneyimlere saygılı olmak
|
||||||
|
* Yapıcı eleştiriyi vermek ve zarifçe kabul etmek
|
||||||
|
* Hatalarımızdan etkilenenlere sorumluluk kabul etmek, özür dilemek ve deneyimden öğrenmek
|
||||||
|
* Sadece bireyler olarak değil, aynı zamanda genel topluluk için en iyisi üzerine odaklanmak
|
||||||
|
|
||||||
|
Kabul edilemez davranış örnekleri şunları içerir:
|
||||||
|
|
||||||
|
* Cinselleştirilmiş dil veya imgelerin kullanımı ve cinsel ilgi veya herhangi bir türdeki yaklaşımlar
|
||||||
|
* Trollük, aşağılayıcı veya hakaret içeren yorumlar ve kişisel veya siyasi saldırılar
|
||||||
|
* Kamuoyu veya özel taciz
|
||||||
|
* Başkalarının fiziksel veya e-posta adresi gibi özel bilgilerini, açık izinleri olmadan yayınlamak
|
||||||
|
* Profesyonel bir ortamda makul bir şekilde uygunsuz kabul edilebilecek diğer davranışlar
|
||||||
|
|
||||||
|
## Uygulama Sorumlulukları
|
||||||
|
|
||||||
|
Topluluk liderleri, kabul edilebilir davranış standartlarımızı açıklığa kavuşturmak ve uygulamakla sorumludur ve uygunsuz, tehditkar, saldırgan veya zarar verici herhangi bir davranışa yanıt olarak uygun ve adil düzeltici önlemler alacaklardır.
|
||||||
|
|
||||||
|
Topluluk liderleri, bu Davranış Kurallarına uyumlu olmayan yorumları, taahhütlerini veya kodu, wiki düzenlemelerini, sorunları ve diğer katkıları kaldırma, düzenleme veya reddetme hakkına sahiptir. Denetim kararlarının nedenlerini uygun olduğunda ileteceklerdir.
|
||||||
|
|
||||||
|
## Kapsam
|
||||||
|
|
||||||
|
Bu Davranış Kuralları, tüm topluluk alanlarında geçerlidir ve aynı zamanda birey resmi olarak topluluğu halka açık alanlarda temsil ettiğinde de geçerlidir. Topluluğumuzu temsil etme örnekleri, resmi bir e-posta adresi kullanmak, resmi bir sosyal medya hesabı üzerinden gönderi yapmak veya çevrimiçi veya çevrimdışı bir etkinlikte atanmış bir temsilci olarak hareket etmeyi içerir.
|
||||||
|
|
||||||
|
## Uygulama
|
||||||
|
|
||||||
|
Taciz edici, rahatsız edici veya başka türlü kabul edilemez davranış örnekleri, [info@rustdesk.com](mailto:info@rustdesk.com) adresindeki uygulama sorumlularına bildirilebilir. Tüm şikayetler hızlı ve adil bir şekilde incelenecek ve araştırılacaktır.
|
||||||
|
|
||||||
|
Tüm topluluk liderleri, olayın raporlayıcısının gizliliğine ve güvenliğine saygı gösterme yükümlülüğündedir.
|
||||||
|
|
||||||
|
## Uygulama Kılavuzları
|
||||||
|
|
||||||
|
Topluluk liderleri, bu Davranış Kurallarını ihlal olarak değerlendirdikleri herhangi bir eylem için bu Topluluk Etkisi Kılavuzlarını izleyeceklerdir:
|
||||||
|
|
||||||
|
### 1. Düzeltme
|
||||||
|
|
||||||
|
**Topluluk Etkisi**: Topluluk içinde profesyonel veya hoşgörülü olmayan uygun olmayan dil veya diğer davranışların kullanımı.
|
||||||
|
|
||||||
|
**Sonuç**: Topluluk liderlerinden özel ve yazılı bir uyarı almak, ihlalin niteliği ve davranışın nedeninin açıklığa kavuşturulması. Bir kamu özrü istenebilir.
|
||||||
|
|
||||||
|
### 2. Uyarı
|
||||||
|
|
||||||
|
**Topluluk Etkisi**: Tek bir olay veya dizi aracılığıyla bir ihlal.
|
||||||
|
|
||||||
|
**Sonuç**: Devam eden davranış için sonuçları olan bir uyarı. Topluluk liderleri de dahil olmak üzere ihlalle ilgili kişilerle etkileşim, belirli bir süre boyunca önerilmez. Bu, topluluk alanlarında ve sosyal medya gibi harici kanallarda etkileşimleri içerir. Bu koşulları ihlal etmek geçici veya kalıcı bir yasağa yol açabilir.
|
||||||
|
|
||||||
|
### 3. Geçici Yasak
|
||||||
|
|
||||||
|
**Topluluk Etkisi**: Sürekli uygunsuz davranış da dahil olmak üzere topluluk standartlarının ciddi bir ihlali.
|
||||||
|
|
||||||
|
**Sonuç**: Belirli bir süre için toplulukla herhangi bir türdeki etkileşim veya halka açık iletişimden geçici bir yasak. Bu dönem boyunca, toplul
|
||||||
|
|
||||||
|
ukla veya uygulama kurallarını uygulayanlarla her türlü kamuoyu veya özel etkileşim izin verilmez. Bu koşulları ihlal etmek geçici veya kalıcı bir yasağa yol açabilir.
|
||||||
|
|
||||||
|
### 4. Kalıcı Yasak
|
||||||
|
|
||||||
|
**Topluluk Etkisi**: Topluluk standartlarının ihlalinde sürekli bir desen sergilemek, bireye sürekli olarak uygun olmayan davranışlarda bulunmak, bir bireye tacizde bulunmak veya birey sınıflarına karşı saldırganlık veya aşağılama yapmak.
|
||||||
|
|
||||||
|
**Sonuç**: Topluluk içinde her türlü halka açık etkileşimden kalıcı bir yasak.
|
||||||
|
|
||||||
|
## Atıf
|
||||||
|
|
||||||
|
Bu Davranış Kuralları, [Contributor Covenant][anasayfa], 2.0 sürümünden uyarlanmıştır ve
|
||||||
|
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0] adresinde bulunmaktadır.
|
||||||
|
|
||||||
|
Topluluk Etkisi Kılavuzları,
|
||||||
|
[Mozilla'nın davranış kuralları uygulama merdiveni][Mozilla DK] tarafından ilham alınarak oluşturulmuştur.
|
||||||
|
|
||||||
|
Bu davranış kuralları hakkında yaygın soruların cevapları için, SSS'ye göz atın:
|
||||||
|
[https://www.contributor-covenant.org/faq][SSS]. Çeviriler,
|
||||||
|
[https://www.contributor-covenant.org/translations][çeviriler] adresinde bulunabilir.
|
||||||
|
|
||||||
|
[anasayfa]: https://www.contributor-covenant.org
|
||||||
|
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||||
|
[Mozilla DK]: https://github.com/mozilla/diversity
|
||||||
|
[SSS]: https://www.contributor-covenant.org/faq
|
||||||
|
[çeviriler]: https://www.contributor-covenant.org/translations
|
||||||
31
docs/CONTRIBUTING-ID.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Berkontribusi dalam pengembangan RustDesk
|
||||||
|
|
||||||
|
RustDesk mengajak semua orang untuk ikut berkontribusi. Berikut ini adalah panduan jika kamu sedang mempertimbangkan untuk memberikan bantuan kepada kami:
|
||||||
|
|
||||||
|
## Kontirbusi
|
||||||
|
|
||||||
|
Untuk melakukan kontribusi pada RustDesk atau dependensinya, sebaiknya dilakukan dalam bentuk pull request di GitHub. Setiap permintaan pull request akan ditinjau oleh kontributor utama atau seseorang yang memiliki wewenang untuk menggabungkan perubahan kode, baik yang sudah dimasukkan ke dalam struktur utama ataupun memberikan umpan balik untuk perubahan yang akan diperlukan. Setiap kontribusi harus sesuai dengan format ini, juga termasuk yang berasal dari kontributor utama.
|
||||||
|
|
||||||
|
Apabila kamu ingin mengatasi sebuah masalah yang sudah ada di daftar issue, harap klaim terlebih dahulu dengan memberikan komentar pada GitHub issue yang ingin kamu kerjakan. Hal ini dilakukan untuk mencegah terjadinya duplikasi dari kontributor pada daftar issue yang sama.
|
||||||
|
|
||||||
|
## Pemeriksaan Pull Request
|
||||||
|
|
||||||
|
- Branch yang menjadi acuan adalah branch master dari repositori utama dan, jika diperlukan, lakukan rebase ke branch master yang terbaru sebelum kamu mengirim pull request. Apabila terdapat masalah kita melakukan proses merge ke branch master kemungkinan kamu akan diminta untuk melakukan rebase pada perubahan yang sudah dibuat.
|
||||||
|
|
||||||
|
- Sebaiknya buatlah commit seminimal mungkin, sambil memastikan bahwa setiap commit yang dibuat sudah benar (contohnya, setiap commit harus bisa di kompilasi dan berhasil melewati tahap test).
|
||||||
|
|
||||||
|
- Setiap commit harus disertai dengan tanda tangan Sertifikat Asal Pengembang (Developer Certificate of Origin) (<http://developercertificate.org>), yang mengindikasikan bahwa kamu (and your employer if applicable) bersedia untuk patuh terhadap persyaratan dari [lisensi projek](../LICENCE). Di git bash, ini adalah opsi parameter `-s` pada `git commit`
|
||||||
|
|
||||||
|
- Jika perubahan yang kamu buat tidak mendapat tinjauan atau kamu membutuhkan orang tertentu untuk meninjaunya, kamu bisa @-reply seorang reviewer meminta peninjauan dalam permintaan pull request atau komentar, atau kamu bisa meminta tinjauan melalui [email](mailto:info@rustdesk.com).
|
||||||
|
|
||||||
|
- Sertakan test yang relevan terhadap bug atau fitur baru yang sudah dikerjakan.
|
||||||
|
|
||||||
|
Untuk instruksi Git yang lebih lanjut, cek disini [GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow).
|
||||||
|
|
||||||
|
## Tindakan
|
||||||
|
|
||||||
|
<https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT-ID.md>
|
||||||
|
|
||||||
|
## Komunikasi
|
||||||
|
|
||||||
|
Kontributor RustDesk sering berkunjung ke [Discord](https://discord.gg/nDceKgxnkV).
|
||||||
41
docs/CONTRIBUTING-JP.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# RustDesk へのコントリビュート
|
||||||
|
|
||||||
|
RustDesk は皆さんからのコントリビュートを歓迎します。ご協力いただける方のガイドラインは
|
||||||
|
以下の通りです:
|
||||||
|
|
||||||
|
## コントリビューション
|
||||||
|
|
||||||
|
RustDesk またはその依存関係へのコントリビュートは、GitHub のプルリクエストの形で行ってください。
|
||||||
|
それぞれのプルリクエストは、コアコントリビューター(パッチの適用を許可されている人)によってレビューされ、
|
||||||
|
メインツリーに適用されるか、必要な変更についてのフィードバックが与えられます。
|
||||||
|
コアコントリビューターからのものであっても、すべてのコントリビューターはこのフォーマットに従うべきです。
|
||||||
|
|
||||||
|
ある issue に取り組みたい場合は、GitHub の issue にコメントすることで、まずその対応を主張してください。
|
||||||
|
これは、同じ issue に対するコントリビューターの重複作業を防ぐためです。
|
||||||
|
|
||||||
|
## プルリクエストのチェックリスト
|
||||||
|
|
||||||
|
- master ブランチからブランチし、必要であればプルリクエストを提出する前に現在の master ブランチにリベースしてください。
|
||||||
|
master と正しくマージできない場合、変更をリベースするよう求められる可能性があります。
|
||||||
|
|
||||||
|
- コミットは、各コミットが独立して正しい(すなわち、各コミットがコンパイルされ、テストに合格する)ことを保証しながら、
|
||||||
|
可能な限り小さくすべきです。
|
||||||
|
|
||||||
|
- コミットには、Developer Certificate of Origin (http://developercertificate.org) の sign-off を添えてください。
|
||||||
|
これは、あなた(および該当する場合はあなたの雇用主)が [プロジェクトのライセンス](../LICENCE) の条項に拘束されることに
|
||||||
|
同意していることを示すものです。git では、これは `git commit` の `-s` オプションを使います。
|
||||||
|
|
||||||
|
- もしあなたのパッチがレビューされなかったり、特定の人にレビューしてもらう必要がある場合、
|
||||||
|
プルリクエストやコメントでレビューを依頼するレビュアーに@返信したり、[email](mailto:info@rustdesk.com) でレビューを依頼することができます。
|
||||||
|
|
||||||
|
- 修正したバグや新機能に関連するテストを追加する。
|
||||||
|
|
||||||
|
具体的なgitの手順については、[GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow)を参照してください。
|
||||||
|
|
||||||
|
## 行動規範
|
||||||
|
|
||||||
|
https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md
|
||||||
|
|
||||||
|
## コミュニケーション
|
||||||
|
|
||||||
|
RustDesk のコントリビューターは、[Discord](https://discord.gg/nDceKgxnkV) を良く使っています。
|
||||||
31
docs/CONTRIBUTING-TR.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# RustDesk'a Katkı Sağlamak
|
||||||
|
|
||||||
|
RustDesk, herkesten katkıyı memnuniyetle karşılar. Eğer bize yardımcı olmayı düşünüyorsanız, işte rehberlik eden kurallar:
|
||||||
|
|
||||||
|
## Katkılar
|
||||||
|
|
||||||
|
RustDesk veya bağımlılıklarına yapılan katkılar, GitHub pull istekleri şeklinde yapılmalıdır. Her bir pull isteği, çekirdek katkıcı tarafından gözden geçirilecek (yamaları kabul etme izni olan biri) ve ana ağaca kabul edilecek veya gerekli değişiklikler için geri bildirim verilecektir. Tüm katkılar bu formata uymalıdır, çekirdek katkıcılardan gelenler bile.
|
||||||
|
|
||||||
|
Eğer bir konu üzerinde çalışmak isterseniz, önce üzerinde çalışmak istediğinizi belirten bir yorum yaparak konuyu talep ediniz. Bu, katkı sağlayanların aynı konuda çift çalışmasını engellemek içindir.
|
||||||
|
|
||||||
|
## Pull İstek Kontrol Listesi
|
||||||
|
|
||||||
|
- Master dalından dallandırın ve gerekiyorsa pull isteğinizi göndermeden önce mevcut master dalına rebase yapın. Eğer master ile temiz bir şekilde birleşmezse, değişikliklerinizi rebase yapmanız istenebilir.
|
||||||
|
|
||||||
|
- Her bir commit mümkün olduğunca küçük olmalıdır, ancak her commit'in bağımsız olarak doğru olduğundan emin olun (örneğin, her commit derlenebilir ve testleri geçmelidir).
|
||||||
|
|
||||||
|
- Commit'ler, bir Geliştirici Sertifikası ile desteklenmelidir (http://developercertificate.org). Bu, [proje lisansının](../LICENCE) koşullarına uymayı kabul ettiğinizi gösteren bir onaydır. Git'te bunu `git commit` seçeneği olarak `-s` seçeneği ile yapabilirsiniz.
|
||||||
|
|
||||||
|
- Yamalarınız gözden geçirilmiyorsa veya belirli bir kişinin gözden geçirmesine ihtiyacınız varsa, çekme isteği veya yorum içinde bir gözden geçirmeyi istemek için bir inceleyiciyi @etiketleyebilir veya inceleme için [e-posta](mailto:info@rustdesk.com) ile talep edebilirsiniz.
|
||||||
|
|
||||||
|
- Düzelttiğiniz hatanın veya eklediğiniz yeni özelliğin ilgili testlerini ekleyin.
|
||||||
|
|
||||||
|
Daha spesifik git talimatları için, [GitHub iş akışı 101](https://github.com/servo/servo/wiki/GitHub-workflow)'e bakınız.
|
||||||
|
|
||||||
|
## Davranış
|
||||||
|
|
||||||
|
https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT-TR.md
|
||||||
|
|
||||||
|
## İletişim
|
||||||
|
|
||||||
|
RustDesk katkı sağlayıcıları, [Discord](https://discord.gg/nDceKgxnkV) kanalını sık sık ziyaret ederler.
|
||||||
14
docs/DEVCONTAINER-JP.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
docker コンテナで devcontainer を起動すると、デバッグモードの linux バイナリが作成されます。
|
||||||
|
|
||||||
|
現在 devcontainer では、Linux と android のビルドをデバッグモードとリリースモードの両方で提供しています。
|
||||||
|
|
||||||
|
以下は、特定のビルドを作成するためにプロジェクトのルートから実行するコマンドの表になります。
|
||||||
|
|
||||||
|
コマンド|ビルド タイプ|モード
|
||||||
|
-|-|-|
|
||||||
|
`.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
|
||||||
|
|
||||||
12
docs/DEVCONTAINER-TR.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Docker konteynerinde devcontainer'ın başlatılmasından sonra, hata ayıklama modunda bir Linux ikili dosyası oluşturulur.
|
||||||
|
|
||||||
|
Şu anda devcontainer, hata ayıklama ve sürüm modunda hem Linux hem de Android derlemeleri sunmaktadır.
|
||||||
|
|
||||||
|
Aşağıda, belirli derlemeler oluşturmak için projenin kökünden çalıştırılması gereken komutlar yer almaktadır.
|
||||||
|
|
||||||
|
Komut | Derleme Türü | Mod
|
||||||
|
-|-|-
|
||||||
|
`.devcontainer/build.sh --debug linux` | Linux | hata ayıklama
|
||||||
|
`.devcontainer/build.sh --release linux` | Linux | sürüm
|
||||||
|
`.devcontainer/build.sh --debug android` | Android-arm64 | hata ayıklama
|
||||||
|
`.devcontainer/build.sh --release android` | Android-arm64 | sürüm
|
||||||
@@ -27,14 +27,6 @@
|
|||||||
|
|
||||||
[**BINARY تنزيل**](https://github.com/rustdesk/rustdesk/releases)
|
[**BINARY تنزيل**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## خوادم مفتوحة ومجانية
|
|
||||||
|
|
||||||
فيما يلي الخوادم التي تستخدمها مجانًا، وقد تتغير طوال الوقت. إذا لم تكن قريبًا من أحد هؤلاء، فقد تكون شبكتك بطيئة.
|
|
||||||
| الموقع | المورد | المواصفات |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
|
||||||
|
|
||||||
## التبعيات
|
## التبعيات
|
||||||
|
|
||||||
لواجهة المستخدم الرسومية [sciter](https://sciter.com/) نسخة سطح المكتب تستخدم
|
لواجهة المستخدم الرسومية [sciter](https://sciter.com/) نسخة سطح المكتب تستخدم
|
||||||
@@ -118,10 +110,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### X11 (Xorg) إلى Wayland تغيير
|
|
||||||
|
|
||||||
افتراضية GNOME session ك Xorg إتبع [هذه](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) الخطوات لإعداد Wayland لا تدعم RustDesk
|
|
||||||
|
|
||||||
## Docker طريقة البناء باستخدام
|
## Docker طريقة البناء باستخدام
|
||||||
|
|
||||||
ابدأ باستنساخ المستودع وبناء الكونتاينر:
|
ابدأ باستنساخ المستودع وبناء الكونتاينر:
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<a href="#file-structure">Struktura</a> •
|
<a href="#file-structure">Struktura</a> •
|
||||||
<a href="#snapshot">Ukázky</a><br>
|
<a href="#snapshot">Ukázky</a><br>
|
||||||
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
|
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
|
||||||
<b>Potřebujeme Vaši pomoc s překláním textů tohoto ČTIMNE, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">uživatelského rozhraní aplikace RustDesk</a> a <a href="https://github.com/rustdesk/doc.rustdesk.com">dokumentace k ní</a> do vašeho jazyka</b>
|
<b>Potřebujeme Vaši pomoc s překladem tohoto README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">uživatelského rozhraní aplikace RustDesk</a> a <a href="https://github.com/rustdesk/doc.rustdesk.com">dokumentace k ní</a> do vašeho jazyka</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Dopisujte si s námi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
Popovídejte si s námi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||||
|
|
||||||
|
|
||||||
[](https://ko-fi.com/I2I04VU09)
|
[](https://ko-fi.com/I2I04VU09)
|
||||||
@@ -22,14 +22,6 @@ Projekt RustDesk vítá přiložení ruky k dílu od každého. Jak začít se d
|
|||||||
|
|
||||||
[**STAHOVÁNÍ ZKOMPILOVANÝCH APLIKACÍ**](https://github.com/rustdesk/rustdesk/releases)
|
[**STAHOVÁNÍ ZKOMPILOVANÝCH APLIKACÍ**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Veřejné, zdarma službu nabízející servery
|
|
||||||
|
|
||||||
Níže jsou uvedeny servery zdarma k vašemu použití (údaje se mohou v čase měnit). Pokud se nenacházíte v oblastech světa poblíž nich, spojení může být pomalé.
|
|
||||||
| umístění | dodavatel | parametry |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
|
||||||
|
|
||||||
## Softwarové součásti, na kterých závisí
|
## Softwarové součásti, na kterých závisí
|
||||||
|
|
||||||
Varianta pro počítač používá pro grafické uživatelské rozhraní [sciter](https://sciter.com/) – stáhněte si potřebnou knihovnu.
|
Varianta pro počítač používá pro grafické uživatelské rozhraní [sciter](https://sciter.com/) – stáhněte si potřebnou knihovnu.
|
||||||
@@ -44,7 +36,7 @@ Varianta pro mobilní platformy používá aplikační rámec (framework) Flutte
|
|||||||
|
|
||||||
- Připravte si vývojové prostředí pro jazyky Rust a C++
|
- Připravte si vývojové prostředí pro jazyky Rust a C++
|
||||||
|
|
||||||
- Nainstalujte [vcpkg](https://github.com/microsoft/vcpkg), a nastavte správně proměnnou prostsředí `VCPKG_ROOT`
|
- Nainstalujte [vcpkg](https://github.com/microsoft/vcpkg), a správně nastavte proměnnou prostředí `VCPKG_ROOT`
|
||||||
|
|
||||||
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
|
- 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
|
- Linux/MacOS: vcpkg install libvpx libyuv opus aom
|
||||||
@@ -111,10 +103,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Změna z Wayland na X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk (zatím) nepodporuje zobrazovací server Wayland. Jak nastavit Xorg jako výchozí pro relace v prostředí GNOME naleznete [zde](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/).
|
|
||||||
|
|
||||||
## Jak sestavit prostřednictvím Docker kontejnerizace
|
## Jak sestavit prostřednictvím Docker kontejnerizace
|
||||||
|
|
||||||
Začněte tím, že si naklonujete tento repozitář a sestavíte docker kontejner:
|
Začněte tím, že si naklonujete tento repozitář a sestavíte docker kontejner:
|
||||||
@@ -131,7 +119,7 @@ Poté pokaždé, když bude třeba aplikaci sestavit, spusťte následující p
|
|||||||
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
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
Všimněte si, že prvotní sestavení může trvat déle (než se do mezipaměti uloží veškeré softwarové součásti, které jsou potřeba) – následná opakování už budou rychlejší. Dále, pokud potřebujete příkazu pro sestavení zadat nějaké argumenty, je možné je zapsat na konec příkazu na pozici `<OPTIONAL-ARGS>`. Například, pokud byste chtěli sestavit optimalizovaně pro vydání, spustili byste výše uvedený příkaz následovaný `--release`. Výsledný spustitelný soubor se objeví v cílové složce na vašem systému a bude ho možné spustit pomocí:
|
Všimněte si, že prvotní sestavení může trvat déle (než se do mezipaměti uloží veškeré softwarové součásti, které jsou potřeba) – následná opakování už budou rychlejší. Pokud navíc potřebujete zadat různé argumenty příkazu pro sestavení, můžete tak učinit na konci příkazu v pozici `<OPTIONAL-ARGS>`. Například, pokud byste chtěli sestavit optimalizovanou verzi pro vydání, spustili byste výše uvedený příkaz následovaný `--release`. Výsledný spustitelný soubor se objeví v cílové složce na vašem systému a bude ho možné spustit pomocí:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
target/debug/rustdesk
|
target/debug/rustdesk
|
||||||
@@ -143,7 +131,7 @@ Nebo, pokud spouštíte variantu pro vydání:
|
|||||||
target/release/rustdesk
|
target/release/rustdesk
|
||||||
```
|
```
|
||||||
|
|
||||||
Zajistětě, abyste tyto příkazy spouštěli z kořene repozitáře s RustDesk, jinak aplikace nemusí být schopná nalézt potřebné prostředky (resources). Také si všimněte, že ostatní dílčí príkazy nástroje cargo, jako třeba `install` nebo `run` zatím nejsou prostřednictvím této metody podporovány, protože by vedly k instalaci či spuštění program uvnitř kontejneru namísto přímo v systému.
|
Ujistěte se, že tyto příkazy spouštíte z kořenového adresáře RustDesk, jinak aplikace nemusí být schopná nalézt potřebné prostředky (resources). Také si všimněte, že ostatní dílčí príkazy nástroje cargo, jako třeba `install` nebo `run` zatím nejsou prostřednictvím této metody podporovány, protože by vedly k instalaci či spuštění program uvnitř kontejneru namísto přímo v systému.
|
||||||
|
|
||||||
## Struktura souborů
|
## Struktura souborů
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,6 @@ RustDesk hilser bidrag fra alle velkommen. Se [`docs/CONTRIBUTING.md`](docs/CONT
|
|||||||
|
|
||||||
[**PROGRAM DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
[**PROGRAM DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Gratis offentlige servere
|
|
||||||
|
|
||||||
Nedenfor er de servere, du bruger gratis, det kan ændre sig med tiden. Hvis du ikke er tæt på en af disse, kan dit netværk være langsomt.
|
|
||||||
|
|
||||||
| Beliggenhed | Udbyder | Specifikation |
|
|
||||||
| ---------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Afhængigheder
|
## Afhængigheder
|
||||||
|
|
||||||
Desktopversioner bruger [sciter](https://sciter.com/) eller Flutter til GUI, denne vejledning er kun for Sciter.
|
Desktopversioner bruger [sciter](https://sciter.com/) eller Flutter til GUI, denne vejledning er kun for Sciter.
|
||||||
@@ -108,33 +100,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
cargo run
|
cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Skift Wayland til X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk understøtter ikke Wayland. Tjek [dette](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) for at konfigurere Xorg som standard GNOME-session.
|
|
||||||
|
|
||||||
## Wayland-support
|
|
||||||
|
|
||||||
Wayland ser ikke ud til at levere nogen API til at sende tastetryk til andre vinduer. Derfor bruger rustdesk et API fra et lavere niveau, nemlig `/dev/uinput`-enheden (Linux-kerneniveau).
|
|
||||||
|
|
||||||
Når wayland er den kontrollerede side, skal du starte på følgende måde:
|
|
||||||
```bash
|
|
||||||
# Start uinput service
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Bemærk**: Wayland-skærmoptagelse bruger forskellige grænseflader. RustDesk understøtter i øjeblikket kun 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
|
|
||||||
```
|
|
||||||
## Sådan bygger du med Docker
|
## Sådan bygger du med Docker
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -29,22 +29,6 @@ RustDesk heißt jegliche Mitarbeit willkommen. Schauen Sie sich [CONTRIBUTING-DE
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Freie öffentliche Server
|
|
||||||
|
|
||||||
Nachfolgend sind die Server gelistet, die Sie kostenlos nutzen können. Es kann sein, dass sich diese Liste immer mal wieder ändert. Falls Sie nicht in der Nähe einer dieser Server sind, kann es sein, dass Ihre Verbindung langsam sein wird.
|
|
||||||
| Standort | Anbieter | Spezifikation |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Deutschland | [Hetzner](https://www.hetzner.com/de/) | 2 vCPU / 4 GB RAM |
|
|
||||||
| Ukraine (Kiew) | [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)
|
|
||||||
|
|
||||||
Wenn Sie VS Code und Docker bereits installiert haben, können Sie auf das Abzeichen oben klicken, um loszulegen. Wenn Sie darauf klicken, wird VS Code automatisch die Dev-Container-Erweiterung installieren, den Quellcode in ein Container-Volume klonen und einen Dev-Container für die Verwendung aufsetzen.
|
|
||||||
|
|
||||||
Weitere Informationen finden Sie in [DEVCONTAINER-DE.md](DEVCONTAINER-DE.md).
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
## Abhängigkeiten
|
||||||
|
|
||||||
Desktop-Versionen verwenden [Sciter](https://sciter.com/) oder Flutter für die GUI, dieses Tutorial ist nur für Sciter.
|
Desktop-Versionen verwenden [Sciter](https://sciter.com/) oder Flutter für die GUI, dieses Tutorial ist nur für Sciter.
|
||||||
@@ -133,34 +117,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wayland zu X11 (Xorg) ändern
|
|
||||||
|
|
||||||
RustDesk unterstützt Wayland nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/), um Xorg als Standard-GNOME-Sitzung zu nutzen.
|
|
||||||
|
|
||||||
## Wayland-Unterstützung
|
|
||||||
|
|
||||||
Wayland scheint keine API für das Senden von Tastatureingaben an andere Fenster zu bieten. Daher verwendet RustDesk eine API von einer niedrigeren Ebene, nämlich dem Gerät `/dev/uinput` (Linux-Kernelebene).
|
|
||||||
|
|
||||||
Wenn Wayland die kontrollierte Seite ist, müssen Sie wie folgt vorgehen:
|
|
||||||
```bash
|
|
||||||
# Dienst uinput starten
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Hinweis**: Die Wayland-Bildschirmaufnahme verwendet verschiedene Schnittstellen. RustDesk unterstützt derzeit nur 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
|
|
||||||
# Keine Unterstützung
|
|
||||||
Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast”
|
|
||||||
# Unterstützung
|
|
||||||
method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2
|
|
||||||
variant uint32 4
|
|
||||||
```
|
|
||||||
|
|
||||||
## Auf Docker kompilieren
|
## Auf Docker kompilieren
|
||||||
|
|
||||||
Beginnen Sie damit, das Repository zu klonen und den Docker-Container zu bauen:
|
Beginnen Sie damit, das Repository zu klonen und den Docker-Container zu bauen:
|
||||||
|
|||||||
@@ -19,14 +19,6 @@ RustDesk bonvenigas kontribuon de ĉiuj. Vidu [`docs/CONTRIBUTING.md`](CONTRIBUT
|
|||||||
|
|
||||||
[**BINARA ELŜUTO**](https://github.com/rustdesk/rustdesk/releases)
|
[**BINARA ELŜUTO**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Senpagaj publikaj serviloj
|
|
||||||
|
|
||||||
Malsupre estas la serviloj, kiuj vi uzas senpage, ĝi povas ŝanĝi laŭlonge de la tempo. Se vi ne estas proksima de unu de tiuj, via reto povas esti malrapida.
|
|
||||||
| Situo | Vendanto | Detaloj |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dependantaĵoj
|
## Dependantaĵoj
|
||||||
|
|
||||||
La labortabla versio uzas [sciter](https://sciter.com/) por la interfaco, bonvolu elŝuti la bibliotekon dinamikan sciter.
|
La labortabla versio uzas [sciter](https://sciter.com/) por la interfaco, bonvolu elŝuti la bibliotekon dinamikan sciter.
|
||||||
@@ -104,10 +96,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Ŝanĝi Wayland por X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk ne subtenas Wayland. Kontrolu [tion](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) por agordi Xorg kiel defaŭlta sesio GNOME.
|
|
||||||
|
|
||||||
## Kiel kompili kun Docker
|
## Kiel kompili kun Docker
|
||||||
|
|
||||||
Komencu klonante la deponejon kaj kompilu la konteneron Docker:
|
Komencu klonante la deponejon kaj kompilu la konteneron Docker:
|
||||||
|
|||||||
@@ -25,15 +25,6 @@ RustDesk agradece la contribución de todo el mundo. Lee [`docs/CONTRIBUTING.md`
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Servidores gratis de uso público
|
|
||||||
|
|
||||||
A continuación se muestran los servidores gratuitos, pueden cambiar a medida que pasa el tiempo. Si no estás cerca de uno de ellos, tu conexión puede ser lenta.
|
|
||||||
|
|
||||||
| Ubicación | Compañía | Especificación |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dependencias
|
## Dependencias
|
||||||
|
|
||||||
La versión Desktop usa [Sciter](https://sciter.com/) o Flutter para el GUI, este tutorial es solo para Sciter.
|
La versión Desktop usa [Sciter](https://sciter.com/) o Flutter para el GUI, este tutorial es solo para Sciter.
|
||||||
@@ -113,34 +104,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
cargo run
|
cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cambia Wayland a X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk no soporta Wayland. Lee [esto](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME.
|
|
||||||
|
|
||||||
## Soporte para Wayland
|
|
||||||
|
|
||||||
Wayland no parece proporcionar ninguna API para enviar pulsaciones de teclas a otras ventanas. Por lo tanto, rustdesk usa una API de nivel bajo, a saber, el dispositivo `/dev/uinput` (a nivel del kernel de Linux).
|
|
||||||
|
|
||||||
Cuando wayland esta del lado controlado, hay que iniciar de la siguiente manera:
|
|
||||||
```bash
|
|
||||||
# Empezar el servicio uinput
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Aviso**: La grabación de pantalla de Wayland utiliza diferentes interfaces. RustDesk actualmente sólo soporta 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
|
|
||||||
# No soportado
|
|
||||||
Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast”
|
|
||||||
# Soportado
|
|
||||||
method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2
|
|
||||||
variant uint32 4
|
|
||||||
```
|
|
||||||
|
|
||||||
## Como compilar con Docker
|
## Como compilar con Docker
|
||||||
|
|
||||||
Empieza clonando el repositorio y compilando el contenedor de docker:
|
Empieza clonando el repositorio y compilando el contenedor de docker:
|
||||||
|
|||||||
@@ -25,13 +25,6 @@
|
|||||||
|
|
||||||
[دریافت نرمافزار](https://github.com/rustdesk/rustdesk/releases)
|
[دریافت نرمافزار](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## سرورهای عمومی رایگان
|
|
||||||
|
|
||||||
شما ميتوانید از سرورهای زیر به رایگان استفاده کنید. این لیست ممکن است به مرور زمان تغییر میکند. اگر به این سرورها نزدیک نیستید، ممکن است اتصال شما کند باشد.
|
|
||||||
| موقعیت | سرویس دهنده | مشخصات |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| آلمان | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## وابستگی ها
|
## وابستگی ها
|
||||||
|
|
||||||
نسخههای رومیزی از [sciter](https://sciter.com/) برای رابط کاربری گرافیکی استفاده میکنند. خواهشمندیم کتابخانهی پویای sciter را خودتان دانلود کنید از این منابع دریافت کنید.
|
نسخههای رومیزی از [sciter](https://sciter.com/) برای رابط کاربری گرافیکی استفاده میکنند. خواهشمندیم کتابخانهی پویای sciter را خودتان دانلود کنید از این منابع دریافت کنید.
|
||||||
@@ -112,10 +105,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### تغییر Wayland به (X11 (Xorg
|
|
||||||
|
|
||||||
راستدسک از Wayland پشتیبانی نمی کند. برای جایگزنی Xorg به عنوان پیشفرض GNOM، [اینجا](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) را کلیک کنید.
|
|
||||||
|
|
||||||
## نحوه ساخت با داکر
|
## نحوه ساخت با داکر
|
||||||
|
|
||||||
این مخزن Git را دریافت کنید و کانتینر را به روش زیر بسازید
|
این مخزن Git را دریافت کنید و کانتینر را به روش زیر بسازید
|
||||||
|
|||||||
@@ -19,14 +19,6 @@ RustDesk toivottaa avustukset tervetulleiksi kaikilta. Katso lisätietoja [`docs
|
|||||||
|
|
||||||
[**BINAARILATAUS**](https://github.com/rustdesk/rustdesk/releases)
|
[**BINAARILATAUS**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Vapaita julkisia palvelimia
|
|
||||||
|
|
||||||
Alla on palvelimia, joita voit käyttää ilmaiseksi, ne saattavat muuttua ajan mittaan. Jos et ole lähellä yhtä näistä, verkkosi voi olla hidas.
|
|
||||||
| Sijainti | Myyjä | Määrittely |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Riippuvuudet
|
## Riippuvuudet
|
||||||
|
|
||||||
Desktop-versiot käyttävät [sciter](https://sciter.com/) graafisena käyttöliittymänä, lataa sciter-dynaaminen kirjasto itsellesi.
|
Desktop-versiot käyttävät [sciter](https://sciter.com/) graafisena käyttöliittymänä, lataa sciter-dynaaminen kirjasto itsellesi.
|
||||||
@@ -104,10 +96,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Vaihda Wayland-ympäristö X11 (Xorg)-ympäristöön
|
|
||||||
|
|
||||||
RustDesk ei tue Waylandia. Tarkista [tämä](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) asettamalla Xorg oletus GNOME-istuntoon.
|
|
||||||
|
|
||||||
## Kuinka rakennetaan Dockerin kanssa
|
## Kuinka rakennetaan Dockerin kanssa
|
||||||
|
|
||||||
Aloita kloonaamalla tietovarasto ja rakentamalla docker-säiliö:
|
Aloita kloonaamalla tietovarasto ja rakentamalla docker-säiliö:
|
||||||
|
|||||||
@@ -19,14 +19,6 @@ RustDesk accueille les contributions de tout le monde. Voir [`docs/CONTRIBUTING.
|
|||||||
|
|
||||||
[**TÉLÉCHARGEMENT BINAIRE**](https://github.com/rustdesk/rustdesk/releases)
|
[**TÉLÉCHARGEMENT BINAIRE**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Serveurs publics libres
|
|
||||||
|
|
||||||
Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut changer au fil du temps. Si vous n'êtes pas proche de l'un d'entre eux, votre réseau peut être lent.
|
|
||||||
|
|
||||||
| Location | Vendor | Specification |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dépendances
|
## Dépendances
|
||||||
|
|
||||||
Les versions de bureau utilisent [sciter](https://sciter.com/) pour l'interface graphique, veuillez télécharger la bibliothèque dynamique sciter vous-même.
|
Les versions de bureau utilisent [sciter](https://sciter.com/) pour l'interface graphique, veuillez télécharger la bibliothèque dynamique sciter vous-même.
|
||||||
@@ -104,10 +96,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
Exécution du cargo
|
Exécution du cargo
|
||||||
```
|
```
|
||||||
|
|
||||||
### Changer Wayland en X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut.
|
|
||||||
|
|
||||||
## Comment construire avec Docker
|
## Comment construire avec Docker
|
||||||
|
|
||||||
Commencez par cloner le dépôt et construire le conteneur Docker :
|
Commencez par cloner le dépôt et construire le conteneur Docker :
|
||||||
|
|||||||
@@ -29,22 +29,6 @@
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Δωρεάν δημόσιοι διακομιστές
|
|
||||||
|
|
||||||
Παρακάτω είναι οι διακομιστές που χρησιμοποιούνται δωρεάν, ενδέχεται να αλλάξουν με την πάροδο του χρόνου. Εάν δεν είστε κοντά σε ένα από αυτούς, το δίκτυό σας ίσως να είναι αργό.
|
|
||||||
| Περιοχή | Πάροχος | Προδιαγραφές |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Γερμανία | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ουκρανία (Κίεβο) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB 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, εάν χρειάζεται, θα κλωνοποιήσει τον πηγαίο κώδικα σε έναν νέο container και θα εκκινήσει ένα Dev Container για χρήση προγραμματισμού.
|
|
||||||
|
|
||||||
Για περισσότερες πληροφορίες μεταβείτε στο [DEVCONTAINER.md](docs/DEVCONTAINER.md).
|
|
||||||
|
|
||||||
## Προαπαιτούμενα για build
|
## Προαπαιτούμενα για build
|
||||||
|
|
||||||
Στις παραθυρικές εκδόσεις χρησιμοποιείται είτε το [sciter](https://sciter.com/) είτε το Flutter, τα παρακάτω βήματα είναι μόνο για το Sciter.
|
Στις παραθυρικές εκδόσεις χρησιμοποιείται είτε το [sciter](https://sciter.com/) είτε το Flutter, τα παρακάτω βήματα είναι μόνο για το Sciter.
|
||||||
@@ -133,34 +117,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg 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 περιβάλλον.
|
|
||||||
|
|
||||||
## Υποστήριξη Wayland
|
|
||||||
|
|
||||||
Το Wayland προς το παρόν δεν διαθέτει κάποιο API το οποίο να στέλνει τα πατήματα πλήκτρων στα υπόλοιπα παράθυρα. Για τον λόγο αυτό, το Rustdesk χρησιμοποιεί ένα API από κατώτερο επίπεδο, όπως το `/dev/uinput` (Linux kernel level).
|
|
||||||
|
|
||||||
Σε περίπτωση που το Wayland είναι η ελεγχόμενη πλευρά, θα πρέπει να ξεκινήσετε με τον παρακάτω τρόπο:
|
|
||||||
```bash
|
|
||||||
# Start uinput service
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Σημείωση**: Η εγγραφή οθόνης του 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Πως να κάνετε build στο Docker
|
## Πως να κάνετε build στο Docker
|
||||||
|
|
||||||
Ξεκινήστε κλωνοποιώντας το αποθετήριο και κάνοντας build το docker container:
|
Ξεκινήστε κλωνοποιώντας το αποθετήριο και κάνοντας build το docker container:
|
||||||
@@ -189,7 +145,7 @@ target/debug/rustdesk
|
|||||||
target/release/rustdesk
|
target/release/rustdesk
|
||||||
```
|
```
|
||||||
|
|
||||||
Βεβαιωθείτε ότι εκτελείτε αυτές τις εντολές από την αρχική διαδρομή του αποθετηρίου του Rustdesk, διαφορετικά η εφαρμογή ενδέχεται να μην είναι σε θέση να βρεί τους απαιτούμενους πόρους. Σημειώστε επίσης ότι άλλες υποεντολές, όπως το `install` ή το `run` δεν υποστηρίζονται επί του παρόντος μέσω αυτής της μεθόδου καθώς θα εγκαταστήσουν ή θα εκτελέσουν το πρόγραμμα εντός του container αντί του κεντρικού υπολογιστή.
|
Βεβαιωθείτε ότι εκτελείτε αυτές τις εντολές από την αρχική διαδρομή του αποθετηρίου του RustDesk, διαφορετικά η εφαρμογή ενδέχεται να μην είναι σε θέση να βρεί τους απαιτούμενους πόρους. Σημειώστε επίσης ότι άλλες υποεντολές, όπως το `install` ή το `run` δεν υποστηρίζονται επί του παρόντος μέσω αυτής της μεθόδου καθώς θα εγκαταστήσουν ή θα εκτελέσουν το πρόγραμμα εντός του container αντί του κεντρικού υπολογιστή.
|
||||||
|
|
||||||
## Δομή φακέλων
|
## Δομή φακέλων
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,6 @@ A RustDesk szívesen fogad minden contributiont, támogatást mindenkitől. Lás
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Ingyenes publikus szerverek
|
|
||||||
|
|
||||||
Ezalatt az üzenet alatt találhatóak azok a publikus szerverek, amelyeket ingyen használhatsz. Ezek a szerverek változhatnak a jövőben, illetve a hálózatuk lehet hogy lassú lehet.
|
|
||||||
| Hely | Host | Specifikáció |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Az asztali verziók [sciter](https://sciter.com/)-t használnak a GUI-hoz, kérlek telepítsd a dynamikus könyvtárat magad.
|
Az asztali verziók [sciter](https://sciter.com/)-t használnak a GUI-hoz, kérlek telepítsd a dynamikus könyvtárat magad.
|
||||||
@@ -116,10 +108,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Válts Wayland-ról X11-re (Xorg)
|
|
||||||
|
|
||||||
A RustDesk nem támogatja a Waylendet. [Itt](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) található egy tutorial amelynek segítségével beállíthatod a Xorg-ot mint alap GNOME session.
|
|
||||||
|
|
||||||
## Hogyan építs Dockerrel
|
## Hogyan építs Dockerrel
|
||||||
|
|
||||||
Kezdjünk a repo clónozásával, majd pedig a Docker container megépítésével:
|
Kezdjünk a repo clónozásával, majd pedig a Docker container megépítésével:
|
||||||
|
|||||||
@@ -13,29 +13,27 @@ Mari mengobrol bersama kami: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter
|
|||||||
|
|
||||||
[](https://ko-fi.com/I2I04VU09)
|
[](https://ko-fi.com/I2I04VU09)
|
||||||
|
|
||||||
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).
|
[](https://console.algora.io/org/rustdesk/bounties?status=open)
|
||||||
|
|
||||||
RustDesk mengajak semua orang untuk ikut berkontribusi. Lihat [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) untuk melihat panduan.
|
Merupakan perangkat lunak Remote Desktop yang baru, dan dibangun dengan Rust. Bahkan kamu bisa langsung menggunakannya tanpa perlu melakukan konfigurasi tambahan. Serta memiliki 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 mengajak semua orang untuk ikut berkontribusi. Lihat [`docs/CONTRIBUTING-ID.md`](CONTRIBUTING-ID.md) untuk melihat panduan.
|
||||||
|
|
||||||
|
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||||
|
|
||||||
[**UNDUH BINARY**](https://github.com/rustdesk/rustdesk/releases)
|
[**UNDUH BINARY**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Server Publik Gratis
|
[**NIGHTLY BUILD**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
|
||||||
|
|
||||||
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.
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
| Lokasi | Penyedia | Spesifikasi |
|
alt="Get it on F-Droid"
|
||||||
| --------- | ------------- | ------------------ |
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
| Jerman | [Hetzner](https://www.hetzner.com) | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraina (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dev Container
|
|
||||||
|
|
||||||
[](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
|
## Dependensi
|
||||||
|
|
||||||
Pada versi desktop, antarmuka pengguna (GUI) menggunakan [Sciter](https://sciter.com/) atau flutter, tutorial ini hanya berlaku untuk Sciter
|
Pada versi desktop, antarmuka pengguna (GUI) menggunakan [Sciter](https://sciter.com/) atau flutter
|
||||||
|
|
||||||
Kamu bisa mengunduh Sciter dynamic library disini.
|
Kamu bisa mengunduh Sciter dynamic library disini.
|
||||||
|
|
||||||
@@ -116,37 +114,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### 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 standar di GNOME.
|
|
||||||
|
|
||||||
## Kompatibilitas dengan Wayland
|
|
||||||
|
|
||||||
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
|
## Cara Build dengan Docker
|
||||||
|
|
||||||
Mulailah dengan melakukan kloning (clone) repositori dan build dengan docker container:
|
Mulailah dengan melakukan kloning (clone) repositori dan build dengan docker container:
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<a href="#passaggi-per-la-compilazione">Compilazione</a> •
|
<a href="#passaggi-per-la-compilazione">Compilazione</a> •
|
||||||
<a href="#come-compilare-con-docker">Docker</a> •
|
<a href="#come-compilare-con-docker">Docker</a> •
|
||||||
<a href="#struttura-dei-file">Struttura</a> •
|
<a href="#struttura-dei-file">Struttura</a> •
|
||||||
<a href="#screenshots">Schermate</a><br>
|
<a href="#schermate">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>
|
[<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-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>]<br>
|
||||||
<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>
|
<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>
|
</p>
|
||||||
|
|
||||||
@@ -13,28 +13,29 @@ Chatta con noi su: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://
|
|||||||
|
|
||||||
[](https://ko-fi.com/I2I04VU09)
|
[](https://ko-fi.com/I2I04VU09)
|
||||||
|
|
||||||
Ancora un altro software per il controllo remoto del desktop, scritto in Rust.
|
[](https://console.algora.io/org/rustdesk/bounties?status=open)
|
||||||
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.
|
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).
|
||||||
Per ulteriori informazioni su come iniziare a contribuire, vedi [`docs/CONTRIBUTING-IT.md`](CONTRIBUTING.md).
|
|
||||||
|
|
||||||
[**DOWNLOAD PROGRAMMA**](https://github.com/rustdesk/rustdesk/releases)
|

|
||||||
|
|
||||||
## Server pubblici gratuiti
|
RustDesk accoglie il contributo di tutti. Per ulteriori informazioni su come iniziare a contribuire, vedi [CONTRIBUTING.md](CONTRIBUTING-IT.md).
|
||||||
|
|
||||||
Qui sotto trovi i server che possono essere usati gratuitamente, la lista potrebbe cambiare nel tempo.
|
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||||
Se non sei vicino a uno di questi server, la connessione potrebbe essere lenta.
|
|
||||||
|
|
||||||
| Posizione | Venditore | Specifiche |
|
[**SCARICA PROGRAMMA**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germania | Hetzner | 2 vCPU / 4GB RAM |
|
[**SCARICA NIGHTLY**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
|
||||||
| Ucraina (Kyev) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
[<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)
|
||||||
|
|
||||||
## Dipendenze
|
## Dipendenze
|
||||||
|
|
||||||
La versione Desktop usa per la GUI [sciter](https://sciter.com/), per favore scarica la libreria dinamica sciter.
|
Le versioni desktop utilizzano Flutter o Sciter (deprecato) per l'interfaccia utente, questo tutorial è solo per Sciter, poiché è più facile per iniziare. Controlla il nostro [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) per la compilazione della versione Flutter.
|
||||||
|
|
||||||
|
Scarica la libreria dinamica Sciter.
|
||||||
|
|
||||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
[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) |
|
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||||
@@ -51,12 +52,22 @@ La versione Desktop usa per la GUI [sciter](https://sciter.com/), per favore sca
|
|||||||
|
|
||||||
- Esegui `cargo run`
|
- Esegui `cargo run`
|
||||||
|
|
||||||
|
## [Build](https://rustdesk.com/docs/en/dev/build/)
|
||||||
|
|
||||||
## Come compilare in Linux
|
## Come compilare in Linux
|
||||||
|
|
||||||
### Ubuntu 18 (Debian 10)
|
### Ubuntu 18 (Debian 10)
|
||||||
|
|
||||||
```sh
|
```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)
|
### Fedora 28 (CentOS 8)
|
||||||
@@ -109,11 +120,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cambiare Wayland in X11 (Xorg)
|
|
||||||
|
|
||||||
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
|
## Come compilare con Docker
|
||||||
|
|
||||||
Clona il repository e compila i container docker:
|
Clona il repository e compila i container docker:
|
||||||
@@ -130,10 +136,7 @@ Quindi, ogni volta che devi compilare l'applicazione, esegui il seguente comando
|
|||||||
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
|
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.
|
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:
|
||||||
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
|
```sh
|
||||||
target/debug/rustdesk
|
target/debug/rustdesk
|
||||||
@@ -145,19 +148,21 @@ Oppure, se stai avviando un eseguibile di rilascio:
|
|||||||
target/release/rustdesk
|
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.
|
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.
|
||||||
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
|
## Struttura dei file
|
||||||
|
|
||||||
- **[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/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/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
|
- **[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
|
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: implementazione del copia e incolla dei file per Windows, Linux, macOS.
|
||||||
|
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: Sciter UI obsoleto (deprecato)
|
||||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: servizi audio/appunti/input/video e connessioni di rete
|
- **[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)**: avvio di 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/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
|
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: codice specifico della piattaforma
|
||||||
|
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: codice Flutter per desktop e mobile
|
||||||
|
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript per client web Flutter
|
||||||
|
|
||||||
## Schermate
|
## Schermate
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ RustDeskは誰からの貢献も歓迎します。 貢献するには [`docs/CON
|
|||||||
|
|
||||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## 無料のパブリックサーバー
|
|
||||||
|
|
||||||
下記のサーバーは、無料で使用できますが、後々変更されることがあります。これらのサーバーから遠い場合、接続が遅い可能性があります。
|
|
||||||
| Location | Vendor | Specification |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## 依存関係
|
## 依存関係
|
||||||
|
|
||||||
デスクトップ版ではGUIに [sciter](https://sciter.com/) が使われています。 sciter dynamic library をダウンロードしてください。
|
デスクトップ版ではGUIに [sciter](https://sciter.com/) が使われています。 sciter dynamic library をダウンロードしてください。
|
||||||
@@ -114,11 +107,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg 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セッションとして構成します。
|
|
||||||
|
|
||||||
## Dockerでビルドする方法
|
## Dockerでビルドする方法
|
||||||
|
|
||||||
リポジトリのクローンを作成し、Dockerコンテナを構築することから始めます。
|
リポジトリのクローンを作成し、Dockerコンテナを構築することから始めます。
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ RustDesk는 모든 기여를 환영합니다. 기여하고자 한다면 [`docs/C
|
|||||||
|
|
||||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## 무료 퍼블릭 서버
|
|
||||||
|
|
||||||
표에 있는 서버는 무료로 사용할 수 있지만 추후 변경될 수도 있습니다. 이 서버에서 멀다면, 네트워크가 느려질 가능성도 있습니다.
|
|
||||||
| Location | Vendor | Specification |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## 의존관계
|
## 의존관계
|
||||||
|
|
||||||
데스크탑판에는 GUI에 [sciter](https://sciter.com/)가 사용되었습니다. sciter dynamic library 를 다운로드해주세요.
|
데스크탑판에는 GUI에 [sciter](https://sciter.com/)가 사용되었습니다. sciter dynamic library 를 다운로드해주세요.
|
||||||
@@ -112,10 +105,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg 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 세션을 구성합니다.
|
|
||||||
|
|
||||||
## Docker에 빌드하는 방법
|
## Docker에 빌드하는 방법
|
||||||
|
|
||||||
레포지토리를 클론하고, Docker 컨테이너 구성하는 것으로 시작합니다.
|
레포지토리를 클론하고, Docker 컨테이너 구성하는 것으로 시작합니다.
|
||||||
|
|||||||
@@ -19,13 +19,6 @@
|
|||||||
|
|
||||||
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## സൗജന്യ പൊതു സെർവറുകൾ
|
|
||||||
|
|
||||||
നിങ്ങൾ സൗജന്യമായി ഉപയോഗിക്കുന്ന സെർവറുകൾ ചുവടെയുണ്ട്, അത് സമയത്തിനനുസരിച്ച് മാറിയേക്കാം. നിങ്ങൾ ഇവയിലൊന്നിനോട് അടുത്തല്ലെങ്കിൽ, നിങ്ങളുടെ നെറ്റ്വർക്ക് സ്ലോ ആയേക്കാം.
|
|
||||||
| സ്ഥാനം | കച്ചവടക്കാരൻ | വിവരണം |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## ഡിപെൻഡൻസികൾ
|
## ഡിപെൻഡൻസികൾ
|
||||||
|
|
||||||
ഡെസ്ക്ടോപ്പ് പതിപ്പുകൾ GUI-യ്ക്കായി [sciter](https://sciter.com/) ഉപയോഗിക്കുന്നു, ദയവായി സ്സൈറ്റർ ഡൈനാമിക് ലൈബ്രറി സ്വയം ഡൗൺലോഡ് ചെയ്യുക.
|
ഡെസ്ക്ടോപ്പ് പതിപ്പുകൾ GUI-യ്ക്കായി [sciter](https://sciter.com/) ഉപയോഗിക്കുന്നു, ദയവായി സ്സൈറ്റർ ഡൈനാമിക് ലൈബ്രറി സ്വയം ഡൗൺലോഡ് ചെയ്യുക.
|
||||||
@@ -103,10 +96,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### വേലാൻഡ് X11 (Xorg) ആയി മാറ്റുക
|
|
||||||
|
|
||||||
RustDesk Wayland-നെ പിന്തുണയ്ക്കുന്നില്ല. സ്ഥിരസ്ഥിതി ഗ്നോം സെഷനായി Xorg കോൺഫിഗർ ചെയ്യുന്നതിന് [ഇത്](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) പരിശോധിക്കുക.
|
|
||||||
|
|
||||||
## ഡോക്കർ ഉപയോഗിച്ച് എങ്ങനെ നിർമ്മിക്കാം
|
## ഡോക്കർ ഉപയോഗിച്ച് എങ്ങനെ നിർമ്മിക്കാം
|
||||||
|
|
||||||
റെപ്പോസിറ്റോറി ക്ലോണുചെയ്ത് ഡോക്കർ കണ്ടെയ്നർ നിർമ്മിക്കുന്നതിലൂടെ ആരംഭിക്കുക:
|
റെപ്പോസിറ്റോറി ക്ലോണുചെയ്ത് ഡോക്കർ കണ്ടെയ്നർ നിർമ്മിക്കുന്നതിലൂടെ ആരംഭിക്കുക:
|
||||||
|
|||||||
@@ -27,22 +27,6 @@ RustDesk verwelkomt bijdragen van iedereen. Zie [`docs/CONTRIBUTING.md`](CONTRIB
|
|||||||
alt="Download het op F-Droid"
|
alt="Download het op F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Gratis openbare servers
|
|
||||||
|
|
||||||
Hieronder staan de servers die u gratis gebruikt, ze kunnen in de loop van de tijd veranderen. Als u niet in de buurt van een van deze servers bevindt, kan uw vervinding langzamer zijn.
|
|
||||||
| Locatie | Aanbieder | Specificaties |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Duitsland | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Oekraine (Kyiv) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dev Container
|
|
||||||
|
|
||||||
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/rustdesk/rustdesk)
|
|
||||||
|
|
||||||
Als u VS Code en Docker al hebt geinstalleerd, kunt u op de bovenstaande badge klikken om te beginnen. Door te klikken zal VS Code automatisch de Dev Containers-extensie installeren indien nodig, de broncode klonen naar een containervolume en een dev container opstarten voor gebruik.
|
|
||||||
|
|
||||||
Bekijk [DEVCONTAINER.md](docs/DEVCONTAINER.md) voor meer informatie.
|
|
||||||
|
|
||||||
## Afhankelijkheden
|
## Afhankelijkheden
|
||||||
|
|
||||||
Desktop versies gebruiken [sciter](https://sciter.com/) of Flutter voor GUI, deze handleiding is alleen voor Sciter.
|
Desktop versies gebruiken [sciter](https://sciter.com/) of Flutter voor GUI, deze handleiding is alleen voor Sciter.
|
||||||
@@ -130,34 +114,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wissel van Wayland naar X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk ondersteunt Wayland niet. Lees [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) hoe je Xorg als standaardsessie kunt instellen voor GNOME.
|
|
||||||
|
|
||||||
## Wayland support
|
|
||||||
|
|
||||||
Wayland lijkt geen API te bieden voor het verzenden van toetsaanslagen naar andere vensters. Daarom gebruikt de rustdesk een API van een lager niveau, namelijk het `/dev/uinput` apparaat (Linux kernel niveau).
|
|
||||||
|
|
||||||
Als wayland de gecontroleerde kant is, moet je op de volgende manier beginnen:
|
|
||||||
```bash
|
|
||||||
# Start uinput service
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Let op**: Wayland schermopname gebruikt verschillende interfaces. RustDesk ondersteunt momenteel alleen 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Bouwen met Docker
|
## Bouwen met Docker
|
||||||
|
|
||||||
Begin met het klonen van de repository en het bouwen van de docker container:
|
Begin met het klonen van de repository en het bouwen van de docker container:
|
||||||
|
|||||||
@@ -29,22 +29,6 @@ RustDesk zaprasza do współpracy każdego. Zobacz [`docs/CONTRIBUTING-PL.md`](C
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Darmowe Serwery Publiczne
|
|
||||||
|
|
||||||
Poniżej znajdują się serwery, z których można korzystać za darmo, może się to zmienić z upływem czasu. Jeśli nie znajdujesz się w pobliżu jednego z nich, Twoja prędkość połączenia może być niska.
|
|
||||||
| Lokalizacja | Dostawca | Specyfikacja |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Niemcy | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
| Ukraina (Kijów) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Konterner Programisty (Dev Container)
|
|
||||||
|
|
||||||
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/rustdesk/rustdesk)
|
|
||||||
|
|
||||||
Jeżeli masz zainstalowany VS Code i Docker, możesz kliknąć w powyższy link, aby rozpocząć. Kliknięcie spowoduje automatyczną instalację rozszrzenia Kontenera Programisty w VS Code (jeżeli wymagany), sklonuje kod źródłowy do kontenera, i przygotuje kontener do użycia.
|
|
||||||
|
|
||||||
Więcej informacji w pliku [DEVCONTAINER-PL.md](docs/DEVCONTAINER-PL.md) for more info.
|
|
||||||
|
|
||||||
## Zależności
|
## Zależności
|
||||||
|
|
||||||
Wersje desktopowe używają [sciter](https://sciter.com/) dla GUI, proszę pobrać samodzielnie bibliotekę sciter.
|
Wersje desktopowe używają [sciter](https://sciter.com/) dla GUI, proszę pobrać samodzielnie bibliotekę sciter.
|
||||||
@@ -128,34 +112,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
cargo run
|
cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Zmień Wayland na X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk nie obsługuje Waylanda. Sprawdź [tutaj](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/), jak skonfigurować Xorg jako domyślną sesję GNOME.
|
|
||||||
|
|
||||||
## Wspracie Wayland
|
|
||||||
|
|
||||||
Wygląda na to, że Wayland nie wspiera żadnego API do wysyłania naciśnięć klawiszy do innych okien. Dlatego rustdesk używa API z niższego poziomu, urządzenia o nazwie `/dev/uinput` (poziom jądra Linux).
|
|
||||||
|
|
||||||
Gdy po stronie kontrolowanej pracuje Wayland, musisz uruchomić program w następujący sposób:
|
|
||||||
```bash
|
|
||||||
# Start uinput service
|
|
||||||
$ sudo rustdesk --service
|
|
||||||
$ rustdesk
|
|
||||||
```
|
|
||||||
**Uwaga**: Nagrywanie ekranu Wayland wykorzystuje różne interfejsy. RustDesk obecnie obsługuje tylko 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Jak kompilować za pomocą Dockera
|
## Jak kompilować za pomocą Dockera
|
||||||
|
|
||||||
Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker:
|
Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker:
|
||||||
|
|||||||
@@ -19,14 +19,6 @@ RustDesk acolhe contribuições de todos. Leia [`docs/CONTRIBUTING.md`](CONTRIBU
|
|||||||
|
|
||||||
[**DOWNLOAD DE BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
|
[**DOWNLOAD DE BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
## Servidores Públicos Grátis
|
|
||||||
|
|
||||||
Abaixo estão os servidores que você está utilizando de graça, ele pode mudar com o tempo. Se você não está próximo de algum deles, sua conexão pode ser lenta.
|
|
||||||
|
|
||||||
| Localização | Fornecedor | Especificações |
|
|
||||||
| ----------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dependências
|
## Dependências
|
||||||
|
|
||||||
Versões de desktop utilizam [sciter](https://sciter.com/) para a GUI, por favor baixe a biblioteca dinâmica sciter por conta própria.
|
Versões de desktop utilizam [sciter](https://sciter.com/) para a GUI, por favor baixe a biblioteca dinâmica sciter por conta própria.
|
||||||
@@ -104,10 +96,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mude Wayland para X11 (Xorg)
|
|
||||||
|
|
||||||
RustDesk não suporta Wayland. Veja [esse link](https://docs.fedoraproject.org/pt_BR/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar o Xorg como a sessão padrão do GNOME.
|
|
||||||
|
|
||||||
## Como compilar com Docker
|
## Como compilar com Docker
|
||||||
|
|
||||||
Comece clonando o repositório e montando o container docker:
|
Comece clonando o repositório e montando o container docker:
|
||||||
|
|||||||
@@ -28,13 +28,6 @@ RustDesk приветствует вклад каждого. Ознакомьт
|
|||||||
|
|
||||||
[<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)
|
[<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)
|
||||||
|
|
||||||
## Бесплатные общедоступные серверы
|
|
||||||
|
|
||||||
Ниже приведены бесплатные публичные сервера, используемые по умолчанию. Имейте ввиду, они могут меняться со временем. Также стоит отметить, что скорость работы сети зависит от вашего местоположения и расстояния до серверов. Подключение происходит к ближайшему доступному.
|
|
||||||
| Расположение | Поставщик | Технические характеристики |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Германия | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Зависимости
|
## Зависимости
|
||||||
|
|
||||||
Настольные версии используют [sciter](https://sciter.com/) для графического интерфейса, загрузите динамическую библиотеку sciter самостоятельно.
|
Настольные версии используют [sciter](https://sciter.com/) для графического интерфейса, загрузите динамическую библиотеку sciter самостоятельно.
|
||||||
@@ -114,10 +107,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg 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 по умолчанию.
|
|
||||||
|
|
||||||
## Как собрать с помощью Docker
|
## Как собрать с помощью Docker
|
||||||
|
|
||||||
Начните с клонирования репозитория и создания docker-контейнера:
|
Начните с клонирования репозитория и создания docker-контейнера:
|
||||||
|
|||||||
178
docs/README-TR.md
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="../res/logo-header.svg" alt="RustDesk - Uzak masaüstü uygulamanız"><br>
|
||||||
|
<a href="#free-public-servers">Sunucular</a> •
|
||||||
|
<a href="#raw-steps-to-build">Derleme</a> •
|
||||||
|
<a href="#how-to-build-with-docker">Docker ile Derleme</a> •
|
||||||
|
<a href="#file-structure">Dosya Yapısı</a> •
|
||||||
|
<a href="#snapshot">Ekran Görüntüleri</a><br>
|
||||||
|
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>]<br>
|
||||||
|
<b>README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> ve <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Belge</a>'sini ana dilinize çevirmemiz için yardımınıza ihtiyacımız var</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Bizimle sohbet edin: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||||
|
|
||||||
|
[](https://ko-fi.com/I2I04VU09)
|
||||||
|
|
||||||
|
Başka bir uzak masaüstü yazılımı daha, Rust dilinde yazılmış. Hemen kullanıma hazır, hiçbir yapılandırma gerektirmez. Verilerinizin tam kontrolünü elinizde tutarsınız ve güvenlikle ilgili endişeleriniz olmaz. Kendi buluş/iletme sunucumuzu kullanabilirsiniz, [kendi sunucunuzu kurabilirsiniz](https://rustdesk.com/server) veya [kendi buluş/iletme sunucunuzu yazabilirsiniz](https://github.com/rustdesk/rustdesk-server-demo).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
RustDesk, herkesten katkıyı kabul eder. Başlamak için [CONTRIBUTING.md](docs/CONTRIBUTING-TR.md) belgesine göz atın.
|
||||||
|
|
||||||
|
[**SSS**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||||
|
|
||||||
|
[**BİNARİ İNDİR**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
|
[**NİGHTLY DERLEME**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
|
||||||
|
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="F-Droid'de Alın"
|
||||||
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
|
## Bağımlılıklar
|
||||||
|
|
||||||
|
Masaüstü sürümleri GUI için
|
||||||
|
|
||||||
|
[Sciter](https://sciter.com/) veya Flutter kullanır, bu kılavuz sadece Sciter içindir.
|
||||||
|
|
||||||
|
Lütfen Sciter dinamik kütüphanesini kendiniz indirin.
|
||||||
|
|
||||||
|
[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)
|
||||||
|
|
||||||
|
## Temel Derleme Adımları
|
||||||
|
|
||||||
|
- Rust geliştirme ortamınızı ve C++ derleme ortamınızı hazırlayın.
|
||||||
|
|
||||||
|
- [vcpkg](https://github.com/microsoft/vcpkg) yükleyin ve `VCPKG_ROOT` çevresel değişkenini doğru bir şekilde ayarlayın.
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- `cargo run` komutunu çalıştırın.
|
||||||
|
|
||||||
|
## [Derleme](https://rustdesk.com/docs/en/dev/build/)
|
||||||
|
|
||||||
|
## Linux Üzerinde Derleme Nasıl Yapılır
|
||||||
|
|
||||||
|
### Ubuntu 18 (Debian 10)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
|
||||||
|
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
|
||||||
|
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arch (Manjaro)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
|
||||||
|
```
|
||||||
|
|
||||||
|
### vcpkg'yi Yükleyin
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/microsoft/vcpkg
|
||||||
|
cd vcpkg
|
||||||
|
git checkout 2023.04.15
|
||||||
|
cd ..
|
||||||
|
vcpkg/bootstrap-vcpkg.sh
|
||||||
|
export VCPKG_ROOT=$HOME/vcpkg
|
||||||
|
vcpkg/vcpkg install libvpx libyuv opus aom
|
||||||
|
```
|
||||||
|
|
||||||
|
### libvpx'i Düzeltin (Fedora için)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd vcpkg/buildtrees/libvpx/src
|
||||||
|
cd *
|
||||||
|
./configure
|
||||||
|
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
|
||||||
|
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
|
||||||
|
make
|
||||||
|
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
||||||
|
cd
|
||||||
|
```
|
||||||
|
|
||||||
|
### Derleme
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
source $HOME/.cargo/env
|
||||||
|
git clone https://github.com/rustdesk/rustdesk
|
||||||
|
cd rustdesk
|
||||||
|
mkdir -p target/debug
|
||||||
|
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
|
||||||
|
mv libsciter-gtk.so target/debug
|
||||||
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker ile Derleme Nasıl Yapılır
|
||||||
|
|
||||||
|
Öncelikle deposunu klonlayın ve Docker konteynerini oluşturun:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/rustdesk/rustdesk
|
||||||
|
cd rustdesk
|
||||||
|
docker build -t "rustdesk-builder" .
|
||||||
|
```
|
||||||
|
|
||||||
|
Ardından, uygulamayı derlemek için her seferinde aşağıdaki komutu çalıştırın:
|
||||||
|
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
İlk derleme, bağımlılıklar önbelleğe alınmadan önce daha uzun sürebilir, sonraki derlemeler daha hızlı olacaktır. Ayrıca, derleme komutuna isteğe bağlı argümanlar belirtmeniz gerekiyorsa, bunu
|
||||||
|
|
||||||
|
komutun sonunda `<İSTEĞE BAĞLI-ARGÜMANLAR>` pozisyonunda yapabilirsiniz. Örneğin, optimize edilmiş bir sürümü derlemek isterseniz, yukarıdaki komutu çalıştırdıktan sonra `--release` ekleyebilirsiniz. Oluşan yürütülebilir dosya sisteminizdeki hedef klasöründe bulunacak ve şu komutla çalıştırılabilir:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
target/debug/rustdesk
|
||||||
|
```
|
||||||
|
|
||||||
|
Veya, yayın yürütülebilir dosyası çalıştırılıyorsa:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
target/release/rustdesk
|
||||||
|
```
|
||||||
|
|
||||||
|
Lütfen bu komutları RustDesk deposunun kökünden çalıştırdığınızdan emin olun, aksi takdirde uygulama gereken kaynakları bulamayabilir. Ayrıca, `install` veya `run` gibi diğer cargo altkomutları şu anda bu yöntem aracılığıyla desteklenmemektedir, çünkü bunlar programı konteyner içinde kurar veya çalıştırır ve ana makinede değil.
|
||||||
|
|
||||||
|
## Dosya Yapısı
|
||||||
|
|
||||||
|
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video kodlayıcı, yapılandırma, tcp/udp sarmalayıcı, protobuf, dosya transferi için fs işlevleri ve diğer bazı yardımcı işlevler
|
||||||
|
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: ekran yakalama
|
||||||
|
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platforma özgü klavye/fare kontrolü
|
||||||
|
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
|
||||||
|
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: ses/pasta/klavye/video hizmetleri ve ağ bağlantıları
|
||||||
|
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: bir eş bağlantısı başlatır
|
||||||
|
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server) ile iletişim kurar, uzak doğrudan (TCP delik vurma) veya iletme bağlantısını bekler
|
||||||
|
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platforma özgü kod
|
||||||
|
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: mobil için Flutter kodu
|
||||||
|
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Flutter web istemcisi için JavaScript
|
||||||
|
|
||||||
|
## Ekran Görüntüleri
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
```
|
||||||
@@ -1,71 +1,59 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="../res/logo-header.svg" alt="RustDesk - Ваш віддалений робочий стіл"><br>
|
<img src="../res/logo-header.svg" alt="RustDesk - Ваша віддалена стільниця"><br>
|
||||||
<a href="#безкоштовні-загальнодоступні-сервери">Сервери</a> •
|
<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> •
|
||||||
<a href="#знімки">Знімки</a><br>
|
<a href="#знімки">Знімки</a><br>
|
||||||
[<a href="../README.md">English</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
|
[<a href="../README.md">English</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>]<br>
|
||||||
<b>Нам потрібна ваша допомога для перекладу цього README і <a href="https://github.com/rustdesk/rustdesk/tree/master/src/rustdesk/tree/master/src/lang">RustDesk UI</a> на вашу рідну мову</B>
|
<b>Нам потрібна ваша допомога для перекладу цього README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">інтерфейсу</a> та <a href="https://github.com/rustdesk/doc.rustdesk.com">документації</a> RustDesk на вашу рідну мову</B>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Спілкування з нами: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
Спілкування з нами: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||||
|
|
||||||
[](https://ko-fi.com/I2I04VU09)
|
[](https://ko-fi.com/I2I04VU09)
|
||||||
|
|
||||||
Ще одне програмне забезпечення для віддаленого робочого столу, написане на Rust. Працює з коробки, не потребує налаштування. Ви повністю контролюєте свої дані, не турбуючись про безпеку. Ви можете використовувати наш сервер ретрансляції, [налаштувати свій власний](https://rustdesk.com/server), або [написати свій власний сервер ретрансляції](https://github.com/rustdesk/rustdesk-server-demo).
|
[](https://console.algora.io/org/rustdesk/bounties?status=open)
|
||||||
|
|
||||||
|
Ще один застосунок для віддаленого керування стільницею, написаний на Rust. Працює з коробки, не потребує налаштування. Ви повністю контролюєте свої дані, не турбуючись про безпеку. Ви можете використовувати наш сервер ретрансляції, [налаштувати свій власний](https://rustdesk.com/server), або [написати свій власний сервер ретрансляції](https://github.com/rustdesk/rustdesk-server-demo).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
RustDesk вітає внесок кожного. Дивіться [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) для допомоги на початку роботи.
|
RustDesk вітає внесок кожного. Ознайомтеся з [CONTRIBUTING.md](docs/CONTRIBUTING.md), щоб отримати допомогу на початковому етапі.
|
||||||
|
|
||||||
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
[**ЧаПи**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||||
|
|
||||||
[**Як працює RustDesk?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F)
|
[**ЗАВАНТАЖЕННЯ ЗАСТОСУНКУ**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
|
|
||||||
[**ЗАВАНТАЖИТИ ЗАСТОСУНОК**](https://github.com/rustdesk/rustdesk/releases)
|
[**НІЧНІ ЗБІРКИ**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
|
||||||
|
|
||||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Безкоштовні загальнодоступні сервери
|
|
||||||
|
|
||||||
Нижче наведені сервери, для безкоштовного використання, вони можуть змінюватися з часом. Якщо ви не перебуваєте поруч з одним із них, ваша мережа може працювати повільно.
|
|
||||||
| Місцезнаходження | Постачальник | Технічні характеристики |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Німеччина | Hetzner | 2 VCPU / 4GB RAM |
|
|
||||||
| Україна (Київ) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB 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, якщо це необхідно, клонує виcхідний код у том контейнера та розгорне контейнер dev для використання.
|
|
||||||
|
|
||||||
Дивіться [DEVCONTAINER.md](docs/DEVCONTAINER.md) для додаткової інфо.
|
|
||||||
|
|
||||||
## Залежності
|
## Залежності
|
||||||
|
|
||||||
Настільні версії використовують [sciter](https://sciter.com/) для графічного інтерфейсу, завантажте динамічну бібліотеку sciter самостійно.
|
Стільничні версії використовують Flutter чи Sciter (застаріле) для графічного інтерфейсу. Ця інструкція лише для Sciter, оскільки він є більш простим та дружнім для початківців. Перегляньте [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) для збірки версії на Flutter.
|
||||||
|
|
||||||
|
Будь ласка, завантажте динамічну бібліотеку Sciter самостійно.
|
||||||
|
|
||||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
[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) |
|
[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)
|
[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
|
- 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
|
- Linux/macOS: vcpkg install libvpx libyuv opus aom
|
||||||
|
|
||||||
- Запустіть `cargo run`
|
- Запустіть `cargo run`
|
||||||
|
|
||||||
|
## [Збирання](https://rustdesk.com/docs/en/dev/build/)
|
||||||
|
|
||||||
## Як зібрати на Linux
|
## Як зібрати на Linux
|
||||||
|
|
||||||
### Ubuntu 18 (Debian 10)
|
### Ubuntu 18 (Debian 10)
|
||||||
@@ -76,11 +64,12 @@ sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxc
|
|||||||
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### openSUSE Tumbleweed
|
### openSUSE Tumbleweed
|
||||||
|
|
||||||
```sh
|
```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
|
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)
|
### Fedora 28 (CentOS 8)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -99,7 +88,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c
|
|||||||
git clone https://github.com/microsoft/vcpkg
|
git clone https://github.com/microsoft/vcpkg
|
||||||
cd vcpkg
|
cd vcpkg
|
||||||
git checkout 2023.04.15
|
git checkout 2023.04.15
|
||||||
cd ...
|
cd ..
|
||||||
vcpkg/bootstrap-vcpkg.sh
|
vcpkg/bootstrap-vcpkg.sh
|
||||||
export VCPKG_ROOT=$HOME/vcpkg
|
export VCPKG_ROOT=$HOME/vcpkg
|
||||||
vcpkg/vcpkg install libvpx libyuv opus aom
|
vcpkg/vcpkg install libvpx libyuv opus aom
|
||||||
@@ -118,7 +107,7 @@ cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
|||||||
cd
|
cd
|
||||||
```
|
```
|
||||||
|
|
||||||
### Збірка
|
### Збирання
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
@@ -131,10 +120,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg 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 за замовчуванням.
|
|
||||||
|
|
||||||
## Як зібрати за допомогою Docker
|
## Як зібрати за допомогою Docker
|
||||||
|
|
||||||
Почніть з клонування сховища та створення docker-контейнера:
|
Почніть з клонування сховища та створення docker-контейнера:
|
||||||
@@ -145,7 +130,7 @@ cd rustdesk
|
|||||||
docker build -t "rustdesk-builder" .
|
docker build -t "rustdesk-builder" .
|
||||||
```
|
```
|
||||||
|
|
||||||
Потім кожного разу, коли вам потрібно зібрати додаток, запускайте таку команду:
|
Надалі щоразу, коли вам буде потрібно зібрати застосунок, запускайте таку команду:
|
||||||
|
|
||||||
```sh
|
```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
|
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
|
||||||
@@ -170,6 +155,7 @@ target/release/rustdesk
|
|||||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: відеокодек, конфіг, обгортка tcp/udp, protobuf, функції fs для передавання файлів і деякі інші службові функції
|
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: відеокодек, конфіг, обгортка tcp/udp, protobuf, функції fs для передавання файлів і деякі інші службові функції
|
||||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: захоплення екрана
|
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: захоплення екрана
|
||||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: специфічне для платформи керування клавіатурою/мишею
|
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: специфічне для платформи керування клавіатурою/мишею
|
||||||
|
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: реалізація копіювання та вставлення файлів для Windows, Linux, macOS.
|
||||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графічний інтерфейс користувача
|
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графічний інтерфейс користувача
|
||||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервіси аудіо/буфера обміну/вводу/відео та мережевих підключень
|
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервіси аудіо/буфера обміну/вводу/відео та мережевих підключень
|
||||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: однорангове з'єднання
|
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: однорангове з'єднання
|
||||||
|
|||||||
@@ -1,64 +1,55 @@
|
|||||||
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="../res/logo-header.svg" alt="RustDesk - Phần mềm điểu khiển máy tính từ xa dành cho bạn"><br>
|
<img src="../res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
|
||||||
<a href="#free-public-servers">Máy chủ</a> •
|
<a href="#free-public-servers">Server</a> •
|
||||||
<a href="#raw-steps-to-build">Build</a> •
|
<a href="#raw-steps-to-build">Build</a> •
|
||||||
<a href="#how-to-build-with-docker">Docker</a> •
|
<a href="#how-to-build-with-docker">Docker</a> •
|
||||||
<a href="#file-structure">Cấu trúc tệp tin</a> •
|
<a href="#file-structure">Structure</a> •
|
||||||
<a href="#snapshot">Snapshot</a><br>
|
<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-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-GR.md">Ελληνικά</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-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-GR.md">Ελληνικά</a>]<br>
|
||||||
<b>Chúng tôi cần sự gíup đỡ của bạn để dịch trang README này, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> và <a href="https://github.com/rustdesk/doc.rustdesk.com">tài liệu</a> sang ngôn ngữ bản địa của bạn</b>
|
<b>Chúng tôi rất hoan nghênh sự hỗ trợ của bạn trong việc dịch trang README, trang giao diện người dùng của RustDesk - <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> và trang tài liệu của RustDesk - <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> sang Tiếng Việt</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Chat với chúng tôi qua: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
Hãy trao đổi với chúng tôi qua: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||||
|
|
||||||
[](https://ko-fi.com/I2I04VU09)
|
[](https://ko-fi.com/I2I04VU09)
|
||||||
|
|
||||||
Một phần mềm điểu khiển máy tính từ xa, đuợc lập trình bằng ngôn ngữ Rust. Hoạt động tức thì, không cần phải cài đặt. Bạn có toàn quyền điểu khiển với dữ liệu của bạn mà không cần phải lo lắng về sự bảo mật. Bạn có thể sử dụng máy chủ rendezvous/relay của chúng tôi, [tự cài đặt máy chủ](https://rustdesk.com/server), hay thậm chí [tự tạo máy chủ rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
|
RustDesk là một phần mềm điểu khiển máy tính từ xa mã nguồn mở, được viết bằng Rust. Nó hoạt động ngay sau khi cài đặt, không yêu cầu cấu hình phức tạp. Bạn có toàn quyền kiểm soát với dữ liệu của mình mà không cần phải lo lắng về vấn đề bảo mật. Bạn có thể sử dụng máy chủ rendezvous/relay của chúng tôi hoặc [tự cài đặt máy chủ của riêng mình](https://rustdesk.com/server) hay thậm chí [tự tạo máy chủ rendezvous/relay cho riêng bạn](https://github.com/rustdesk/rustdesk-server-demo).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Mọi người đều đuợc chào đón để đóng góp vào RustDesk. Để bắt đầu, hãy đọc [`docs/CONTRIBUTING.md`](CONTRIBUTING.md).
|
**RustDesk** luôn hoan nghênh mọi đóng góp từ mọi người. Hãy xem tệp [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) để bắt đầu.
|
||||||
|
|
||||||
[**RustDesk hoạt động như thế nào?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F)
|
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||||
|
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
|
||||||
[**CÁC BẢN PHÂN PHÁT MÃ NHỊ PHÂN**](https://github.com/rustdesk/rustdesk/releases)
|
[**NIGHTLY BUILD**](https://github.com/rustdesk/rustdesk/FAQreleases/tag/nightly)
|
||||||
|
|
||||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## Các Máy Chủ Công Khai Miễn Phí
|
|
||||||
|
|
||||||
Dưới đây là những máy chủ mà bạn có thể sử dụng mà không mất phí, chú ý là máy chủ có thể thay đổi theo thời gian. Nếu địa điểm của bạn không gần một trong số những máy chủ này, thì kết nói có thể chậm.
|
|
||||||
|
|
||||||
| Địa điểm | Nhà cung cấp | Cấu hình |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| Germany | Hetzner | 2 vCPU / 4GB RAM |
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Phiên bản cho máy tính sử dụng [sciter](https://sciter.com/) cho giao diện của phần mềm, vậy nên bạn cần tự tải về thư viện sciter.
|
Phiên bản máy tính sử dụng __Flutter__ hoặc __Sciter__ (đã lỗi thời) cho giao diện người dùng (GUI). Hướng dẫn này chỉ áp dụng cho phiên bản Sciter, vì nó thân thiện và dễ bắt đầu hơn. Hãy kiểm tra [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) của chúng tôi để xây dựng phiên bản Flutter.
|
||||||
|
|
||||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
Vui lòng tự tải thư viện `Sciter` về máy theo hướng dẫn cho từng hệ điều hành.
|
||||||
[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)
|
|
||||||
|
|
||||||
Phiên bản cho điện thoại sử dụng Flutter. Chúng tôi sẽ chuyển sang sử dụng Flutter thay cho Sciter cho phiên bản máy tính.
|
[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)
|
||||||
|
|
||||||
## Cách để build
|
## Các bước build cơ bản
|
||||||
|
|
||||||
- Chuẩn bị môi trường phát triển Rust và môi trường build C++
|
- Chuẩn bị môi trường phát triển Rust và môi trường biên dịch C++
|
||||||
|
|
||||||
- Tải và cài [vcpkg](https://github.com/microsoft/vcpkg), và đặt biến môi trường `VCPKG_ROOT` sao cho đúng.
|
- Tải và cài đặt [`vcpkg`](https://github.com/microsoft/vcpkg), và thiết lập biến môi trường `VCPKG_ROOT`.
|
||||||
|
|
||||||
- Đối với Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
|
|
||||||
- Đối với Linux/MacOS: vcpkg install libvpx libyuv opus aom
|
|
||||||
|
|
||||||
|
- 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`
|
||||||
- Chạy lệnh `cargo run`
|
- Chạy lệnh `cargo run`
|
||||||
|
|
||||||
## [Build](https://rustdesk.com/docs/en/dev/build/)
|
## [Build](https://rustdesk.com/docs/en/dev/build/)
|
||||||
|
|
||||||
## Cách để build cho Linux
|
## Cách build cho Linux
|
||||||
|
|
||||||
### Ubuntu 18 (Debian 10)
|
### Ubuntu 18 (Debian 10)
|
||||||
|
|
||||||
@@ -78,7 +69,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
|
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cách cài vcpkg
|
### Cách cài đặt `vcpkg`
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/microsoft/vcpkg
|
git clone https://github.com/microsoft/vcpkg
|
||||||
@@ -90,7 +81,7 @@ export VCPKG_ROOT=$HOME/vcpkg
|
|||||||
vcpkg/vcpkg install libvpx libyuv opus aom
|
vcpkg/vcpkg install libvpx libyuv opus aom
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cách sửa lỗi libvpx (Dành cho hệ điều hành Fedora)
|
### Cách sửa lỗi `libvpx` (Dành cho hệ điều hành Fedora)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd vcpkg/buildtrees/libvpx/src
|
cd vcpkg/buildtrees/libvpx/src
|
||||||
@@ -103,7 +94,7 @@ cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
|
|||||||
cd
|
cd
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cách build
|
### Build
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
@@ -116,13 +107,9 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg cargo run
|
VCPKG_ROOT=$HOME/vcpkg cargo run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Chuyển từ Wayland sang X11 (Xorg)
|
## Cách build bằng Docker
|
||||||
|
|
||||||
RustDesk hiện không hỗ trợ Wayland. Hãy xem [đường linh ở đây](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) cách để cài đặt Xorg làm session mặc định của GNOME.
|
Bắt đầu bằng cách sao chép repo này về máy tính của bạn và tạo Docker container:
|
||||||
|
|
||||||
## Cách để build sử dụng Docker
|
|
||||||
|
|
||||||
Bắt đầu bằng cách sao chép repo này về máy tính và build cái Docker cointainer:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/rustdesk/rustdesk
|
git clone https://github.com/rustdesk/rustdesk
|
||||||
@@ -130,37 +117,37 @@ cd rustdesk
|
|||||||
docker build -t "rustdesk-builder" .
|
docker build -t "rustdesk-builder" .
|
||||||
```
|
```
|
||||||
|
|
||||||
Rồi mỗi khi bạn chạy ứng dụng, thì hãy chạy lệnh này:
|
Sau đó, mỗi khi bạn chạy ứng dụng, thì hãy chạy dòng lệnh sau:
|
||||||
|
|
||||||
```sh
|
```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
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
Chú ý: Lần build đầu tiên có thể sẽ mất lâu hơn truớc khi các dependecies đuợc lưu lại, những lần build sau sẽ nhanh hơn. Hơn nũa, nếu bạn cần cung cấp các cài đặt lệnh khác cho lệnh build, bạn có thể đặt những cài đặt lệnh này vào cuối lệnh ở phần `<OPTIONAL-ARGS>`. Ví dụ nếu bạn cần build phiên bản đuợc tối ưu hóa, bạn sẽ chạy lệnh trên cùng với cài đặt lệnh ‘--release’. Kết quả build sẽ được lưu trong thư mục target trên máy tính của bạn, và có thể chạy với lệnh:
|
Lưu ý rằng **lần build đầu tiên có thể mất thời gian hơn trước khi các dependencies được lưu vào bộ nhớ cache**, nhưng các lần build sau sẽ nhanh hơn. Ngoài ra, nếu bạn cần chỉ định các đối số khác cho lệnh build, bạn có thể thêm chúng vào cuối lệnh ở phần `<OPTIONAL-ARGS>`. Ví dụ, nếu bạn muốn build phiên bản tối ưu hóa, bạn sẽ chạy lệnh trên với tùy chọn `--release`. Kết quả biên dịch sẽ được lưu trong thư mục target trên máy tính của bạn, và có thể chạy với lệnh:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
target/debug/rustdesk
|
target/debug/rustdesk
|
||||||
```
|
```
|
||||||
|
|
||||||
Nếu bạn đang chạy bản build đuợc tối ưu hóa, thì bạn có thể chạy với lệnh:
|
Nếu bạn đang chạy bản build được tối ưu hóa, thì bạn có thể chạy với lệnh:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
target/release/rustdesk
|
target/release/rustdesk
|
||||||
```
|
```
|
||||||
|
|
||||||
Hãy đảm bảo là bạn đang chạy những lệnh này từ thu mục rễ của repo RustDesk, vì nếu không thì ứng dụng có thể sẽ không tìm đuợc những tệp tài nguyên cần thiết. Cũng như nhớ rằng những lệnh con của cargo như `install` hoặc `run` hiện chưa được hỗ trợ bởi phương pháp này vì chúng sẽ cài đặt hoặc chạy ứng dụng trong container thay vì trên máy tính của bạn.
|
Hãy đảm bảo rằng bạn đang chạy các lệnh này từ gốc của thư mục **RustDesk**, nếu không, ứng dụng có thể không thể tìm thấy các tệp tài nguyên cần thiết. Hãy lưu ý rằng các câu lệnh con khác của **cargo** như **install** hoặc **run** hiện không được hỗ trợ qua phương pháp này, vì chúng sẽ cài đặt hoặc chạy chương trình bên trong **container** thay vì trên máy tính của bạn.
|
||||||
|
|
||||||
## Cấu trúc tệp tin
|
## Cấu trúc tệp tin
|
||||||
|
|
||||||
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, cấu hình, tcp/udp wrapper, protobuf, fs functions để truyền file, và một số hàm tiện ích khác
|
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, cấu hình, tcp/udp wrapper, protobuf, fs functions để truyền file, và một số hàm tiện ích khác
|
||||||
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: để ghi lại màn hình
|
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: ghi lại màn hình
|
||||||
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: để điều khiển máy tính/con chuột trên những nền tảng khác nhau
|
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: điều khiển máy tính/chuột trên các nền tảng khác nhau
|
||||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: giao diện người dùng
|
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: giao diện người dùng
|
||||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: các dịch vụ âm thanh, clipboard, đầu vào, video và các kết nối mạng
|
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: các dịch vụ âm thanh, clipboard, đầu vào, video và các kết nối mạng
|
||||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: để bắt đầu kết nối với một peer
|
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: bắt đầu kết nối với một peer
|
||||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Để liên lạc với [rustdesk-server](https://github.com/rustdesk/rustdesk-server), đợi cho kết nối trực tiếp (TCP hole punching) hoặc kết nối được relayed.
|
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: giao tiếp với [rustdesk-server](https://github.com/rustdesk/rustdesk-server), đợi kết nối trực tiếp (TCP hole punching) hoặc kết nối được chuyển tiếp.
|
||||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: mã nguồn riêng cho mỗi nền tảng
|
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: mã nguồn riêng cho mỗi nền tảng
|
||||||
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Mã Flutter dành cho điện thoại
|
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Mã Flutter dành máy tính và điện thoại
|
||||||
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Mã JavaScript dành cho giao diện trên web bằng Flutter
|
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Mã JavaScript dành cho giao diện trên web bằng Flutter
|
||||||
|
|
||||||
## Snapshot
|
## Snapshot
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
RustDesk 期待各位的贡献. 如何参与开发? 详情请看 [CONTRIBUTING.md](docs/CONTRIBUTING.md).
|
RustDesk 期待各位的贡献. 如何参与开发? 详情请看 [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||||
|
|
||||||
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||||
|
|
||||||
@@ -30,23 +30,6 @@ RustDesk 期待各位的贡献. 如何参与开发? 详情请看 [CONTRIBUTING.m
|
|||||||
alt="Get it on F-Droid"
|
alt="Get it on F-Droid"
|
||||||
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
|
||||||
|
|
||||||
## 免费的公共服务器
|
|
||||||
|
|
||||||
以下是您可以使用的、免费的、会随时更新的公共服务器列表,在国内也许网速会很慢或者无法访问。
|
|
||||||
|
|
||||||
| Location | Vendor | Specification |
|
|
||||||
| --------- | ------------- | ------------------ |
|
|
||||||
| 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.
|
|
||||||
|
|
||||||
## 依赖
|
## 依赖
|
||||||
|
|
||||||
桌面版本界面使用[sciter](https://sciter.com/), 请自行下载。
|
桌面版本界面使用[sciter](https://sciter.com/), 请自行下载。
|
||||||
@@ -134,39 +117,6 @@ mv libsciter-gtk.so target/debug
|
|||||||
VCPKG_ROOT=$HOME/vcpkg 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.
|
|
||||||
|
|
||||||
## 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 容器:
|
克隆版本库并构建 Docker 容器:
|
||||||
|
|||||||
9
docs/SECURITY-JP.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# セキュリティポリシー
|
||||||
|
|
||||||
|
## 脆弱性の報告
|
||||||
|
|
||||||
|
私たちはプロジェクトのセキュリティを非常に重視しています。私たちは、すべてのユーザーが脆弱性を発見した場合、私たちに報告することを奨励しています。
|
||||||
|
RustDesk プロジェクトにセキュリティの脆弱性を発見した場合は、info@rustdesk.com までメールで責任を持って報告してください。
|
||||||
|
|
||||||
|
現時点では、バグ報奨金制度はありません。私たちは大きな問題を解決しようとしている小さなチームです。コミュニティ全体のために安全なアプリケーションを作り続けることができるよう、
|
||||||
|
責任を持って脆弱性を報告してください。
|
||||||
9
docs/SECURITY-TR.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Güvenlik Politikası
|
||||||
|
|
||||||
|
## Bir Güvenlik Açığı Bildirme
|
||||||
|
|
||||||
|
Projemiz için güvenliği çok önemsiyoruz. Kullanıcıların keşfettikleri herhangi bir güvenlik açığını bize bildirmelerini teşvik ediyoruz.
|
||||||
|
Eğer RustDesk projesinde bir güvenlik açığı bulursanız, lütfen info@rustdesk.com adresine sorumlu bir şekilde bildirin.
|
||||||
|
|
||||||
|
Şu an için bir hata ödül programımız bulunmamaktadır. Büyük bir sorunu çözmeye çalışan küçük bir ekibiz. Herhangi bir güvenlik açığını sorumlu bir şekilde bildirmenizi rica ederiz,
|
||||||
|
böylece tüm topluluk için güvenli bir uygulama oluşturmaya devam edebiliriz.
|
||||||
@@ -1,36 +1,50 @@
|
|||||||
{
|
{
|
||||||
"id": "com.rustdesk.RustDesk",
|
"id": "com.rustdesk.RustDesk",
|
||||||
"runtime": "org.freedesktop.Platform",
|
"runtime": "org.freedesktop.Platform",
|
||||||
"runtime-version": "21.08",
|
"runtime-version": "23.08",
|
||||||
"sdk": "org.freedesktop.Sdk",
|
"sdk": "org.freedesktop.Sdk",
|
||||||
"command": "rustdesk",
|
"command": "rustdesk",
|
||||||
"icon": "share/icons/hicolor/scalable/apps/rustdesk.svg",
|
"icon": "share/icons/hicolor/scalable/apps/rustdesk.svg",
|
||||||
"modules": [
|
"modules": [
|
||||||
"shared-modules/libappindicator/libappindicator-gtk3-12.10.json",
|
"shared-modules/libappindicator/libappindicator-gtk3-12.10.json",
|
||||||
"xdotool.json",
|
"xdotool.json",
|
||||||
|
{
|
||||||
|
"name": "pam",
|
||||||
|
"buildsystem": "simple",
|
||||||
|
"build-commands": [
|
||||||
|
"./configure --disable-selinux --prefix=/app && make -j4 install"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/linux-pam/linux-pam/releases/download/v1.3.1/Linux-PAM-1.3.1.tar.xz",
|
||||||
|
"sha256": "eff47a4ecd833fbf18de9686632a70ee8d0794b79aecb217ebd0ce11db4cd0db"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "rustdesk",
|
"name": "rustdesk",
|
||||||
"buildsystem": "simple",
|
"buildsystem": "simple",
|
||||||
"build-commands": [
|
"build-commands": [
|
||||||
"bsdtar -zxvf rustdesk-1.2.2.deb",
|
"bsdtar -zxvf rustdesk.deb",
|
||||||
"tar -xvf ./data.tar.xz",
|
"tar -xvf ./data.tar.xz",
|
||||||
"cp -r ./usr/* /app/",
|
"cp -r ./usr/* /app/",
|
||||||
"mkdir -p /app/bin && ln -s /app/lib/rustdesk/rustdesk /app/bin/rustdesk",
|
"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",
|
"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",
|
"mv /app/share/applications/rustdesk-link.desktop /app/share/applications/com.rustdesk.RustDesk-link.desktop",
|
||||||
"sed -i '/^Icon=/ c\\Icon=com.rustdesk.RustDesk' /app/share/applications/rustdesk-link.desktop",
|
"sed -i '/^Icon=/ c\\Icon=com.rustdesk.RustDesk' /app/share/applications/*.desktop",
|
||||||
"mv /app/share/icons/hicolor/scalable/apps/rustdesk.svg /app/share/icons/hicolor/scalable/apps/com.rustdesk.RustDesk.svg",
|
"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"
|
"for size in 16 24 32 48 64 128 256 512; do\n rsvg-convert -w $size -h $size -f png -o $size.png scalable.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"],
|
"cleanup": ["/include", "/lib/pkgconfig", "/share/gtk-doc"],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "../rustdesk-1.2.2.deb"
|
"path": "./rustdesk.deb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "../res/logo.svg"
|
"path": "../res/scalable.svg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1
flutter/.gitignore
vendored
@@ -32,7 +32,6 @@
|
|||||||
/build/
|
/build/
|
||||||
|
|
||||||
# Web related
|
# Web related
|
||||||
lib/generated_plugin_registrant.dart
|
|
||||||
|
|
||||||
# Symbolication related
|
# Symbolication related
|
||||||
app.*.symbols
|
app.*.symbols
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ A few resources to get you started if this is your first Flutter project:
|
|||||||
|
|
||||||
For help getting started with Flutter development, view the
|
For help getting started with Flutter development, view the
|
||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
samples, guidance on mobile development, and a full API reference.
|
samples and guidance on mobile development, and a full API reference.
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
import com.google.protobuf.gradle.*
|
||||||
|
plugins {
|
||||||
|
id "com.google.protobuf" version "0.9.4"
|
||||||
|
}
|
||||||
|
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||||
if (keystorePropertiesFile.exists()) {
|
if (keystorePropertiesFile.exists()) {
|
||||||
@@ -31,10 +36,33 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'com.google.protobuf:protobuf-javalite:3.20.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
protobuf {
|
||||||
|
protoc {
|
||||||
|
artifact = 'com.google.protobuf:protoc:3.20.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
generateProtoTasks {
|
||||||
|
all().configureEach { task ->
|
||||||
|
task.builtins {
|
||||||
|
java {
|
||||||
|
option "lite"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 33
|
compileSdkVersion 33
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
|
||||||
|
main.proto.srcDirs += '../../../libs/hbb_common/protos'
|
||||||
|
main.proto.includes += "message.proto"
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@@ -46,7 +74,7 @@ android {
|
|||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.carriez.flutter_hbb"
|
applicationId "com.carriez.flutter_hbb"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 33
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
@@ -65,6 +93,7 @@ android {
|
|||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,8 +104,7 @@ flutter {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "androidx.media:media:1.6.0"
|
implementation "androidx.media:media:1.6.0"
|
||||||
implementation 'com.github.getActivity:XXPermissions:16.2'
|
implementation 'com.github.getActivity:XXPermissions:18.5'
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib") { version { strictly("$kotlin_version") } }
|
implementation("org.jetbrains.kotlin:kotlin-stdlib") { version { strictly("$kotlin_version") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"project_info": {
|
|
||||||
"project_number": "768133699366",
|
|
||||||
"firebase_url": "https://rustdesk.firebaseio.com",
|
|
||||||
"project_id": "rustdesk",
|
|
||||||
"storage_bucket": "rustdesk.appspot.com"
|
|
||||||
},
|
|
||||||
"client": [
|
|
||||||
{
|
|
||||||
"client_info": {
|
|
||||||
"mobilesdk_app_id": "1:768133699366:android:5fc9015370e344457993e7",
|
|
||||||
"android_client_info": {
|
|
||||||
"package_name": "com.carriez.flutter_hbb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"oauth_client": [
|
|
||||||
{
|
|
||||||
"client_id": "768133699366-s9gdfsijefsd5g1nura4kmfne42lencn.apps.googleusercontent.com",
|
|
||||||
"client_type": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"api_key": [
|
|
||||||
{
|
|
||||||
"current_key": "AIzaSyAPOsKcXjrAR-7Z148sYr_gdB_JQZkamTM"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": {
|
|
||||||
"appinvite_service": {
|
|
||||||
"other_platform_oauth_client": [
|
|
||||||
{
|
|
||||||
"client_id": "768133699366-s9gdfsijefsd5g1nura4kmfne42lencn.apps.googleusercontent.com",
|
|
||||||
"client_type": 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"configuration_version": "1"
|
|
||||||
}
|
|
||||||
4
flutter/android/app/proguard-rules
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Keep class members from protobuf generated code.
|
||||||
|
-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite {
|
||||||
|
<fields>;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
package="com.carriez.flutter_hbb">
|
package="com.carriez.flutter_hbb">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
@@ -61,6 +62,14 @@
|
|||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<!-- Intent for deep linking-->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="rustdesk" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
@@ -81,4 +90,4 @@
|
|||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
package com.carriez.flutter_hbb
|
||||||
|
|
||||||
|
import ffi.FFI
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.*
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.media.projection.MediaProjection
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
const val AUDIO_ENCODING = AudioFormat.ENCODING_PCM_FLOAT // ENCODING_OPUS need API 30
|
||||||
|
const val AUDIO_SAMPLE_RATE = 48000
|
||||||
|
const val AUDIO_CHANNEL_MASK = AudioFormat.CHANNEL_IN_STEREO
|
||||||
|
|
||||||
|
class AudioRecordHandle(private var context: Context, private var isVideoStart: ()->Boolean, private var isAudioStart: ()->Boolean) {
|
||||||
|
private val logTag = "LOG_AUDIO_RECORD_HANDLE"
|
||||||
|
|
||||||
|
private var audioRecorder: AudioRecord? = null
|
||||||
|
private var audioReader: AudioReader? = null
|
||||||
|
private var minBufferSize = 0
|
||||||
|
private var audioRecordStat = false
|
||||||
|
private var audioThread: Thread? = null
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
|
fun createAudioRecorder(inVoiceCall: Boolean, mediaProjection: MediaProjection?): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (ActivityCompat.checkSelfPermission(
|
||||||
|
context,
|
||||||
|
Manifest.permission.RECORD_AUDIO
|
||||||
|
) != PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
|
Log.d(logTag, "createAudioRecorder failed, no RECORD_AUDIO permission")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = AudioRecord.Builder()
|
||||||
|
.setAudioFormat(
|
||||||
|
AudioFormat.Builder()
|
||||||
|
.setEncoding(AUDIO_ENCODING)
|
||||||
|
.setSampleRate(AUDIO_SAMPLE_RATE)
|
||||||
|
.setChannelMask(AUDIO_CHANNEL_MASK).build()
|
||||||
|
);
|
||||||
|
if (inVoiceCall) {
|
||||||
|
builder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
|
||||||
|
} else {
|
||||||
|
mediaProjection?.let {
|
||||||
|
var apcc = AudioPlaybackCaptureConfiguration.Builder(it)
|
||||||
|
.addMatchingUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
|
.addMatchingUsage(AudioAttributes.USAGE_ALARM)
|
||||||
|
.addMatchingUsage(AudioAttributes.USAGE_GAME)
|
||||||
|
.addMatchingUsage(AudioAttributes.USAGE_UNKNOWN).build();
|
||||||
|
builder.setAudioPlaybackCaptureConfig(apcc);
|
||||||
|
} ?: let {
|
||||||
|
Log.d(logTag, "createAudioRecorder failed, mediaProjection null")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audioRecorder = builder.build()
|
||||||
|
Log.d(logTag, "createAudioRecorder done,minBufferSize:$minBufferSize")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
|
private fun checkAudioReader() {
|
||||||
|
if (audioReader != null && minBufferSize != 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// read f32 to byte , length * 4
|
||||||
|
minBufferSize = 2 * 4 * AudioRecord.getMinBufferSize(
|
||||||
|
AUDIO_SAMPLE_RATE,
|
||||||
|
AUDIO_CHANNEL_MASK,
|
||||||
|
AUDIO_ENCODING
|
||||||
|
)
|
||||||
|
if (minBufferSize == 0) {
|
||||||
|
Log.d(logTag, "get min buffer size fail!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
audioReader = AudioReader(minBufferSize, 4)
|
||||||
|
Log.d(logTag, "init audioData len:$minBufferSize")
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
|
fun startAudioRecorder() {
|
||||||
|
checkAudioReader()
|
||||||
|
if (audioReader != null && audioRecorder != null && minBufferSize != 0) {
|
||||||
|
try {
|
||||||
|
FFI.setFrameRawEnable("audio", true)
|
||||||
|
audioRecorder!!.startRecording()
|
||||||
|
audioRecordStat = true
|
||||||
|
audioThread = thread {
|
||||||
|
while (audioRecordStat) {
|
||||||
|
audioReader!!.readSync(audioRecorder!!)?.let {
|
||||||
|
FFI.onAudioFrameUpdate(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// let's release here rather than onDestroy to avoid threading issue
|
||||||
|
audioRecorder?.release()
|
||||||
|
audioRecorder = null
|
||||||
|
minBufferSize = 0
|
||||||
|
FFI.setFrameRawEnable("audio", false)
|
||||||
|
Log.d(logTag, "Exit audio thread")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.d(logTag, "startAudioRecorder fail:$e")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(logTag, "startAudioRecorder fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onVoiceCallStarted(mediaProjection: MediaProjection?): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (isVideoStart() || isAudioStart()) {
|
||||||
|
if (!switchToVoiceCall(mediaProjection)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!switchToVoiceCall(mediaProjection)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onVoiceCallClosed(mediaProjection: MediaProjection?): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (isVideoStart()) {
|
||||||
|
switchOutVoiceCall(mediaProjection)
|
||||||
|
}
|
||||||
|
tryReleaseAudio()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
|
fun switchToVoiceCall(mediaProjection: MediaProjection?): Boolean {
|
||||||
|
audioRecorder?.let {
|
||||||
|
if (it.getAudioSource() == MediaRecorder.AudioSource.VOICE_COMMUNICATION) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audioRecordStat = false
|
||||||
|
audioThread?.join()
|
||||||
|
audioThread = null
|
||||||
|
|
||||||
|
if (!createAudioRecorder(true, mediaProjection)) {
|
||||||
|
Log.e(logTag, "createAudioRecorder fail")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
startAudioRecorder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
|
fun switchOutVoiceCall(mediaProjection: MediaProjection?): Boolean {
|
||||||
|
audioRecorder?.let {
|
||||||
|
if (it.getAudioSource() != MediaRecorder.AudioSource.VOICE_COMMUNICATION) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audioRecordStat = false
|
||||||
|
audioThread?.join()
|
||||||
|
|
||||||
|
if (!createAudioRecorder(false, mediaProjection)) {
|
||||||
|
Log.e(logTag, "createAudioRecorder fail")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
startAudioRecorder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tryReleaseAudio() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isAudioStart() || isVideoStart()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
audioRecordStat = false
|
||||||
|
audioThread?.join()
|
||||||
|
audioThread = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun destroy() {
|
||||||
|
Log.d(logTag, "destroy audio record handle")
|
||||||
|
|
||||||
|
audioRecordStat = false
|
||||||
|
audioThread?.join()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,12 +10,27 @@ import android.accessibilityservice.AccessibilityService
|
|||||||
import android.accessibilityservice.GestureDescription
|
import android.accessibilityservice.GestureDescription
|
||||||
import android.graphics.Path
|
import android.graphics.Path
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.widget.EditText
|
||||||
import android.view.accessibility.AccessibilityEvent
|
import android.view.accessibility.AccessibilityEvent
|
||||||
|
import android.view.ViewGroup.LayoutParams
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.accessibilityservice.AccessibilityServiceInfo
|
||||||
|
import android.accessibilityservice.AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR
|
||||||
|
import android.accessibilityservice.AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.lang.Character
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import hbb.MessageOuterClass.KeyEvent
|
||||||
|
import hbb.MessageOuterClass.KeyboardMode
|
||||||
|
import hbb.KeyEventConverter
|
||||||
|
|
||||||
const val LIFT_DOWN = 9
|
const val LIFT_DOWN = 9
|
||||||
const val LIFT_MOVE = 8
|
const val LIFT_MOVE = 8
|
||||||
@@ -26,6 +41,13 @@ const val WHEEL_BUTTON_UP = 34
|
|||||||
const val WHEEL_DOWN = 523331
|
const val WHEEL_DOWN = 523331
|
||||||
const val WHEEL_UP = 963
|
const val WHEEL_UP = 963
|
||||||
|
|
||||||
|
const val TOUCH_SCALE_START = 1
|
||||||
|
const val TOUCH_SCALE = 2
|
||||||
|
const val TOUCH_SCALE_END = 3
|
||||||
|
const val TOUCH_PAN_START = 4
|
||||||
|
const val TOUCH_PAN_UPDATE = 5
|
||||||
|
const val TOUCH_PAN_END = 6
|
||||||
|
|
||||||
const val WHEEL_STEP = 120
|
const val WHEEL_STEP = 120
|
||||||
const val WHEEL_DURATION = 50L
|
const val WHEEL_DURATION = 50L
|
||||||
const val LONG_TAP_DELAY = 200L
|
const val LONG_TAP_DELAY = 200L
|
||||||
@@ -51,6 +73,8 @@ class InputService : AccessibilityService() {
|
|||||||
private var isWheelActionsPolling = false
|
private var isWheelActionsPolling = false
|
||||||
private var isWaitingLongPress = false
|
private var isWaitingLongPress = false
|
||||||
|
|
||||||
|
private var fakeEditTextForTextStateCalculation: EditText? = null
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
fun onMouseInput(mask: Int, _x: Int, _y: Int) {
|
fun onMouseInput(mask: Int, _x: Int, _y: Int) {
|
||||||
val x = max(0, _x)
|
val x = max(0, _x)
|
||||||
@@ -167,6 +191,30 @@ class InputService : AccessibilityService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
fun onTouchInput(mask: Int, _x: Int, _y: Int) {
|
||||||
|
when (mask) {
|
||||||
|
TOUCH_PAN_UPDATE -> {
|
||||||
|
mouseX -= _x * SCREEN_INFO.scale
|
||||||
|
mouseY -= _y * SCREEN_INFO.scale
|
||||||
|
mouseX = max(0, mouseX);
|
||||||
|
mouseY = max(0, mouseY);
|
||||||
|
continueGesture(mouseX, mouseY)
|
||||||
|
}
|
||||||
|
TOUCH_PAN_START -> {
|
||||||
|
mouseX = max(0, _x) * SCREEN_INFO.scale
|
||||||
|
mouseY = max(0, _y) * SCREEN_INFO.scale
|
||||||
|
startGesture(mouseX, mouseY)
|
||||||
|
}
|
||||||
|
TOUCH_PAN_END -> {
|
||||||
|
endGesture(mouseX, mouseY)
|
||||||
|
mouseX = max(0, _x) * SCREEN_INFO.scale
|
||||||
|
mouseY = max(0, _y) * SCREEN_INFO.scale
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
private fun consumeWheelActions() {
|
private fun consumeWheelActions() {
|
||||||
if (isWheelActionsPolling) {
|
if (isWheelActionsPolling) {
|
||||||
@@ -221,9 +269,296 @@ class InputService : AccessibilityService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
fun onKeyEvent(data: ByteArray) {
|
||||||
|
val keyEvent = KeyEvent.parseFrom(data)
|
||||||
|
val keyboardMode = keyEvent.getMode()
|
||||||
|
|
||||||
|
var textToCommit: String? = null
|
||||||
|
|
||||||
|
if (keyboardMode == KeyboardMode.Legacy) {
|
||||||
|
if (keyEvent.hasChr() && keyEvent.getDown()) {
|
||||||
|
val chr = keyEvent.getChr()
|
||||||
|
if (chr != null) {
|
||||||
|
textToCommit = String(Character.toChars(chr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (keyboardMode == KeyboardMode.Translate) {
|
||||||
|
if (keyEvent.hasSeq() && keyEvent.getDown()) {
|
||||||
|
val seq = keyEvent.getSeq()
|
||||||
|
if (seq != null) {
|
||||||
|
textToCommit = seq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(logTag, "onKeyEvent $keyEvent textToCommit:$textToCommit")
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 33) {
|
||||||
|
getInputMethod()?.let { inputMethod ->
|
||||||
|
inputMethod.getCurrentInputConnection()?.let { inputConnection ->
|
||||||
|
if (textToCommit != null) {
|
||||||
|
textToCommit?.let { text ->
|
||||||
|
inputConnection.commitText(text, 1, null)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
KeyEventConverter.toAndroidKeyEvent(keyEvent).let { event ->
|
||||||
|
inputConnection.sendKeyEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
handler.post {
|
||||||
|
KeyEventConverter.toAndroidKeyEvent(keyEvent)?.let { event ->
|
||||||
|
val possibleNodes = possibleAccessibiltyNodes()
|
||||||
|
Log.d(logTag, "possibleNodes:$possibleNodes")
|
||||||
|
for (item in possibleNodes) {
|
||||||
|
val success = trySendKeyEvent(event, item, textToCommit)
|
||||||
|
if (success) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun insertAccessibilityNode(list: LinkedList<AccessibilityNodeInfo>, node: AccessibilityNodeInfo) {
|
||||||
|
if (node == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (list.contains(node)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list.add(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findChildNode(node: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
|
||||||
|
if (node == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (node.isEditable() && node.isFocusable()) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
val childCount = node.getChildCount()
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
val child = node.getChild(i)
|
||||||
|
if (child != null) {
|
||||||
|
if (child.isEditable() && child.isFocusable()) {
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT < 33) {
|
||||||
|
child.recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
val child = node.getChild(i)
|
||||||
|
if (child != null) {
|
||||||
|
val result = findChildNode(child)
|
||||||
|
if (Build.VERSION.SDK_INT < 33) {
|
||||||
|
if (child != result) {
|
||||||
|
child.recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result != null) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun possibleAccessibiltyNodes(): LinkedList<AccessibilityNodeInfo> {
|
||||||
|
val linkedList = LinkedList<AccessibilityNodeInfo>()
|
||||||
|
val latestList = LinkedList<AccessibilityNodeInfo>()
|
||||||
|
|
||||||
|
val focusInput = findFocus(AccessibilityNodeInfo.FOCUS_INPUT)
|
||||||
|
var focusAccessibilityInput = findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)
|
||||||
|
|
||||||
|
val rootInActiveWindow = getRootInActiveWindow()
|
||||||
|
|
||||||
|
Log.d(logTag, "focusInput:$focusInput focusAccessibilityInput:$focusAccessibilityInput rootInActiveWindow:$rootInActiveWindow")
|
||||||
|
|
||||||
|
if (focusInput != null) {
|
||||||
|
if (focusInput.isFocusable() && focusInput.isEditable()) {
|
||||||
|
insertAccessibilityNode(linkedList, focusInput)
|
||||||
|
} else {
|
||||||
|
insertAccessibilityNode(latestList, focusInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (focusAccessibilityInput != null) {
|
||||||
|
if (focusAccessibilityInput.isFocusable() && focusAccessibilityInput.isEditable()) {
|
||||||
|
insertAccessibilityNode(linkedList, focusAccessibilityInput)
|
||||||
|
} else {
|
||||||
|
insertAccessibilityNode(latestList, focusAccessibilityInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val childFromFocusInput = findChildNode(focusInput)
|
||||||
|
Log.d(logTag, "childFromFocusInput:$childFromFocusInput")
|
||||||
|
|
||||||
|
if (childFromFocusInput != null) {
|
||||||
|
insertAccessibilityNode(linkedList, childFromFocusInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
val childFromFocusAccessibilityInput = findChildNode(focusAccessibilityInput)
|
||||||
|
if (childFromFocusAccessibilityInput != null) {
|
||||||
|
insertAccessibilityNode(linkedList, childFromFocusAccessibilityInput)
|
||||||
|
}
|
||||||
|
Log.d(logTag, "childFromFocusAccessibilityInput:$childFromFocusAccessibilityInput")
|
||||||
|
|
||||||
|
if (rootInActiveWindow != null) {
|
||||||
|
insertAccessibilityNode(linkedList, rootInActiveWindow)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (item in latestList) {
|
||||||
|
insertAccessibilityNode(linkedList, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkedList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun trySendKeyEvent(event: android.view.KeyEvent, node: AccessibilityNodeInfo, textToCommit: String?): Boolean {
|
||||||
|
node.refresh()
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setSelection(0,0)
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setText(null)
|
||||||
|
|
||||||
|
val text = node.getText()
|
||||||
|
var isShowingHint = false
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
isShowingHint = node.isShowingHintText()
|
||||||
|
}
|
||||||
|
|
||||||
|
var textSelectionStart = node.textSelectionStart
|
||||||
|
var textSelectionEnd = node.textSelectionEnd
|
||||||
|
|
||||||
|
if (text != null) {
|
||||||
|
if (textSelectionStart > text.length) {
|
||||||
|
textSelectionStart = text.length
|
||||||
|
}
|
||||||
|
if (textSelectionEnd > text.length) {
|
||||||
|
textSelectionEnd = text.length
|
||||||
|
}
|
||||||
|
if (textSelectionStart > textSelectionEnd) {
|
||||||
|
textSelectionStart = textSelectionEnd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var success = false
|
||||||
|
|
||||||
|
Log.d(logTag, "existing text:$text textToCommit:$textToCommit textSelectionStart:$textSelectionStart textSelectionEnd:$textSelectionEnd")
|
||||||
|
|
||||||
|
if (textToCommit != null) {
|
||||||
|
if ((textSelectionStart == -1) || (textSelectionEnd == -1)) {
|
||||||
|
val newText = textToCommit
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setText(newText)
|
||||||
|
success = updateTextForAccessibilityNode(node)
|
||||||
|
} else if (text != null) {
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setText(text)
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setSelection(
|
||||||
|
textSelectionStart,
|
||||||
|
textSelectionEnd
|
||||||
|
)
|
||||||
|
this.fakeEditTextForTextStateCalculation?.text?.insert(textSelectionStart, textToCommit)
|
||||||
|
success = updateTextAndSelectionForAccessibiltyNode(node)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isShowingHint) {
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setText(null)
|
||||||
|
} else {
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setText(text)
|
||||||
|
}
|
||||||
|
if (textSelectionStart != -1 && textSelectionEnd != -1) {
|
||||||
|
Log.d(logTag, "setting selection $textSelectionStart $textSelectionEnd")
|
||||||
|
this.fakeEditTextForTextStateCalculation?.setSelection(
|
||||||
|
textSelectionStart,
|
||||||
|
textSelectionEnd
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fakeEditTextForTextStateCalculation?.let {
|
||||||
|
// This is essiential to make sure layout object is created. OnKeyDown may not work if layout is not created.
|
||||||
|
val rect = Rect()
|
||||||
|
node.getBoundsInScreen(rect)
|
||||||
|
|
||||||
|
it.layout(rect.left, rect.top, rect.right, rect.bottom)
|
||||||
|
it.onPreDraw()
|
||||||
|
if (event.action == android.view.KeyEvent.ACTION_DOWN) {
|
||||||
|
val succ = it.onKeyDown(event.getKeyCode(), event)
|
||||||
|
Log.d(logTag, "onKeyDown $succ")
|
||||||
|
} else if (event.action == android.view.KeyEvent.ACTION_UP) {
|
||||||
|
val success = it.onKeyUp(event.getKeyCode(), event)
|
||||||
|
Log.d(logTag, "keyup $success")
|
||||||
|
} else {}
|
||||||
|
}
|
||||||
|
|
||||||
|
success = updateTextAndSelectionForAccessibiltyNode(node)
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateTextForAccessibilityNode(node: AccessibilityNodeInfo): Boolean {
|
||||||
|
var success = false
|
||||||
|
this.fakeEditTextForTextStateCalculation?.text?.let {
|
||||||
|
val arguments = Bundle()
|
||||||
|
arguments.putCharSequence(
|
||||||
|
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
|
||||||
|
it.toString()
|
||||||
|
)
|
||||||
|
success = node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateTextAndSelectionForAccessibiltyNode(node: AccessibilityNodeInfo): Boolean {
|
||||||
|
var success = updateTextForAccessibilityNode(node)
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
val selectionStart = this.fakeEditTextForTextStateCalculation?.selectionStart
|
||||||
|
val selectionEnd = this.fakeEditTextForTextStateCalculation?.selectionEnd
|
||||||
|
|
||||||
|
if (selectionStart != null && selectionEnd != null) {
|
||||||
|
val arguments = Bundle()
|
||||||
|
arguments.putInt(
|
||||||
|
AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT,
|
||||||
|
selectionStart
|
||||||
|
)
|
||||||
|
arguments.putInt(
|
||||||
|
AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
|
||||||
|
selectionEnd
|
||||||
|
)
|
||||||
|
success = node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments)
|
||||||
|
Log.d(logTag, "Update selection to $selectionStart $selectionEnd success:$success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onAccessibilityEvent(event: AccessibilityEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {
|
override fun onServiceConnected() {
|
||||||
super.onServiceConnected()
|
super.onServiceConnected()
|
||||||
ctx = this
|
ctx = this
|
||||||
|
val info = AccessibilityServiceInfo()
|
||||||
|
if (Build.VERSION.SDK_INT >= 33) {
|
||||||
|
info.flags = FLAG_INPUT_METHOD_EDITOR or FLAG_RETRIEVE_INTERACTIVE_WINDOWS
|
||||||
|
} else {
|
||||||
|
info.flags = FLAG_RETRIEVE_INTERACTIVE_WINDOWS
|
||||||
|
}
|
||||||
|
setServiceInfo(info)
|
||||||
|
fakeEditTextForTextStateCalculation = EditText(this)
|
||||||
|
// Size here doesn't matter, we won't show this view.
|
||||||
|
fakeEditTextForTextStateCalculation?.layoutParams = LayoutParams(100, 100)
|
||||||
|
fakeEditTextForTextStateCalculation?.onPreDraw()
|
||||||
|
val layout = fakeEditTextForTextStateCalculation?.getLayout()
|
||||||
|
Log.d(logTag, "fakeEditTextForTextStateCalculation layout:$layout")
|
||||||
Log.d(logTag, "onServiceConnected!")
|
Log.d(logTag, "onServiceConnected!")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +567,5 @@ class InputService : AccessibilityService() {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAccessibilityEvent(event: AccessibilityEvent?) {}
|
|
||||||
|
|
||||||
override fun onInterrupt() {}
|
override fun onInterrupt() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package hbb;
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.KeyCharacterMap
|
||||||
|
import hbb.MessageOuterClass.KeyboardMode
|
||||||
|
import hbb.MessageOuterClass.ControlKey
|
||||||
|
|
||||||
|
object KeyEventConverter {
|
||||||
|
fun toAndroidKeyEvent(keyEventProto: hbb.MessageOuterClass.KeyEvent): KeyEvent {
|
||||||
|
var chrValue = 0
|
||||||
|
var modifiers = 0
|
||||||
|
|
||||||
|
val keyboardMode = keyEventProto.getMode()
|
||||||
|
|
||||||
|
if (keyEventProto.hasChr()) {
|
||||||
|
if (keyboardMode == KeyboardMode.Map || keyboardMode == KeyboardMode.Translate) {
|
||||||
|
chrValue = keyEventProto.getChr()
|
||||||
|
} else {
|
||||||
|
chrValue = convertUnicodeToKeyCode(keyEventProto.getChr() as Int)
|
||||||
|
}
|
||||||
|
} else if (keyEventProto.hasControlKey()) {
|
||||||
|
chrValue = convertControlKeyToKeyCode(keyEventProto.getControlKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
var modifiersList = keyEventProto.getModifiersList()
|
||||||
|
|
||||||
|
if (modifiersList != null) {
|
||||||
|
for (modifier in keyEventProto.getModifiersList()) {
|
||||||
|
val modifierValue = convertModifier(modifier)
|
||||||
|
modifiers = modifiers or modifierValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var action = 0
|
||||||
|
if (keyEventProto.getDown()) {
|
||||||
|
action = KeyEvent.ACTION_DOWN
|
||||||
|
} else {
|
||||||
|
action = KeyEvent.ACTION_UP
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyEvent(0, 0, action, chrValue, 0, modifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertModifier(controlKey: hbb.MessageOuterClass.ControlKey): Int {
|
||||||
|
// Add logic to map ControlKey values to Android KeyEvent key codes.
|
||||||
|
// You'll need to provide the mapping for each key.
|
||||||
|
return when (controlKey) {
|
||||||
|
ControlKey.Alt -> KeyEvent.META_ALT_ON
|
||||||
|
ControlKey.Control -> KeyEvent.META_CTRL_ON
|
||||||
|
ControlKey.CapsLock -> KeyEvent.META_CAPS_LOCK_ON
|
||||||
|
ControlKey.Meta -> KeyEvent.META_META_ON
|
||||||
|
ControlKey.NumLock -> KeyEvent.META_NUM_LOCK_ON
|
||||||
|
ControlKey.RShift -> KeyEvent.META_SHIFT_RIGHT_ON
|
||||||
|
ControlKey.Shift -> KeyEvent.META_SHIFT_ON
|
||||||
|
ControlKey.RAlt -> KeyEvent.META_ALT_RIGHT_ON
|
||||||
|
ControlKey.RControl -> KeyEvent.META_CTRL_RIGHT_ON
|
||||||
|
else -> 0 // Default to unknown.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val tag = "KeyEventConverter"
|
||||||
|
|
||||||
|
private fun convertUnicodeToKeyCode(unicode: Int): Int {
|
||||||
|
val charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD)
|
||||||
|
android.util.Log.d(tag, "unicode: $unicode")
|
||||||
|
val events = charMap.getEvents(charArrayOf(unicode.toChar()))
|
||||||
|
if (events != null && events.size > 0) {
|
||||||
|
android.util.Log.d(tag, "keycode ${events[0].keyCode}")
|
||||||
|
return events[0].keyCode
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertControlKeyToKeyCode(controlKey: hbb.MessageOuterClass.ControlKey): Int {
|
||||||
|
// Add logic to map ControlKey values to Android KeyEvent key codes.
|
||||||
|
// You'll need to provide the mapping for each key.
|
||||||
|
return when (controlKey) {
|
||||||
|
ControlKey.Alt -> KeyEvent.KEYCODE_ALT_LEFT
|
||||||
|
ControlKey.Backspace -> KeyEvent.KEYCODE_DEL
|
||||||
|
ControlKey.Control -> KeyEvent.KEYCODE_CTRL_LEFT
|
||||||
|
ControlKey.CapsLock -> KeyEvent.KEYCODE_CAPS_LOCK
|
||||||
|
ControlKey.Meta -> KeyEvent.KEYCODE_META_LEFT
|
||||||
|
ControlKey.NumLock -> KeyEvent.KEYCODE_NUM_LOCK
|
||||||
|
ControlKey.RShift -> KeyEvent.KEYCODE_SHIFT_RIGHT
|
||||||
|
ControlKey.Shift -> KeyEvent.KEYCODE_SHIFT_LEFT
|
||||||
|
ControlKey.RAlt -> KeyEvent.KEYCODE_ALT_RIGHT
|
||||||
|
ControlKey.RControl -> KeyEvent.KEYCODE_CTRL_RIGHT
|
||||||
|
ControlKey.DownArrow -> KeyEvent.KEYCODE_DPAD_DOWN
|
||||||
|
ControlKey.LeftArrow -> KeyEvent.KEYCODE_DPAD_LEFT
|
||||||
|
ControlKey.RightArrow -> KeyEvent.KEYCODE_DPAD_RIGHT
|
||||||
|
ControlKey.UpArrow -> KeyEvent.KEYCODE_DPAD_UP
|
||||||
|
ControlKey.End -> KeyEvent.KEYCODE_MOVE_END
|
||||||
|
ControlKey.Home -> KeyEvent.KEYCODE_MOVE_HOME
|
||||||
|
ControlKey.PageUp -> KeyEvent.KEYCODE_PAGE_UP
|
||||||
|
ControlKey.PageDown -> KeyEvent.KEYCODE_PAGE_DOWN
|
||||||
|
ControlKey.Insert -> KeyEvent.KEYCODE_INSERT
|
||||||
|
ControlKey.Escape -> KeyEvent.KEYCODE_ESCAPE
|
||||||
|
ControlKey.F1 -> KeyEvent.KEYCODE_F1
|
||||||
|
ControlKey.F2 -> KeyEvent.KEYCODE_F2
|
||||||
|
ControlKey.F3 -> KeyEvent.KEYCODE_F3
|
||||||
|
ControlKey.F4 -> KeyEvent.KEYCODE_F4
|
||||||
|
ControlKey.F5 -> KeyEvent.KEYCODE_F5
|
||||||
|
ControlKey.F6 -> KeyEvent.KEYCODE_F6
|
||||||
|
ControlKey.F7 -> KeyEvent.KEYCODE_F7
|
||||||
|
ControlKey.F8 -> KeyEvent.KEYCODE_F8
|
||||||
|
ControlKey.F9 -> KeyEvent.KEYCODE_F9
|
||||||
|
ControlKey.F10 -> KeyEvent.KEYCODE_F10
|
||||||
|
ControlKey.F11 -> KeyEvent.KEYCODE_F11
|
||||||
|
ControlKey.F12 -> KeyEvent.KEYCODE_F12
|
||||||
|
ControlKey.Space -> KeyEvent.KEYCODE_SPACE
|
||||||
|
ControlKey.Tab -> KeyEvent.KEYCODE_TAB
|
||||||
|
ControlKey.Return -> KeyEvent.KEYCODE_ENTER
|
||||||
|
ControlKey.Delete -> KeyEvent.KEYCODE_FORWARD_DEL
|
||||||
|
ControlKey.Clear -> KeyEvent.KEYCODE_CLEAR
|
||||||
|
ControlKey.Pause -> KeyEvent.KEYCODE_BREAK
|
||||||
|
else -> 0 // Default to unknown.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ package com.carriez.flutter_hbb
|
|||||||
* Inspired by [droidVNC-NG] https://github.com/bk138/droidVNC-NG
|
* Inspired by [droidVNC-NG] https://github.com/bk138/droidVNC-NG
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ffi.FFI
|
||||||
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -15,10 +17,20 @@ import android.os.Build
|
|||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.media.MediaCodecInfo
|
||||||
|
import android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
|
||||||
|
import android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
|
||||||
|
import android.media.MediaCodecList
|
||||||
|
import android.media.MediaFormat
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
import com.hjq.permissions.XXPermissions
|
import com.hjq.permissions.XXPermissions
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
@@ -30,6 +42,9 @@ class MainActivity : FlutterActivity() {
|
|||||||
private val logTag = "mMainActivity"
|
private val logTag = "mMainActivity"
|
||||||
private var mainService: MainService? = null
|
private var mainService: MainService? = null
|
||||||
|
|
||||||
|
private var isAudioStart = false
|
||||||
|
private val audioRecordHandle = AudioRecordHandle(this, { false }, { isAudioStart })
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
if (MainService.isReady) {
|
if (MainService.isReady) {
|
||||||
@@ -42,6 +57,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
channelTag
|
channelTag
|
||||||
)
|
)
|
||||||
initFlutterChannel(flutterMethodChannel!!)
|
initFlutterChannel(flutterMethodChannel!!)
|
||||||
|
thread { setCodecInfo() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -217,10 +233,145 @@ class MainActivity : FlutterActivity() {
|
|||||||
result.success(false)
|
result.success(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"on_voice_call_started" -> {
|
||||||
|
onVoiceCallStarted()
|
||||||
|
}
|
||||||
|
"on_voice_call_closed" -> {
|
||||||
|
onVoiceCallClosed()
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
result.error("-1", "No such method", null)
|
result.error("-1", "No such method", null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setCodecInfo() {
|
||||||
|
val codecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)
|
||||||
|
val codecs = codecList.codecInfos
|
||||||
|
val codecArray = JSONArray()
|
||||||
|
|
||||||
|
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||||
|
var w = 0
|
||||||
|
var h = 0
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
val m = windowManager.maximumWindowMetrics
|
||||||
|
w = m.bounds.width()
|
||||||
|
h = m.bounds.height()
|
||||||
|
} else {
|
||||||
|
val dm = DisplayMetrics()
|
||||||
|
windowManager.defaultDisplay.getRealMetrics(dm)
|
||||||
|
w = dm.widthPixels
|
||||||
|
h = dm.heightPixels
|
||||||
|
}
|
||||||
|
val align = 64
|
||||||
|
w = (w + align - 1) / align * align
|
||||||
|
h = (h + align - 1) / align * align
|
||||||
|
codecs.forEach { codec ->
|
||||||
|
val codecObject = JSONObject()
|
||||||
|
codecObject.put("name", codec.name)
|
||||||
|
codecObject.put("is_encoder", codec.isEncoder)
|
||||||
|
var hw: Boolean? = null;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
hw = codec.isHardwareAccelerated
|
||||||
|
} else {
|
||||||
|
// https://chromium.googlesource.com/external/webrtc/+/HEAD/sdk/android/src/java/org/webrtc/MediaCodecUtils.java#29
|
||||||
|
// https://chromium.googlesource.com/external/webrtc/+/master/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java#229
|
||||||
|
if (listOf("OMX.google.", "OMX.SEC.", "c2.android").any { codec.name.startsWith(it, true) }) {
|
||||||
|
hw = false
|
||||||
|
} else if (listOf("c2.qti", "OMX.qcom.video", "OMX.Exynos", "OMX.hisi", "OMX.MTK", "OMX.Intel", "OMX.Nvidia").any { codec.name.startsWith(it, true) }) {
|
||||||
|
hw = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hw != true) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
codecObject.put("hw", hw)
|
||||||
|
var mime_type = ""
|
||||||
|
codec.supportedTypes.forEach { type ->
|
||||||
|
if (listOf("video/avc", "video/hevc").contains(type)) { // "video/x-vnd.on2.vp8", "video/x-vnd.on2.vp9", "video/av01"
|
||||||
|
mime_type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mime_type.isNotEmpty()) {
|
||||||
|
codecObject.put("mime_type", mime_type)
|
||||||
|
val caps = codec.getCapabilitiesForType(mime_type)
|
||||||
|
if (codec.isEncoder) {
|
||||||
|
// Encoder‘s max_height and max_width are interchangeable
|
||||||
|
if (!caps.videoCapabilities.isSizeSupported(w,h) && !caps.videoCapabilities.isSizeSupported(h,w)) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
codecObject.put("min_width", caps.videoCapabilities.supportedWidths.lower)
|
||||||
|
codecObject.put("max_width", caps.videoCapabilities.supportedWidths.upper)
|
||||||
|
codecObject.put("min_height", caps.videoCapabilities.supportedHeights.lower)
|
||||||
|
codecObject.put("max_height", caps.videoCapabilities.supportedHeights.upper)
|
||||||
|
val surface = caps.colorFormats.contains(COLOR_FormatSurface);
|
||||||
|
codecObject.put("surface", surface)
|
||||||
|
val nv12 = caps.colorFormats.contains(COLOR_FormatYUV420SemiPlanar)
|
||||||
|
codecObject.put("nv12", nv12)
|
||||||
|
if (!(nv12 || surface)) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
codecObject.put("min_bitrate", caps.videoCapabilities.bitrateRange.lower / 1000)
|
||||||
|
codecObject.put("max_bitrate", caps.videoCapabilities.bitrateRange.upper / 1000)
|
||||||
|
if (!codec.isEncoder) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
codecObject.put("low_latency", caps.isFeatureSupported(MediaCodecInfo.CodecCapabilities.FEATURE_LowLatency))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!codec.isEncoder) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
codecArray.put(codecObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val result = JSONObject()
|
||||||
|
result.put("version", Build.VERSION.SDK_INT)
|
||||||
|
result.put("w", w)
|
||||||
|
result.put("h", h)
|
||||||
|
result.put("codecs", codecArray)
|
||||||
|
FFI.setCodecInfo(result.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onVoiceCallStarted() {
|
||||||
|
var ok = false
|
||||||
|
mainService?.let {
|
||||||
|
ok = it.onVoiceCallStarted()
|
||||||
|
} ?: let {
|
||||||
|
isAudioStart = true
|
||||||
|
ok = audioRecordHandle.onVoiceCallStarted(null)
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
// Rarely happens, So we just add log and msgbox here.
|
||||||
|
Log.e(logTag, "onVoiceCallStarted fail")
|
||||||
|
flutterMethodChannel?.invokeMethod("msgbox", mapOf(
|
||||||
|
"type" to "custom-nook-nocancel-hasclose-error",
|
||||||
|
"title" to "Voice call",
|
||||||
|
"text" to "Failed to start voice call."))
|
||||||
|
} else {
|
||||||
|
Log.d(logTag, "onVoiceCallStarted success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onVoiceCallClosed() {
|
||||||
|
var ok = false
|
||||||
|
mainService?.let {
|
||||||
|
ok = it.onVoiceCallClosed()
|
||||||
|
} ?: let {
|
||||||
|
isAudioStart = false
|
||||||
|
ok = audioRecordHandle.onVoiceCallClosed(null)
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
// Rarely happens, So we just add log and msgbox here.
|
||||||
|
Log.e(logTag, "onVoiceCallClosed fail")
|
||||||
|
flutterMethodChannel?.invokeMethod("msgbox", mapOf(
|
||||||
|
"type" to "custom-nook-nocancel-hasclose-error",
|
||||||
|
"title" to "Voice call",
|
||||||
|
"text" to "Failed to stop voice call."))
|
||||||
|
} else {
|
||||||
|
Log.d(logTag, "onVoiceCallClosed success")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.carriez.flutter_hbb
|
package com.carriez.flutter_hbb
|
||||||
|
|
||||||
|
import ffi.FFI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture screen,get video and audio,send to rust.
|
* Capture screen,get video and audio,send to rust.
|
||||||
* Dispatch notifications
|
* Dispatch notifications
|
||||||
@@ -44,7 +46,6 @@ import java.nio.ByteBuffer
|
|||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
const val DEFAULT_NOTIFY_TITLE = "RustDesk"
|
const val DEFAULT_NOTIFY_TITLE = "RustDesk"
|
||||||
const val DEFAULT_NOTIFY_TEXT = "Service is running"
|
const val DEFAULT_NOTIFY_TEXT = "Service is running"
|
||||||
const val DEFAULT_NOTIFY_ID = 1
|
const val DEFAULT_NOTIFY_ID = 1
|
||||||
@@ -53,38 +54,45 @@ const val NOTIFY_ID_OFFSET = 100
|
|||||||
const val MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_VP9
|
const val MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_VP9
|
||||||
|
|
||||||
// video const
|
// video const
|
||||||
|
|
||||||
const val MAX_SCREEN_SIZE = 1200
|
const val MAX_SCREEN_SIZE = 1200
|
||||||
|
|
||||||
const val VIDEO_KEY_BIT_RATE = 1024_000
|
const val VIDEO_KEY_BIT_RATE = 1024_000
|
||||||
const val VIDEO_KEY_FRAME_RATE = 30
|
const val VIDEO_KEY_FRAME_RATE = 30
|
||||||
|
|
||||||
// audio const
|
|
||||||
const val AUDIO_ENCODING = AudioFormat.ENCODING_PCM_FLOAT // ENCODING_OPUS need API 30
|
|
||||||
const val AUDIO_SAMPLE_RATE = 48000
|
|
||||||
const val AUDIO_CHANNEL_MASK = AudioFormat.CHANNEL_IN_STEREO
|
|
||||||
|
|
||||||
class MainService : Service() {
|
class MainService : Service() {
|
||||||
|
|
||||||
init {
|
|
||||||
System.loadLibrary("rustdesk")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
fun rustMouseInput(mask: Int, x: Int, y: Int) {
|
fun rustPointerInput(kind: String, mask: Int, x: Int, y: Int) {
|
||||||
// turn on screen with LIFT_DOWN when screen off
|
// turn on screen with LIFT_DOWN when screen off
|
||||||
if (!powerManager.isInteractive && mask == LIFT_DOWN) {
|
if (!powerManager.isInteractive && (kind == "touch" || mask == LIFT_DOWN)) {
|
||||||
if (wakeLock.isHeld) {
|
if (wakeLock.isHeld) {
|
||||||
Log.d(logTag,"Turn on Screen, WakeLock release")
|
Log.d(logTag, "Turn on Screen, WakeLock release")
|
||||||
wakeLock.release()
|
wakeLock.release()
|
||||||
}
|
}
|
||||||
Log.d(logTag,"Turn on Screen")
|
Log.d(logTag,"Turn on Screen")
|
||||||
wakeLock.acquire(5000)
|
wakeLock.acquire(5000)
|
||||||
} else {
|
} else {
|
||||||
InputService.ctx?.onMouseInput(mask,x,y)
|
when (kind) {
|
||||||
|
"touch" -> {
|
||||||
|
InputService.ctx?.onTouchInput(mask, x, y)
|
||||||
|
}
|
||||||
|
"mouse" -> {
|
||||||
|
InputService.ctx?.onMouseInput(mask, x, y)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
fun rustKeyEventInput(input: ByteArray) {
|
||||||
|
InputService.ctx?.onKeyEvent(input)
|
||||||
|
}
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
fun rustGetByName(name: String): String {
|
fun rustGetByName(name: String): String {
|
||||||
return when (name) {
|
return when (name) {
|
||||||
@@ -127,10 +135,51 @@ class MainService : Service() {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"update_voice_call_state" -> {
|
||||||
|
try {
|
||||||
|
val jsonObject = JSONObject(arg1)
|
||||||
|
val id = jsonObject["id"] as Int
|
||||||
|
val username = jsonObject["name"] as String
|
||||||
|
val peerId = jsonObject["peer_id"] as String
|
||||||
|
val inVoiceCall = jsonObject["in_voice_call"] as Boolean
|
||||||
|
val incomingVoiceCall = jsonObject["incoming_voice_call"] as Boolean
|
||||||
|
if (!inVoiceCall) {
|
||||||
|
if (incomingVoiceCall) {
|
||||||
|
voiceCallRequestNotification(id, "Voice Call Request", username, peerId)
|
||||||
|
} else {
|
||||||
|
if (!audioRecordHandle.switchOutVoiceCall(mediaProjection)) {
|
||||||
|
Log.e(logTag, "switchOutVoiceCall fail")
|
||||||
|
MainActivity.flutterMethodChannel?.invokeMethod("msgbox", mapOf(
|
||||||
|
"type" to "custom-nook-nocancel-hasclose-error",
|
||||||
|
"title" to "Voice call",
|
||||||
|
"text" to "Failed to switch out voice call."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!audioRecordHandle.switchToVoiceCall(mediaProjection)) {
|
||||||
|
Log.e(logTag, "switchToVoiceCall fail")
|
||||||
|
MainActivity.flutterMethodChannel?.invokeMethod("msgbox", mapOf(
|
||||||
|
"type" to "custom-nook-nocancel-hasclose-error",
|
||||||
|
"title" to "Voice call",
|
||||||
|
"text" to "Failed to switch to voice call."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
"stop_capture" -> {
|
"stop_capture" -> {
|
||||||
Log.d(logTag, "from rust:stop_capture")
|
Log.d(logTag, "from rust:stop_capture")
|
||||||
stopCapture()
|
stopCapture()
|
||||||
}
|
}
|
||||||
|
"is_hardware_codec" -> {
|
||||||
|
val isHwCodec = arg1.toBoolean()
|
||||||
|
if (isHardwareCodec != isHwCodec) {
|
||||||
|
isHardwareCodec = isHwCodec
|
||||||
|
updateScreenInfo(resources.configuration.orientation)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,38 +191,28 @@ class MainService : Service() {
|
|||||||
private val powerManager: PowerManager by lazy { applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager }
|
private val powerManager: PowerManager by lazy { applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager }
|
||||||
private val wakeLock: PowerManager.WakeLock by lazy { powerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "rustdesk:wakelock")}
|
private val wakeLock: PowerManager.WakeLock by lazy { powerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "rustdesk:wakelock")}
|
||||||
|
|
||||||
// jvm call rust
|
|
||||||
private external fun init(ctx: Context)
|
|
||||||
|
|
||||||
/// When app start on boot, app_dir will not be passed from flutter
|
|
||||||
/// so pass a app_dir here to rust server
|
|
||||||
private external fun startServer(app_dir: String)
|
|
||||||
private external fun startService()
|
|
||||||
private external fun onVideoFrameUpdate(buf: ByteBuffer)
|
|
||||||
private external fun onAudioFrameUpdate(buf: ByteBuffer)
|
|
||||||
private external fun translateLocale(localeName: String, input: String): String
|
|
||||||
private external fun refreshScreen()
|
|
||||||
private external fun setFrameRawEnable(name: String, value: Boolean)
|
|
||||||
// private external fun sendVp9(data: ByteArray)
|
|
||||||
|
|
||||||
private fun translate(input: String): String {
|
private fun translate(input: String): String {
|
||||||
Log.d(logTag, "translate:$LOCAL_NAME")
|
Log.d(logTag, "translate:$LOCAL_NAME")
|
||||||
return translateLocale(LOCAL_NAME, input)
|
return FFI.translateLocale(LOCAL_NAME, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var _isReady = false // media permission ready status
|
private var _isReady = false // media permission ready status
|
||||||
private var _isStart = false // screen capture start status
|
private var _isStart = false // screen capture start status
|
||||||
|
private var _isAudioStart = false // audio capture start status
|
||||||
val isReady: Boolean
|
val isReady: Boolean
|
||||||
get() = _isReady
|
get() = _isReady
|
||||||
val isStart: Boolean
|
val isStart: Boolean
|
||||||
get() = _isStart
|
get() = _isStart
|
||||||
|
val isAudioStart: Boolean
|
||||||
|
get() = _isAudioStart
|
||||||
}
|
}
|
||||||
|
|
||||||
private val logTag = "LOG_SERVICE"
|
private val logTag = "LOG_SERVICE"
|
||||||
private val useVP9 = false
|
private val useVP9 = false
|
||||||
private val binder = LocalBinder()
|
private val binder = LocalBinder()
|
||||||
|
|
||||||
|
private var reuseVirtualDisplay = Build.VERSION.SDK_INT > 33
|
||||||
|
|
||||||
// video
|
// video
|
||||||
private var mediaProjection: MediaProjection? = null
|
private var mediaProjection: MediaProjection? = null
|
||||||
@@ -184,10 +223,7 @@ class MainService : Service() {
|
|||||||
private var virtualDisplay: VirtualDisplay? = null
|
private var virtualDisplay: VirtualDisplay? = null
|
||||||
|
|
||||||
// audio
|
// audio
|
||||||
private var audioRecorder: AudioRecord? = null
|
private val audioRecordHandle = AudioRecordHandle(this, { isStart }, { isAudioStart })
|
||||||
private var audioReader: AudioReader? = null
|
|
||||||
private var minBufferSize = 0
|
|
||||||
private var audioRecordStat = false
|
|
||||||
|
|
||||||
// notification
|
// notification
|
||||||
private lateinit var notificationManager: NotificationManager
|
private lateinit var notificationManager: NotificationManager
|
||||||
@@ -196,7 +232,8 @@ class MainService : Service() {
|
|||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
Log.d(logTag,"MainService onCreate")
|
Log.d(logTag,"MainService onCreate, sdk int:${Build.VERSION.SDK_INT} reuseVirtualDisplay:$reuseVirtualDisplay")
|
||||||
|
FFI.init(this)
|
||||||
HandlerThread("Service", Process.THREAD_PRIORITY_BACKGROUND).apply {
|
HandlerThread("Service", Process.THREAD_PRIORITY_BACKGROUND).apply {
|
||||||
start()
|
start()
|
||||||
serviceLooper = looper
|
serviceLooper = looper
|
||||||
@@ -208,7 +245,7 @@ class MainService : Service() {
|
|||||||
// keep the config dir same with flutter
|
// keep the config dir same with flutter
|
||||||
val prefs = applicationContext.getSharedPreferences(KEY_SHARED_PREFERENCES, FlutterActivity.MODE_PRIVATE)
|
val prefs = applicationContext.getSharedPreferences(KEY_SHARED_PREFERENCES, FlutterActivity.MODE_PRIVATE)
|
||||||
val configPath = prefs.getString(KEY_APP_DIR_CONFIG_PATH, "") ?: ""
|
val configPath = prefs.getString(KEY_APP_DIR_CONFIG_PATH, "") ?: ""
|
||||||
startServer(configPath)
|
FFI.startServer(configPath, "")
|
||||||
|
|
||||||
createForegroundNotification()
|
createForegroundNotification()
|
||||||
}
|
}
|
||||||
@@ -218,6 +255,7 @@ class MainService : Service() {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var isHardwareCodec: Boolean? = null;
|
||||||
private fun updateScreenInfo(orientation: Int) {
|
private fun updateScreenInfo(orientation: Int) {
|
||||||
var w: Int
|
var w: Int
|
||||||
var h: Int
|
var h: Int
|
||||||
@@ -250,7 +288,7 @@ class MainService : Service() {
|
|||||||
Log.d(logTag,"updateScreenInfo:w:$w,h:$h")
|
Log.d(logTag,"updateScreenInfo:w:$w,h:$h")
|
||||||
var scale = 1
|
var scale = 1
|
||||||
if (w != 0 && h != 0) {
|
if (w != 0 && h != 0) {
|
||||||
if (w > MAX_SCREEN_SIZE || h > MAX_SCREEN_SIZE) {
|
if (isHardwareCodec == false && (w > MAX_SCREEN_SIZE || h > MAX_SCREEN_SIZE)) {
|
||||||
scale = 2
|
scale = 2
|
||||||
w /= scale
|
w /= scale
|
||||||
h /= scale
|
h /= scale
|
||||||
@@ -263,7 +301,7 @@ class MainService : Service() {
|
|||||||
SCREEN_INFO.dpi = dpi
|
SCREEN_INFO.dpi = dpi
|
||||||
if (isStart) {
|
if (isStart) {
|
||||||
stopCapture()
|
stopCapture()
|
||||||
refreshScreen()
|
FFI.refreshScreen()
|
||||||
startCapture()
|
startCapture()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,7 +329,7 @@ class MainService : Service() {
|
|||||||
createForegroundNotification()
|
createForegroundNotification()
|
||||||
|
|
||||||
if (intent.getBooleanExtra(EXT_INIT_FROM_BOOT, false)) {
|
if (intent.getBooleanExtra(EXT_INIT_FROM_BOOT, false)) {
|
||||||
startService()
|
FFI.startService()
|
||||||
}
|
}
|
||||||
Log.d(logTag, "service starting: ${startId}:${Thread.currentThread()}")
|
Log.d(logTag, "service starting: ${startId}:${Thread.currentThread()}")
|
||||||
val mediaProjectionManager =
|
val mediaProjectionManager =
|
||||||
@@ -301,7 +339,6 @@ class MainService : Service() {
|
|||||||
mediaProjection =
|
mediaProjection =
|
||||||
mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, it)
|
mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, it)
|
||||||
checkMediaPermission()
|
checkMediaPermission()
|
||||||
init(this)
|
|
||||||
_isReady = true
|
_isReady = true
|
||||||
} ?: let {
|
} ?: let {
|
||||||
Log.d(logTag, "getParcelableExtra intent null, invoke requestMediaProjection")
|
Log.d(logTag, "getParcelableExtra intent null, invoke requestMediaProjection")
|
||||||
@@ -340,12 +377,13 @@ class MainService : Service() {
|
|||||||
).apply {
|
).apply {
|
||||||
setOnImageAvailableListener({ imageReader: ImageReader ->
|
setOnImageAvailableListener({ imageReader: ImageReader ->
|
||||||
try {
|
try {
|
||||||
|
// If not call acquireLatestImage, listener will not be called again
|
||||||
imageReader.acquireLatestImage().use { image ->
|
imageReader.acquireLatestImage().use { image ->
|
||||||
if (image == null) return@setOnImageAvailableListener
|
if (image == null || !isStart) return@setOnImageAvailableListener
|
||||||
val planes = image.planes
|
val planes = image.planes
|
||||||
val buffer = planes[0].buffer
|
val buffer = planes[0].buffer
|
||||||
buffer.rewind()
|
buffer.rewind()
|
||||||
onVideoFrameUpdate(buffer)
|
FFI.onVideoFrameUpdate(buffer)
|
||||||
}
|
}
|
||||||
} catch (ignored: java.lang.Exception) {
|
} catch (ignored: java.lang.Exception) {
|
||||||
}
|
}
|
||||||
@@ -356,6 +394,14 @@ class MainService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onVoiceCallStarted(): Boolean {
|
||||||
|
return audioRecordHandle.onVoiceCallStarted(mediaProjection)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onVoiceCallClosed(): Boolean {
|
||||||
|
return audioRecordHandle.onVoiceCallClosed(mediaProjection)
|
||||||
|
}
|
||||||
|
|
||||||
fun startCapture(): Boolean {
|
fun startCapture(): Boolean {
|
||||||
if (isStart) {
|
if (isStart) {
|
||||||
return true
|
return true
|
||||||
@@ -364,6 +410,7 @@ class MainService : Service() {
|
|||||||
Log.w(logTag, "startCapture fail,mediaProjection is null")
|
Log.w(logTag, "startCapture fail,mediaProjection is null")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScreenInfo(resources.configuration.orientation)
|
updateScreenInfo(resources.configuration.orientation)
|
||||||
Log.d(logTag, "Start Capture")
|
Log.d(logTag, "Start Capture")
|
||||||
surface = createSurface()
|
surface = createSurface()
|
||||||
@@ -375,47 +422,66 @@ class MainService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
startAudioRecorder()
|
if (!audioRecordHandle.createAudioRecorder(false, mediaProjection)) {
|
||||||
|
Log.d(logTag, "createAudioRecorder fail")
|
||||||
|
} else {
|
||||||
|
Log.d(logTag, "audio recorder start")
|
||||||
|
audioRecordHandle.startAudioRecorder()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
checkMediaPermission()
|
checkMediaPermission()
|
||||||
_isStart = true
|
_isStart = true
|
||||||
setFrameRawEnable("video",true)
|
FFI.setFrameRawEnable("video",true)
|
||||||
setFrameRawEnable("audio",true)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun stopCapture() {
|
fun stopCapture() {
|
||||||
Log.d(logTag, "Stop Capture")
|
Log.d(logTag, "Stop Capture")
|
||||||
setFrameRawEnable("video",false)
|
FFI.setFrameRawEnable("video",false)
|
||||||
setFrameRawEnable("audio",false)
|
|
||||||
_isStart = false
|
_isStart = false
|
||||||
// release video
|
// release video
|
||||||
virtualDisplay?.release()
|
if (reuseVirtualDisplay) {
|
||||||
surface?.release()
|
// The virtual display video projection can be paused by calling `setSurface(null)`.
|
||||||
|
// https://developer.android.com/reference/android/hardware/display/VirtualDisplay.Callback
|
||||||
|
// https://learn.microsoft.com/en-us/dotnet/api/android.hardware.display.virtualdisplay.callback.onpaused?view=net-android-34.0
|
||||||
|
virtualDisplay?.setSurface(null)
|
||||||
|
} else {
|
||||||
|
virtualDisplay?.release()
|
||||||
|
}
|
||||||
|
// suface needs to be release after `imageReader.close()` to imageReader access released surface
|
||||||
|
// https://github.com/rustdesk/rustdesk/issues/4118#issuecomment-1515666629
|
||||||
imageReader?.close()
|
imageReader?.close()
|
||||||
|
imageReader = null
|
||||||
videoEncoder?.let {
|
videoEncoder?.let {
|
||||||
it.signalEndOfInputStream()
|
it.signalEndOfInputStream()
|
||||||
it.stop()
|
it.stop()
|
||||||
it.release()
|
it.release()
|
||||||
}
|
}
|
||||||
virtualDisplay = null
|
if (!reuseVirtualDisplay) {
|
||||||
|
virtualDisplay = null
|
||||||
|
}
|
||||||
videoEncoder = null
|
videoEncoder = null
|
||||||
|
// suface needs to be release after `imageReader.close()` to imageReader access released surface
|
||||||
|
// https://github.com/rustdesk/rustdesk/issues/4118#issuecomment-1515666629
|
||||||
|
surface?.release()
|
||||||
|
|
||||||
// release audio
|
// release audio
|
||||||
audioRecordStat = false
|
_isAudioStart = false
|
||||||
audioRecorder?.release()
|
audioRecordHandle.tryReleaseAudio()
|
||||||
audioRecorder = null
|
|
||||||
minBufferSize = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun destroy() {
|
fun destroy() {
|
||||||
Log.d(logTag, "destroy service")
|
Log.d(logTag, "destroy service")
|
||||||
_isReady = false
|
_isReady = false
|
||||||
|
_isAudioStart = false
|
||||||
|
|
||||||
stopCapture()
|
stopCapture()
|
||||||
imageReader?.close()
|
|
||||||
imageReader = null
|
if (reuseVirtualDisplay) {
|
||||||
|
virtualDisplay?.release()
|
||||||
|
virtualDisplay = null
|
||||||
|
}
|
||||||
|
|
||||||
mediaProjection = null
|
mediaProjection = null
|
||||||
checkMediaPermission()
|
checkMediaPermission()
|
||||||
@@ -445,11 +511,7 @@ class MainService : Service() {
|
|||||||
Log.d(logTag, "startRawVideoRecorder failed,surface is null")
|
Log.d(logTag, "startRawVideoRecorder failed,surface is null")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
virtualDisplay = mp.createVirtualDisplay(
|
createOrSetVirtualDisplay(mp, surface!!)
|
||||||
"RustDeskVD",
|
|
||||||
SCREEN_INFO.width, SCREEN_INFO.height, SCREEN_INFO.dpi, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
|
||||||
surface, null, null
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startVP9VideoRecorder(mp: MediaProjection) {
|
private fun startVP9VideoRecorder(mp: MediaProjection) {
|
||||||
@@ -461,11 +523,28 @@ class MainService : Service() {
|
|||||||
}
|
}
|
||||||
it.setCallback(cb)
|
it.setCallback(cb)
|
||||||
it.start()
|
it.start()
|
||||||
virtualDisplay = mp.createVirtualDisplay(
|
createOrSetVirtualDisplay(mp, surface!!)
|
||||||
"RustDeskVD",
|
}
|
||||||
SCREEN_INFO.width, SCREEN_INFO.height, SCREEN_INFO.dpi, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
}
|
||||||
surface, null, null
|
|
||||||
)
|
// https://github.com/bk138/droidVNC-NG/blob/b79af62db5a1c08ed94e6a91464859ffed6f4e97/app/src/main/java/net/christianbeier/droidvnc_ng/MediaProjectionService.java#L250
|
||||||
|
// Reuse virtualDisplay if it exists, to avoid media projection confirmation dialog every connection.
|
||||||
|
private fun createOrSetVirtualDisplay(mp: MediaProjection, s: Surface) {
|
||||||
|
try {
|
||||||
|
virtualDisplay?.let {
|
||||||
|
it.resize(SCREEN_INFO.width, SCREEN_INFO.height, SCREEN_INFO.dpi)
|
||||||
|
it.setSurface(s)
|
||||||
|
} ?: let {
|
||||||
|
virtualDisplay = mp.createVirtualDisplay(
|
||||||
|
"RustDeskVD",
|
||||||
|
SCREEN_INFO.width, SCREEN_INFO.height, SCREEN_INFO.dpi, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||||
|
s, null, null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
Log.w(logTag, "createOrSetVirtualDisplay: got SecurityException, re-requesting confirmation");
|
||||||
|
// This initiates a prompt dialog for the user to confirm screen projection.
|
||||||
|
requestMediaProjection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,7 +572,6 @@ class MainService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun createMediaCodec() {
|
private fun createMediaCodec() {
|
||||||
Log.d(logTag, "MediaFormat.MIMETYPE_VIDEO_VP9 :$MIME_TYPE")
|
Log.d(logTag, "MediaFormat.MIMETYPE_VIDEO_VP9 :$MIME_TYPE")
|
||||||
videoEncoder = MediaCodec.createEncoderByType(MIME_TYPE)
|
videoEncoder = MediaCodec.createEncoderByType(MIME_TYPE)
|
||||||
@@ -513,76 +591,6 @@ class MainService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private fun startAudioRecorder() {
|
|
||||||
checkAudioRecorder()
|
|
||||||
if (audioReader != null && audioRecorder != null && minBufferSize != 0) {
|
|
||||||
try {
|
|
||||||
audioRecorder!!.startRecording()
|
|
||||||
audioRecordStat = true
|
|
||||||
thread {
|
|
||||||
while (audioRecordStat) {
|
|
||||||
audioReader!!.readSync(audioRecorder!!)?.let {
|
|
||||||
onAudioFrameUpdate(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.d(logTag, "Exit audio thread")
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.d(logTag, "startAudioRecorder fail:$e")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(logTag, "startAudioRecorder fail")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private fun checkAudioRecorder() {
|
|
||||||
if (audioRecorder != null && audioRecorder != null && minBufferSize != 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// read f32 to byte , length * 4
|
|
||||||
minBufferSize = 2 * 4 * AudioRecord.getMinBufferSize(
|
|
||||||
AUDIO_SAMPLE_RATE,
|
|
||||||
AUDIO_CHANNEL_MASK,
|
|
||||||
AUDIO_ENCODING
|
|
||||||
)
|
|
||||||
if (minBufferSize == 0) {
|
|
||||||
Log.d(logTag, "get min buffer size fail!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
audioReader = AudioReader(minBufferSize, 4)
|
|
||||||
Log.d(logTag, "init audioData len:$minBufferSize")
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
mediaProjection?.let {
|
|
||||||
val apcc = AudioPlaybackCaptureConfiguration.Builder(it)
|
|
||||||
.addMatchingUsage(AudioAttributes.USAGE_MEDIA)
|
|
||||||
.addMatchingUsage(AudioAttributes.USAGE_ALARM)
|
|
||||||
.addMatchingUsage(AudioAttributes.USAGE_GAME)
|
|
||||||
.addMatchingUsage(AudioAttributes.USAGE_UNKNOWN).build()
|
|
||||||
if (ActivityCompat.checkSelfPermission(
|
|
||||||
this,
|
|
||||||
Manifest.permission.RECORD_AUDIO
|
|
||||||
) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
audioRecorder = AudioRecord.Builder()
|
|
||||||
.setAudioFormat(
|
|
||||||
AudioFormat.Builder()
|
|
||||||
.setEncoding(AUDIO_ENCODING)
|
|
||||||
.setSampleRate(AUDIO_SAMPLE_RATE)
|
|
||||||
.setChannelMask(AUDIO_CHANNEL_MASK).build()
|
|
||||||
)
|
|
||||||
.setAudioPlaybackCaptureConfig(apcc)
|
|
||||||
.setBufferSizeInBytes(minBufferSize).build()
|
|
||||||
Log.d(logTag, "createAudioRecorder done,minBufferSize:$minBufferSize")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.d(logTag, "createAudioRecorder fail")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initNotification() {
|
private fun initNotification() {
|
||||||
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
notificationChannel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
notificationChannel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@@ -667,6 +675,21 @@ class MainService : Service() {
|
|||||||
notificationManager.notify(getClientNotifyID(clientID), notification)
|
notificationManager.notify(getClientNotifyID(clientID), notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun voiceCallRequestNotification(
|
||||||
|
clientID: Int,
|
||||||
|
type: String,
|
||||||
|
username: String,
|
||||||
|
peerId: String
|
||||||
|
) {
|
||||||
|
val notification = notificationBuilder
|
||||||
|
.setOngoing(false)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||||
|
.setContentTitle(translate("Do you accept?"))
|
||||||
|
.setContentText("$type:$username-$peerId")
|
||||||
|
.build()
|
||||||
|
notificationManager.notify(getClientNotifyID(clientID), notification)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getClientNotifyID(clientID: Int): Int {
|
private fun getClientNotifyID(clientID: Int): Int {
|
||||||
return clientID + NOTIFY_ID_OFFSET
|
return clientID + NOTIFY_ID_OFFSET
|
||||||
}
|
}
|
||||||
|
|||||||
22
flutter/android/app/src/main/kotlin/ffi.kt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// ffi.kt
|
||||||
|
|
||||||
|
package ffi
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
object FFI {
|
||||||
|
init {
|
||||||
|
System.loadLibrary("rustdesk")
|
||||||
|
}
|
||||||
|
|
||||||
|
external fun init(ctx: Context)
|
||||||
|
external fun startServer(app_dir: String, custom_client_config: String)
|
||||||
|
external fun startService()
|
||||||
|
external fun onVideoFrameUpdate(buf: ByteBuffer)
|
||||||
|
external fun onAudioFrameUpdate(buf: ByteBuffer)
|
||||||
|
external fun translateLocale(localeName: String, input: String): String
|
||||||
|
external fun refreshScreen()
|
||||||
|
external fun setFrameRawEnable(name: String, value: Boolean)
|
||||||
|
external fun setCodecInfo(info: String)
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,5 +1,6 @@
|
|||||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:accessibilityEventTypes="typeWindowsChanged"
|
android:accessibilityEventTypes="typeWindowsChanged"
|
||||||
|
android:canRetrieveWindowContent="true"
|
||||||
android:accessibilityFlags="flagDefault"
|
android:accessibilityFlags="flagDefault"
|
||||||
android:notificationTimeout="50"
|
android:notificationTimeout="50"
|
||||||
android:description="@string/accessibility_service_description"
|
android:description="@string/accessibility_service_description"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.7.10'
|
ext.kotlin_version = '1.9.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
|||||||
1
flutter/assets/auth-gitlab.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="236" preserveAspectRatio="xMidYMid"><path fill="#e24329" d="m128.075 236.075 47.104-144.97H80.97z"/><path fill="#fc6d26" d="M128.075 236.074 80.97 91.104H14.956z"/><path fill="#fca326" d="M14.956 91.104.642 135.16a9.752 9.752 0 0 0 3.542 10.903l123.891 90.012z"/><path fill="#e24329" d="M14.956 91.105H80.97L52.601 3.79c-1.46-4.493-7.816-4.492-9.275 0z"/><path fill="#fc6d26" d="m128.075 236.074 47.104-144.97h66.015z"/><path fill="#fca326" d="m241.194 91.104 14.314 44.056a9.752 9.752 0 0 1-3.543 10.903l-123.89 90.012z"/><path fill="#e24329" d="M241.194 91.105h-66.015l28.37-87.315c1.46-4.493 7.816-4.492 9.275 0z"/></svg>
|
||||||
|
After Width: | Height: | Size: 684 B |
1
flutter/assets/checkbox-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1696255389449" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1922" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M435.2 704c-9 0-17.8-3.8-23.8-10.6l-115.2-128c-11.8-13.2-10.8-33.4 2.4-45.2 13.2-11.8 33.4-10.8 45.2 2.4l90.6 100.6 245.2-291.8c11.4-13.6 31.6-15.2 45-4 13.6 11.4 15.2 31.6 4 45l-268.8 320c-6 7-14.6 11.2-24 11.4-0.2 0.2-0.4 0.2-0.6 0.2z" p-id="1923"></path><path d="M800 928H224c-70.6 0-128-57.4-128-128V224c0-70.6 57.4-128 128-128h576c70.6 0 128 57.4 128 128v576c0 70.6-57.4 128-128 128zM224 160c-35.2 0-64 28.8-64 64v576c0 35.2 28.8 64 64 64h576c35.2 0 64-28.8 64-64V224c0-35.2-28.8-64-64-64H224z" p-id="1924"></path></svg>
|
||||||
|
After Width: | Height: | Size: 856 B |
1
flutter/assets/chevron_up_chevron_down.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1696245886035" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4133" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 132.717714c-9.435429 0-18.852571 3.84-29.147429 12.434286L194.011429 379.574857c-7.277714 6.418286-11.556571 15.433143-11.556572 28.288 0 22.272 16.713143 39.003429 39.424 39.003429 8.996571 0 18.432-3.437714 28.288-11.154286L512 222.281143l261.851429 213.430857c9.874286 7.716571 19.291429 11.154286 28.708571 11.154286 22.308571 0 39.003429-16.731429 39.003429-39.003429 0-12.854857-4.278857-21.869714-11.556572-28.288L541.147429 144.713143c-10.294857-8.137143-19.291429-11.995429-29.147429-11.995429z m0 758.564572c9.856 0 18.852571-3.84 29.147429-11.995429L829.988571 644.425143c7.277714-6.418286 11.556571-15.433143 11.556572-28.288 0-22.272-16.713143-39.424-38.985143-39.424-9.435429 0-18.870857 3.858286-28.708571 11.574857L512 801.718857 250.148571 588.288c-9.874286-7.716571-19.291429-11.574857-28.288-11.574857-22.710857 0-39.424 17.152-39.424 39.424 0 12.854857 4.278857 21.869714 11.556572 28.288l288.859428 234.422857c10.294857 8.594286 19.712 12.434286 29.147429 12.434286z" p-id="4134"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
flutter/assets/file_transfer.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1694049173782" class="icon" viewBox="0 0 1024 1024" width="24" height="24" fill="#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="992" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M891.64 184.73H620.41c-27.41 0-54.41-7.77-77.32-22.5L428.13 87.36C402.77 71 372.91 62 342.64 62H131.95C93.5 62 62 93.5 62 132.36v759.68C62 930.91 93.5 962 131.95 962h759.68c38.86 0 70.36-31.09 70.36-69.96V255.09c0.01-38.86-31.49-70.36-70.35-70.36zM480.5 753.77c0 16.77-13.5 30.68-30.68 30.68-16.77 0-30.68-13.91-30.68-30.68V523.04l-31.91 55.64c-8.59 14.32-27.41 19.64-42.14 11.04-14.32-8.59-19.64-27.41-11.05-41.73l89.18-154.64c6.96-12.27 21.27-18 34.77-14.32 13.09 3.27 22.5 15.55 22.5 29.45v345.29z m209.04-139.5l-89.18 154.64c-5.32 9.82-15.55 15.55-26.59 15.55-2.46 0-5.32-0.41-7.77-1.23-13.5-3.68-22.91-15.55-22.91-29.46V408.5c0-16.77 13.91-30.68 30.68-30.68 17.18 0 30.68 13.91 30.68 30.68v230.73l31.91-55.64c8.59-14.73 27.41-19.64 42.14-11.05 14.73 8.6 19.64 27.01 11.04 41.73z" p-id="993"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
flutter/assets/scam.png
Normal file
|
After Width: | Height: | Size: 627 KiB |
@@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" class="icon" viewBox="0 0 1024 1024"><path d="M608 160c141.16 0 256 114.84 256 256 0 17.67 14.33 32 32 32s32-14.33 32-32c0-85.48-33.29-165.83-93.73-226.27C773.83 129.29 693.47 96 608 96c-17.67 0-32 14.33-32 32s14.33 32 32 32zm-24 168c61.76 0 112 50.24 112 112 0 17.67 14.33 32 32 32s32-14.33 32-32c0-97.05-78.95-176-176-176-17.67 0-32 14.33-32 32s14.33 32 32 32z"/><path d="M808.3 561.21c-12.76-3.83-25.7-6.2-38.46-7.03-60.3-4.5-116.45 18.9-146.55 61.08-22.6 31.67-45.66 50.01-68.52 54.5-17.71 3.48-33.12-1.7-45.49-5.85-2.66-.9-5.18-1.74-7.68-2.49-93.84-28.17-156.49-108.42-155.9-199.7.16-24.14 16.38-45.98 42.34-56.99 43.75-18.56 77.35-54 92.17-97.22 7.02-20.48 9.65-41.57 7.8-62.68-2.66-31.78-15.1-61.85-35.96-86.96-21.1-25.39-49.51-44-82.16-53.8-4.07-1.22-8.22-2.31-12.35-3.23-30.63-6.87-62.7-4.49-92.73 6.88-29.24 11.07-54.56 29.86-73.23 54.33a476.073 476.073 0 0 0-36.42 55.34 477.675 477.675 0 0 0-17.24 33.81C109.84 312.17 95.73 376.76 96 443.15c.26 63.78 13.7 126.26 39.95 185.7 27.55 62.39 69.3 119.84 120.74 166.11 54.14 48.71 117.6 84.85 188.63 107.4C499.02 919.41 554.33 928 610.21 928c10.99 0 22.01-.33 33.03-1 17.64-1.07 31.08-16.23 30.01-33.87-1.07-17.64-16.22-31.08-33.87-30.01-59.19 3.57-117.96-3.75-174.69-21.76C342.78 802.66 244.31 715.78 194.5 603c-46.76-105.9-46.21-221.33 1.55-325.03 4.55-9.87 9.57-19.72 14.92-29.26 9.29-16.54 19.89-32.64 31.5-47.86 23.47-30.77 64.09-45.87 101.07-37.58 2.66.6 5.33 1.3 7.95 2.08 40.93 12.29 69.48 45.6 72.75 84.86 0 .05.01.1.01.15 1.07 12.15-.47 24.39-4.58 36.37-8.94 26.06-29.58 47.59-56.63 59.07-23.58 10.01-43.63 25.72-57.99 45.45-15.12 20.78-23.2 45-23.36 70.05-.37 57.15 19 114.29 54.53 160.91 36.46 47.83 87.28 82.58 146.96 100.49 1.5.45 3.44 1.1 5.69 1.86 29.79 10.01 108.9 36.59 186.49-72.13 16.95-23.75 52.2-37.26 89.81-34.42l.36.03c7.97.51 16.17 2.02 24.34 4.47 22.12 6.64 42.04 25.38 56.11 52.77 16.97 33.04 21.71 72.53 12.1 100.56l-.16.47c-5.54 16.05-17.78 29.48-34.47 37.8-15.82 7.89-22.24 27.1-14.36 42.92s27.1 22.24 42.92 14.36c31.78-15.85 55.36-42.19 66.41-74.2l.18-.53c15.23-44.4 9.22-102.11-15.68-150.61-22.07-43.02-55.68-73.15-94.62-84.84z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" class="icon" viewBox="-186 -186 1365 1365"><path d="M608 160c141.16 0 256 114.84 256 256 0 17.67 14.33 32 32 32s32-14.33 32-32c0-85.48-33.29-165.83-93.73-226.27C773.83 129.29 693.47 96 608 96c-17.67 0-32 14.33-32 32s14.33 32 32 32zm-24 168c61.76 0 112 50.24 112 112 0 17.67 14.33 32 32 32s32-14.33 32-32c0-97.05-78.95-176-176-176-17.67 0-32 14.33-32 32s14.33 32 32 32z"/><path d="M808.3 561.21c-12.76-3.83-25.7-6.2-38.46-7.03-60.3-4.5-116.45 18.9-146.55 61.08-22.6 31.67-45.66 50.01-68.52 54.5-17.71 3.48-33.12-1.7-45.49-5.85-2.66-.9-5.18-1.74-7.68-2.49-93.84-28.17-156.49-108.42-155.9-199.7.16-24.14 16.38-45.98 42.34-56.99 43.75-18.56 77.35-54 92.17-97.22 7.02-20.48 9.65-41.57 7.8-62.68-2.66-31.78-15.1-61.85-35.96-86.96-21.1-25.39-49.51-44-82.16-53.8-4.07-1.22-8.22-2.31-12.35-3.23-30.63-6.87-62.7-4.49-92.73 6.88-29.24 11.07-54.56 29.86-73.23 54.33a476.073 476.073 0 0 0-36.42 55.34 477.675 477.675 0 0 0-17.24 33.81C109.84 312.17 95.73 376.76 96 443.15c.26 63.78 13.7 126.26 39.95 185.7 27.55 62.39 69.3 119.84 120.74 166.11 54.14 48.71 117.6 84.85 188.63 107.4C499.02 919.41 554.33 928 610.21 928c10.99 0 22.01-.33 33.03-1 17.64-1.07 31.08-16.23 30.01-33.87-1.07-17.64-16.22-31.08-33.87-30.01-59.19 3.57-117.96-3.75-174.69-21.76C342.78 802.66 244.31 715.78 194.5 603c-46.76-105.9-46.21-221.33 1.55-325.03 4.55-9.87 9.57-19.72 14.92-29.26 9.29-16.54 19.89-32.64 31.5-47.86 23.47-30.77 64.09-45.87 101.07-37.58 2.66.6 5.33 1.3 7.95 2.08 40.93 12.29 69.48 45.6 72.75 84.86 0 .05.01.1.01.15 1.07 12.15-.47 24.39-4.58 36.37-8.94 26.06-29.58 47.59-56.63 59.07-23.58 10.01-43.63 25.72-57.99 45.45-15.12 20.78-23.2 45-23.36 70.05-.37 57.15 19 114.29 54.53 160.91 36.46 47.83 87.28 82.58 146.96 100.49 1.5.45 3.44 1.1 5.69 1.86 29.79 10.01 108.9 36.59 186.49-72.13 16.95-23.75 52.2-37.26 89.81-34.42l.36.03c7.97.51 16.17 2.02 24.34 4.47 22.12 6.64 42.04 25.38 56.11 52.77 16.97 33.04 21.71 72.53 12.1 100.56l-.16.47c-5.54 16.05-17.78 29.48-34.47 37.8-15.82 7.89-22.24 27.1-14.36 42.92s27.1 22.24 42.92 14.36c31.78-15.85 55.36-42.19 66.41-74.2l.18-.53c15.23-44.4 9.22-102.11-15.68-150.61-22.07-43.02-55.68-73.15-94.62-84.84z"/></svg>
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@@ -1,13 +1,17 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Build libyuv / opus / libvpx / oboe for Android
|
set -e -o pipefail
|
||||||
|
|
||||||
|
ANDROID_ABI=$1
|
||||||
|
|
||||||
|
# Build RustDesk dependencies for Android using vcpkg.json
|
||||||
# Required:
|
# Required:
|
||||||
# 1. set VCPKG_ROOT / ANDROID_NDK path environment variables
|
# 1. set VCPKG_ROOT / ANDROID_NDK path environment variables
|
||||||
# 2. vcpkg initialized
|
# 2. vcpkg initialized
|
||||||
# 3. ndk, version: 22 (if ndk < 22 you need to change LD as `export LD=$TOOLCHAIN/bin/$NDK_LLVM_TARGET-ld`)
|
# 3. ndk, version: r25c or newer
|
||||||
|
|
||||||
if [ -z "$ANDROID_NDK" ]; then
|
if [ -z "$ANDROID_NDK_HOME" ]; then
|
||||||
echo "Failed! Please set ANDROID_NDK"
|
echo "Failed! Please set ANDROID_NDK_HOME"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -18,107 +22,66 @@ fi
|
|||||||
|
|
||||||
API_LEVEL="21"
|
API_LEVEL="21"
|
||||||
|
|
||||||
|
# Get directory of this script
|
||||||
|
|
||||||
|
SCRIPTDIR="$(readlink -f "$0")"
|
||||||
|
SCRIPTDIR="$(dirname "$SCRIPTDIR")"
|
||||||
|
|
||||||
|
# Check if vcpkg.json is one level up - in root directory of RD
|
||||||
|
|
||||||
|
if [ ! -f "$SCRIPTDIR/../vcpkg.json" ]; then
|
||||||
|
echo "Failed! Please check where vcpkg.json is!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# NDK llvm toolchain
|
# NDK llvm toolchain
|
||||||
|
|
||||||
HOST_TAG="linux-x86_64" # current platform, set as `ls $ANDROID_NDK/toolchains/llvm/prebuilt/`
|
HOST_TAG="linux-x86_64" # current platform, set as `ls $ANDROID_NDK/toolchains/llvm/prebuilt/`
|
||||||
TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG
|
TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG
|
||||||
|
|
||||||
function build {
|
function build {
|
||||||
ANDROID_ABI=$1
|
ANDROID_ABI=$1
|
||||||
VCPKG_TARGET=$2
|
|
||||||
NDK_LLVM_TARGET=$3
|
|
||||||
LIBVPX_TARGET=$4
|
|
||||||
|
|
||||||
PREFIX=$VCPKG_ROOT/installed/$VCPKG_TARGET/
|
case "$ANDROID_ABI" in
|
||||||
|
arm64-v8a)
|
||||||
|
ABI=aarch64-linux-android$API_LEVEL
|
||||||
|
VCPKG_TARGET=arm64-android
|
||||||
|
;;
|
||||||
|
armeabi-v7a)
|
||||||
|
ABI=armv7a-linux-androideabi$API_LEVEL
|
||||||
|
VCPKG_TARGET=arm-neon-android
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
ABI=x86_64-linux-android$API_LEVEL
|
||||||
|
VCPKG_TARGET=x64-android
|
||||||
|
;;
|
||||||
|
x86)
|
||||||
|
ABI=i686-linux-android$API_LEVEL
|
||||||
|
VCPKG_TARGET=x86-android
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: ANDROID_ABI must be one of: arm64-v8a, armeabi-v7a, x86_64, x86" >&2
|
||||||
|
return 1
|
||||||
|
esac
|
||||||
|
|
||||||
# 1
|
echo "*** [$ANDROID_ABI][Start] Build and install vcpkg dependencies"
|
||||||
echo "*** [$ANDROID_ABI][Start] Build opus / libyuv from vcpkg"
|
pushd "$SCRIPTDIR/.."
|
||||||
export ANDROID_NDK_HOME=$ANDROID_NDK
|
$VCPKG_ROOT/vcpkg install --triplet $VCPKG_TARGET --x-install-root="$VCPKG_ROOT/installed"
|
||||||
pushd $VCPKG_ROOT
|
|
||||||
$VCPKG_ROOT/vcpkg install opus --triplet $VCPKG_TARGET
|
|
||||||
$VCPKG_ROOT/vcpkg install libyuv --triplet $VCPKG_TARGET
|
|
||||||
popd
|
popd
|
||||||
echo "*** [$ANDROID_ABI][Finished] Build opus / libyuv from vcpkg"
|
echo "*** [$ANDROID_ABI][Finished] Build and install vcpkg dependencies"
|
||||||
|
|
||||||
# 2
|
if [ -d "$VCPKG_ROOT/installed/arm-neon-android" ]; then
|
||||||
echo "*** [$ANDROID_ABI][Start] Build libvpx"
|
echo "*** [Start] Move arm-neon-android to arm-android"
|
||||||
pushd build/libvpx
|
|
||||||
export AR=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}-ar
|
|
||||||
export AS=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}-as
|
|
||||||
export LD=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}-ld.gold # if ndk < 22, use aarch64-linux-android-ld
|
|
||||||
export RANLIB=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}-ranlib
|
|
||||||
export STRIP=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}-strip
|
|
||||||
|
|
||||||
if [ $NDK_LLVM_TARGET == "arm-linux-androideabi" ]
|
mv "$VCPKG_ROOT/installed/arm-neon-android" "$VCPKG_ROOT/installed/arm-android"
|
||||||
then
|
|
||||||
export CC=$TOOLCHAIN/bin/armv7a-linux-androideabi${API_LEVEL}-clang
|
|
||||||
export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi${API_LEVEL}-clang++
|
|
||||||
else
|
|
||||||
export CC=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}${API_LEVEL}-clang
|
|
||||||
export CXX=$TOOLCHAIN/bin/${NDK_LLVM_TARGET}${API_LEVEL}-clang++
|
|
||||||
fi
|
|
||||||
make clean
|
|
||||||
./configure --target=$LIBVPX_TARGET \
|
|
||||||
--enable-pic
|
|
||||||
--disable-webm-io \
|
|
||||||
--disable-unit-tests \
|
|
||||||
--disable-examples \
|
|
||||||
--disable-libyuv \
|
|
||||||
--disable-postproc \
|
|
||||||
--disable-tools \
|
|
||||||
--disable-docs \
|
|
||||||
--prefix=$PREFIX
|
|
||||||
make -j5
|
|
||||||
make install
|
|
||||||
|
|
||||||
popd
|
echo "*** [Finished] Move arm-neon-android to arm-android"
|
||||||
echo "*** [$ANDROID_ABI][Finished] Build libvpx"
|
fi
|
||||||
|
|
||||||
# 3
|
|
||||||
echo "*** [$ANDROID_ABI][Start] Build oboe"
|
|
||||||
pushd build/oboe
|
|
||||||
make clean
|
|
||||||
cmake -DBUILD_SHARED_LIBS=true \
|
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
|
||||||
-DANDROID_TOOLCHAIN=clang \
|
|
||||||
-DANDROID_STL=c++_shared \
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
|
|
||||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
|
||||||
-DANDROID_ABI=$ANDROID_ABI \
|
|
||||||
-DANDROID_PLATFORM=android-$API_LEVEL
|
|
||||||
make -j5
|
|
||||||
make install
|
|
||||||
mv $PREFIX/lib/$ANDROID_ABI/liboboe.a $PREFIX/lib/
|
|
||||||
popd
|
|
||||||
echo "*** [$ANDROID_ABI][Finished] Build oboe"
|
|
||||||
|
|
||||||
echo "*** [$ANDROID_ABI][All Finished]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
git clone -b v1.11.0 --depth=1 https://github.com/webmproject/libvpx.git build/libvpx
|
if [ ! -z "$ANDROID_ABI" ]; then
|
||||||
git clone -b 1.6.1 --depth=1 https://github.com/google/oboe build/oboe
|
build "$ANDROID_ABI"
|
||||||
patch -N -d build/oboe -p1 < ../src/oboe.patch
|
else
|
||||||
|
echo "Usage: build-android-deps.sh <ANDROID-ABI>" >&2
|
||||||
# VCPKG_TARGET ANDROID_ABI
|
exit 1
|
||||||
# arm64-android arm64-v8a
|
fi
|
||||||
# arm-android armeabi-v7a
|
|
||||||
# x64-android x86_64
|
|
||||||
# x86-android x86
|
|
||||||
|
|
||||||
# NDK_LLVM_TARGET
|
|
||||||
# aarch64-linux-android
|
|
||||||
# arm-linux-androideabi
|
|
||||||
# x86_64-linux-android
|
|
||||||
# i686-linux-android
|
|
||||||
|
|
||||||
# LIBVPX_TARGET :
|
|
||||||
# arm64-android-gcc
|
|
||||||
# armv7-android-gcc
|
|
||||||
# x86_64-android-gcc
|
|
||||||
# x86-android-gcc
|
|
||||||
|
|
||||||
# args: ANDROID_ABI VCPKG_TARGET NDK_LLVM_TARGET LIBVPX_TARGET
|
|
||||||
build arm64-v8a arm64-android aarch64-linux-android arm64-android-gcc
|
|
||||||
build armeabi-v7a arm-android arm-linux-androideabi armv7-android-gcc
|
|
||||||
|
|
||||||
# rm -rf build/libvpx
|
|
||||||
# rm -rf build/oboe
|
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
flutter build ipa --release --obfuscate --split-debug-info=./split-debug-info
|
# https://docs.flutter.dev/deployment/ios
|
||||||
|
# flutter build ipa --release --obfuscate --split-debug-info=./split-debug-info
|
||||||
|
# no obfuscate, because no easy to check errors
|
||||||
|
flutter build ipa --release
|
||||||
|
|||||||
@@ -21,6 +21,6 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>11.0</string>
|
<string>12.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '11.0'
|
# platform :ios, '12.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
platform :ios, '11.0'
|
platform :ios, '12.0'
|
||||||
|
|
||||||
project 'Runner', {
|
project 'Runner', {
|
||||||
'Debug' => :debug,
|
'Debug' => :debug,
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ PODS:
|
|||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_keyboard_visibility (0.0.1):
|
- flutter_keyboard_visibility (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FMDB (2.7.5):
|
|
||||||
- FMDB/standard (= 2.7.5)
|
|
||||||
- FMDB/standard (2.7.5)
|
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- MTBBarcodeScanner (5.0.11)
|
- MTBBarcodeScanner (5.0.11)
|
||||||
@@ -52,12 +49,12 @@ PODS:
|
|||||||
- qr_code_scanner (0.2.0):
|
- qr_code_scanner (0.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- MTBBarcodeScanner
|
- MTBBarcodeScanner
|
||||||
- SDWebImage (5.15.5):
|
- SDWebImage (5.18.11):
|
||||||
- SDWebImage/Core (= 5.15.5)
|
- SDWebImage/Core (= 5.18.11)
|
||||||
- SDWebImage/Core (5.15.5)
|
- SDWebImage/Core (5.18.11)
|
||||||
- sqflite (0.0.2):
|
- sqflite (0.0.3):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FMDB (>= 2.7.5)
|
- FlutterMacOS
|
||||||
- SwiftyGif (5.4.4)
|
- SwiftyGif (5.4.4)
|
||||||
- uni_links (0.0.1):
|
- uni_links (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -65,7 +62,8 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- video_player_avfoundation (0.0.1):
|
- video_player_avfoundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- wakelock (0.0.1):
|
- FlutterMacOS
|
||||||
|
- wakelock_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
@@ -75,19 +73,18 @@ DEPENDENCIES:
|
|||||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
|
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
|
||||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
|
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
|
||||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
- DKImagePickerController
|
- DKImagePickerController
|
||||||
- DKPhotoGallery
|
- DKPhotoGallery
|
||||||
- FMDB
|
|
||||||
- MTBBarcodeScanner
|
- MTBBarcodeScanner
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
- SwiftyGif
|
- SwiftyGif
|
||||||
@@ -106,41 +103,40 @@ EXTERNAL SOURCES:
|
|||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/ios"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
qr_code_scanner:
|
qr_code_scanner:
|
||||||
:path: ".symlinks/plugins/qr_code_scanner/ios"
|
:path: ".symlinks/plugins/qr_code_scanner/ios"
|
||||||
sqflite:
|
sqflite:
|
||||||
:path: ".symlinks/plugins/sqflite/ios"
|
:path: ".symlinks/plugins/sqflite/darwin"
|
||||||
uni_links:
|
uni_links:
|
||||||
:path: ".symlinks/plugins/uni_links/ios"
|
:path: ".symlinks/plugins/uni_links/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
video_player_avfoundation:
|
video_player_avfoundation:
|
||||||
:path: ".symlinks/plugins/video_player_avfoundation/ios"
|
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
|
||||||
wakelock:
|
wakelock_plus:
|
||||||
:path: ".symlinks/plugins/wakelock/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
|
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
|
||||||
image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb
|
|
||||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
||||||
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
|
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
||||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||||
SDWebImage: fd7e1a22f00303e058058278639bf6196ee431fe
|
SDWebImage: a3ba0b8faac7228c3c8eadd1a55c9c9fe5e16457
|
||||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||||
url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2
|
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
||||||
video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff
|
video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579
|
||||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
||||||
|
|
||||||
PODFILE CHECKSUM: c649b4e69a3086d323110011d04604e416ad0dcd
|
PODFILE CHECKSUM: d4cb12ad5d3bdb3352770b1d3db237584e155156
|
||||||
|
|
||||||
COCOAPODS: 1.12.0
|
COCOAPODS: 1.15.2
|
||||||
|
|||||||
@@ -159,7 +159,7 @@
|
|||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1300;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
@@ -208,6 +208,7 @@
|
|||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
);
|
);
|
||||||
name = "Thin Binary";
|
name = "Thin Binary";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
@@ -346,7 +347,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@@ -393,8 +394,6 @@
|
|||||||
"-framework",
|
"-framework",
|
||||||
"\"DKPhotoGallery\"",
|
"\"DKPhotoGallery\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"FMDB\"",
|
|
||||||
"-framework",
|
|
||||||
"\"Foundation\"",
|
"\"Foundation\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"ImageIO\"",
|
"\"ImageIO\"",
|
||||||
@@ -433,10 +432,11 @@
|
|||||||
"-framework",
|
"-framework",
|
||||||
"\"video_player_avfoundation\"",
|
"\"video_player_avfoundation\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"wakelock\"",
|
"\"wakelock_plus\"",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb;
|
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
STRIP_STYLE = "non-global";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
@@ -491,7 +491,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@@ -541,7 +541,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@@ -590,8 +590,6 @@
|
|||||||
"-framework",
|
"-framework",
|
||||||
"\"DKPhotoGallery\"",
|
"\"DKPhotoGallery\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"FMDB\"",
|
|
||||||
"-framework",
|
|
||||||
"\"Foundation\"",
|
"\"Foundation\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"ImageIO\"",
|
"\"ImageIO\"",
|
||||||
@@ -630,10 +628,11 @@
|
|||||||
"-framework",
|
"-framework",
|
||||||
"\"video_player_avfoundation\"",
|
"\"video_player_avfoundation\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"wakelock\"",
|
"\"wakelock_plus\"",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb;
|
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
STRIP_STYLE = "non-global";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -679,8 +678,6 @@
|
|||||||
"-framework",
|
"-framework",
|
||||||
"\"DKPhotoGallery\"",
|
"\"DKPhotoGallery\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"FMDB\"",
|
|
||||||
"-framework",
|
|
||||||
"\"Foundation\"",
|
"\"Foundation\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"ImageIO\"",
|
"\"ImageIO\"",
|
||||||
@@ -719,10 +716,11 @@
|
|||||||
"-framework",
|
"-framework",
|
||||||
"\"video_player_avfoundation\"",
|
"\"video_player_avfoundation\"",
|
||||||
"-framework",
|
"-framework",
|
||||||
"\"wakelock\"",
|
"\"wakelock_plus\"",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb;
|
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
STRIP_STYLE = "non-global";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1300"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ import Flutter
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func dummyMethodToEnforceBundling() {
|
public func dummyMethodToEnforceBundling() {
|
||||||
get_rgba();
|
dummy_method_to_enforce_bundling();
|
||||||
// free_rgba(nil);
|
session_get_rgba(nil, 0);
|
||||||
// get_by_name("", "");
|
|
||||||
// set_by_name("", "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,122 +1,122 @@
|
|||||||
{
|
{
|
||||||
"images": [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-20x20@2x.png",
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "20x20"
|
"size" : "20x20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-20x20@3x.png",
|
"filename" : "Icon-App-20x20@3x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "3x",
|
"scale" : "3x",
|
||||||
"size": "20x20"
|
"size" : "20x20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-29x29@1x.png",
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "1x",
|
"scale" : "1x",
|
||||||
"size": "29x29"
|
"size" : "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-29x29@2x.png",
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "29x29"
|
"size" : "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-29x29@3x.png",
|
"filename" : "Icon-App-29x29@3x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "3x",
|
"scale" : "3x",
|
||||||
"size": "29x29"
|
"size" : "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-40x40@2x.png",
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "40x40"
|
"size" : "40x40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-40x40@3x.png",
|
"filename" : "Icon-App-40x40@3x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "3x",
|
"scale" : "3x",
|
||||||
"size": "40x40"
|
"size" : "40x40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-60x60@2x.png",
|
"filename" : "Icon-App-60x60@2x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "60x60"
|
"size" : "60x60"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-60x60@3x.png",
|
"filename" : "Icon-App-60x60@3x.png",
|
||||||
"idiom": "iphone",
|
"idiom" : "iphone",
|
||||||
"scale": "3x",
|
"scale" : "3x",
|
||||||
"size": "60x60"
|
"size" : "60x60"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-20x20@1x.png",
|
"filename" : "Icon-App-20x20@1x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "1x",
|
"scale" : "1x",
|
||||||
"size": "20x20"
|
"size" : "20x20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-20x20@2x.png",
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "20x20"
|
"size" : "20x20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-29x29@1x.png",
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "1x",
|
"scale" : "1x",
|
||||||
"size": "29x29"
|
"size" : "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-29x29@2x.png",
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "29x29"
|
"size" : "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-40x40@1x.png",
|
"filename" : "Icon-App-40x40@1x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "1x",
|
"scale" : "1x",
|
||||||
"size": "40x40"
|
"size" : "40x40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-40x40@2x.png",
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "40x40"
|
"size" : "40x40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-76x76@1x.png",
|
"filename" : "Icon-App-76x76@1x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "1x",
|
"scale" : "1x",
|
||||||
"size": "76x76"
|
"size" : "76x76"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-76x76@2x.png",
|
"filename" : "Icon-App-76x76@2x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "76x76"
|
"size" : "76x76"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-83.5x83.5@2x.png",
|
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||||
"idiom": "ipad",
|
"idiom" : "ipad",
|
||||||
"scale": "2x",
|
"scale" : "2x",
|
||||||
"size": "83.5x83.5"
|
"size" : "83.5x83.5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Icon-App-1024x1024@1x.png",
|
"filename" : "Icon-App-1024x1024@1x.png",
|
||||||
"idiom": "ios-marketing",
|
"idiom" : "ios-marketing",
|
||||||
"scale": "1x",
|
"scale" : "1x",
|
||||||
"size": "1024x1024"
|
"size" : "1024x1024"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info": {
|
"info" : {
|
||||||
"author": "icons_launcher",
|
"author" : "xcode",
|
||||||
"version": 1
|
"version" : 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage.png",
|
"filename" : "LaunchImage.png",
|
||||||
|
"idiom" : "universal",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage@2x.png",
|
"filename" : "LaunchImage@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage@3x.png",
|
"filename" : "LaunchImage@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"version" : 1,
|
"author" : "xcode",
|
||||||
"author" : "xcode"
|
"version" : 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Flutter View Controller-->
|
<!--Flutter View Controller-->
|
||||||
@@ -14,13 +16,14 @@
|
|||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
|
<point key="canvasLocation" x="48" y="-2"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -24,6 +24,21 @@
|
|||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLIconFile</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>com.carriez.rustdesk</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>rustdesk</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#import "GeneratedPluginRegistrant.h"
|
#import "GeneratedPluginRegistrant.h"
|
||||||
|
|
||||||
#import "ffi.h"
|
#import "bridge_generated.h"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
void* get_rgba();
|
|
||||||
void free_rgba(void*);
|
|
||||||
void set_by_name(const char*, const char*);
|
|
||||||
const char* get_by_name(const char*, const char*);
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hbb/common.dart';
|
||||||
|
import 'package:flutter_hbb/consts.dart';
|
||||||
|
|
||||||
import 'package:flutter_hbb/models/peer_model.dart';
|
import 'package:flutter_hbb/models/peer_model.dart';
|
||||||
|
|
||||||
@@ -10,9 +12,11 @@ class HttpType {
|
|||||||
static const kAuthReqTypeMobile = "mobile";
|
static const kAuthReqTypeMobile = "mobile";
|
||||||
static const kAuthReqTypeSMSCode = "sms_code";
|
static const kAuthReqTypeSMSCode = "sms_code";
|
||||||
static const kAuthReqTypeEmailCode = "email_code";
|
static const kAuthReqTypeEmailCode = "email_code";
|
||||||
|
static const kAuthReqTypeTfaCode = "tfa_code";
|
||||||
|
|
||||||
static const kAuthResTypeToken = "access_token";
|
static const kAuthResTypeToken = "access_token";
|
||||||
static const kAuthResTypeEmailCheck = "email_check";
|
static const kAuthResTypeEmailCheck = "email_check";
|
||||||
|
static const kAuthResTypeTfaCheck = "tfa_check";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UserStatus { kDisabled, kNormal, kUnverified }
|
enum UserStatus { kDisabled, kNormal, kUnverified }
|
||||||
@@ -48,11 +52,18 @@ class UserPayload {
|
|||||||
};
|
};
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toGroupCacheJson() {
|
||||||
|
final Map<String, dynamic> map = {
|
||||||
|
'name': name,
|
||||||
|
};
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PeerPayload {
|
class PeerPayload {
|
||||||
String id = '';
|
String id = '';
|
||||||
String info = '';
|
Map<String, dynamic> info = {};
|
||||||
int? status;
|
int? status;
|
||||||
String user = '';
|
String user = '';
|
||||||
String user_name = '';
|
String user_name = '';
|
||||||
@@ -60,14 +71,45 @@ class PeerPayload {
|
|||||||
|
|
||||||
PeerPayload.fromJson(Map<String, dynamic> json)
|
PeerPayload.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'] ?? '',
|
: id = json['id'] ?? '',
|
||||||
info = json['info'] ?? '',
|
info = (json['info'] is Map<String, dynamic>) ? json['info'] : {},
|
||||||
status = json['status'],
|
status = json['status'],
|
||||||
user = json['user'] ?? '',
|
user = json['user'] ?? '',
|
||||||
user_name = json['user_name'] ?? '',
|
user_name = json['user_name'] ?? '',
|
||||||
note = json['note'] ?? '';
|
note = json['note'] ?? '';
|
||||||
|
|
||||||
static Peer toPeer(PeerPayload p) {
|
static Peer toPeer(PeerPayload p) {
|
||||||
return Peer.fromJson({"id": p.id, "username": p.user_name});
|
return Peer.fromJson({
|
||||||
|
"id": p.id,
|
||||||
|
'loginName': p.user_name,
|
||||||
|
"username": p.info['username'] ?? '',
|
||||||
|
"platform": _platform(p.info['os']),
|
||||||
|
"hostname": p.info['device_name'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static String? _platform(dynamic field) {
|
||||||
|
if (field == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final fieldStr = field.toString();
|
||||||
|
List<String> list = fieldStr.split(' / ');
|
||||||
|
if (list.isEmpty) return null;
|
||||||
|
final os = list[0];
|
||||||
|
switch (os.toLowerCase()) {
|
||||||
|
case 'windows':
|
||||||
|
return kPeerPlatformWindows;
|
||||||
|
case 'linux':
|
||||||
|
return kPeerPlatformLinux;
|
||||||
|
case 'macos':
|
||||||
|
return kPeerPlatformMacOS;
|
||||||
|
case 'android':
|
||||||
|
return kPeerPlatformAndroid;
|
||||||
|
default:
|
||||||
|
if (fieldStr.toLowerCase().contains('linux')) {
|
||||||
|
return kPeerPlatformLinux;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +121,8 @@ class LoginRequest {
|
|||||||
bool? autoLogin;
|
bool? autoLogin;
|
||||||
String? type;
|
String? type;
|
||||||
String? verificationCode;
|
String? verificationCode;
|
||||||
|
String? tfaCode;
|
||||||
|
String? secret;
|
||||||
|
|
||||||
LoginRequest(
|
LoginRequest(
|
||||||
{this.username,
|
{this.username,
|
||||||
@@ -87,7 +131,9 @@ class LoginRequest {
|
|||||||
this.uuid,
|
this.uuid,
|
||||||
this.autoLogin,
|
this.autoLogin,
|
||||||
this.type,
|
this.type,
|
||||||
this.verificationCode});
|
this.verificationCode,
|
||||||
|
this.tfaCode,
|
||||||
|
this.secret});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
@@ -100,6 +146,8 @@ class LoginRequest {
|
|||||||
if (verificationCode != null) {
|
if (verificationCode != null) {
|
||||||
data['verificationCode'] = verificationCode;
|
data['verificationCode'] = verificationCode;
|
||||||
}
|
}
|
||||||
|
if (tfaCode != null) data['tfaCode'] = tfaCode;
|
||||||
|
if (secret != null) data['secret'] = secret;
|
||||||
|
|
||||||
Map<String, dynamic> deviceInfo = {};
|
Map<String, dynamic> deviceInfo = {};
|
||||||
try {
|
try {
|
||||||
@@ -115,13 +163,18 @@ class LoginRequest {
|
|||||||
class LoginResponse {
|
class LoginResponse {
|
||||||
String? access_token;
|
String? access_token;
|
||||||
String? type;
|
String? type;
|
||||||
|
String? tfa_type;
|
||||||
|
String? secret;
|
||||||
UserPayload? user;
|
UserPayload? user;
|
||||||
|
|
||||||
LoginResponse({this.access_token, this.type, this.user});
|
LoginResponse(
|
||||||
|
{this.access_token, this.type, this.tfa_type, this.secret, this.user});
|
||||||
|
|
||||||
LoginResponse.fromJson(Map<String, dynamic> json) {
|
LoginResponse.fromJson(Map<String, dynamic> json) {
|
||||||
access_token = json['access_token'];
|
access_token = json['access_token'];
|
||||||
type = json['type'];
|
type = json['type'];
|
||||||
|
tfa_type = json['tfa_type'];
|
||||||
|
secret = json['secret'];
|
||||||
user = json['user'] != null ? UserPayload.fromJson(json['user']) : null;
|
user = json['user'] != null ? UserPayload.fromJson(json['user']) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,3 +189,79 @@ class RequestException implements Exception {
|
|||||||
return "RequestException, statusCode: $statusCode, error: $cause";
|
return "RequestException, statusCode: $statusCode, error: $cause";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ShareRule {
|
||||||
|
read(1),
|
||||||
|
readWrite(2),
|
||||||
|
fullControl(3);
|
||||||
|
|
||||||
|
const ShareRule(this.value);
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
static String desc(int v) {
|
||||||
|
if (v == ShareRule.read.value) {
|
||||||
|
return translate('Read-only');
|
||||||
|
}
|
||||||
|
if (v == ShareRule.readWrite.value) {
|
||||||
|
return translate('Read/Write');
|
||||||
|
}
|
||||||
|
if (v == ShareRule.fullControl.value) {
|
||||||
|
return translate('Full Control');
|
||||||
|
}
|
||||||
|
return v.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String shortDesc(int v) {
|
||||||
|
if (v == ShareRule.read.value) {
|
||||||
|
return 'R';
|
||||||
|
}
|
||||||
|
if (v == ShareRule.readWrite.value) {
|
||||||
|
return 'RW';
|
||||||
|
}
|
||||||
|
if (v == ShareRule.fullControl.value) {
|
||||||
|
return 'F';
|
||||||
|
}
|
||||||
|
return v.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ShareRule? fromValue(int v) {
|
||||||
|
if (v == ShareRule.read.value) {
|
||||||
|
return ShareRule.read;
|
||||||
|
}
|
||||||
|
if (v == ShareRule.readWrite.value) {
|
||||||
|
return ShareRule.readWrite;
|
||||||
|
}
|
||||||
|
if (v == ShareRule.fullControl.value) {
|
||||||
|
return ShareRule.fullControl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AbProfile {
|
||||||
|
String guid;
|
||||||
|
String name;
|
||||||
|
String owner;
|
||||||
|
String? note;
|
||||||
|
int rule;
|
||||||
|
|
||||||
|
AbProfile(this.guid, this.name, this.owner, this.note, this.rule);
|
||||||
|
|
||||||
|
AbProfile.fromJson(Map<String, dynamic> json)
|
||||||
|
: guid = json['guid'] ?? '',
|
||||||
|
name = json['name'] ?? '',
|
||||||
|
owner = json['owner'] ?? '',
|
||||||
|
note = json['note'] ?? '',
|
||||||
|
rule = json['rule'] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AbTag {
|
||||||
|
String name;
|
||||||
|
int color;
|
||||||
|
|
||||||
|
AbTag(this.name, this.color);
|
||||||
|
|
||||||
|
AbTag.fromJson(Map<String, dynamic> json)
|
||||||
|
: name = json['name'] ?? '',
|
||||||
|
color = json['color'] ?? '';
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter_hbb/common.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
@@ -10,7 +11,7 @@ class PrivacyModeState {
|
|||||||
static void init(String id) {
|
static void init(String id) {
|
||||||
final key = tag(id);
|
final key = tag(id);
|
||||||
if (!Get.isRegistered(tag: key)) {
|
if (!Get.isRegistered(tag: key)) {
|
||||||
final RxBool state = false.obs;
|
final RxString state = ''.obs;
|
||||||
Get.put(state, tag: key);
|
Get.put(state, tag: key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,11 +21,11 @@ class PrivacyModeState {
|
|||||||
if (Get.isRegistered(tag: key)) {
|
if (Get.isRegistered(tag: key)) {
|
||||||
Get.delete(tag: key);
|
Get.delete(tag: key);
|
||||||
} else {
|
} else {
|
||||||
Get.find<RxBool>(tag: key).value = false;
|
Get.find<RxString>(tag: key).value = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
static RxString find(String id) => Get.find<RxString>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlockInputState {
|
class BlockInputState {
|
||||||
@@ -167,6 +168,29 @@ class ShowRemoteCursorState {
|
|||||||
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShowRemoteCursorLockState {
|
||||||
|
static String tag(String id) => 'show_remote_cursor_lock_$id';
|
||||||
|
|
||||||
|
static void init(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
final RxBool state = false.obs;
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
} else {
|
||||||
|
Get.find<RxBool>(tag: key).value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
|
}
|
||||||
|
|
||||||
class KeyboardEnabledState {
|
class KeyboardEnabledState {
|
||||||
static String tag(String id) => 'keyboard_enabled_$id';
|
static String tag(String id) => 'keyboard_enabled_$id';
|
||||||
|
|
||||||
@@ -314,10 +338,12 @@ initSharedStates(String id) {
|
|||||||
CurrentDisplayState.init(id);
|
CurrentDisplayState.init(id);
|
||||||
KeyboardEnabledState.init(id);
|
KeyboardEnabledState.init(id);
|
||||||
ShowRemoteCursorState.init(id);
|
ShowRemoteCursorState.init(id);
|
||||||
|
ShowRemoteCursorLockState.init(id);
|
||||||
RemoteCursorMovedState.init(id);
|
RemoteCursorMovedState.init(id);
|
||||||
FingerprintState.init(id);
|
FingerprintState.init(id);
|
||||||
PeerBoolOption.init(id, 'zoom-cursor', () => false);
|
PeerBoolOption.init(id, kOptionZoomCursor, () => false);
|
||||||
UnreadChatCountState.init(id);
|
UnreadChatCountState.init(id);
|
||||||
|
if (isMobile) ConnectionTypeState.init(id); // desktop in other places
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSharedStates(String id) {
|
removeSharedStates(String id) {
|
||||||
@@ -325,9 +351,11 @@ removeSharedStates(String id) {
|
|||||||
BlockInputState.delete(id);
|
BlockInputState.delete(id);
|
||||||
CurrentDisplayState.delete(id);
|
CurrentDisplayState.delete(id);
|
||||||
ShowRemoteCursorState.delete(id);
|
ShowRemoteCursorState.delete(id);
|
||||||
|
ShowRemoteCursorLockState.delete(id);
|
||||||
KeyboardEnabledState.delete(id);
|
KeyboardEnabledState.delete(id);
|
||||||
RemoteCursorMovedState.delete(id);
|
RemoteCursorMovedState.delete(id);
|
||||||
FingerprintState.delete(id);
|
FingerprintState.delete(id);
|
||||||
PeerBoolOption.delete(id, 'zoom-cursor');
|
PeerBoolOption.delete(id, kOptionZoomCursor);
|
||||||
UnreadChatCountState.delete(id);
|
UnreadChatCountState.delete(id);
|
||||||
|
if (isMobile) ConnectionTypeState.delete(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
|
import 'package:dynamic_layouts/dynamic_layouts.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||||
|
import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||||
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
||||||
import 'package:flutter_hbb/models/ab_model.dart';
|
import 'package:flutter_hbb/models/ab_model.dart';
|
||||||
import 'package:flutter_hbb/models/platform_model.dart';
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:flex_color_picker/flex_color_picker.dart';
|
||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import 'dialog.dart';
|
import 'dialog.dart';
|
||||||
@@ -34,30 +42,29 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Obx(() {
|
Widget build(BuildContext context) => Obx(() {
|
||||||
if (gFFI.userModel.userName.value.isEmpty) {
|
if (!gFFI.userModel.isLogin) {
|
||||||
return Center(
|
return Center(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: loginDialog, child: Text(translate("Login"))));
|
onPressed: loginDialog, child: Text(translate("Login"))));
|
||||||
} else {
|
} else {
|
||||||
if (gFFI.abModel.abLoading.value && gFFI.abModel.emtpy) {
|
|
||||||
return const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
// NOT use Offstage to wrap LinearProgressIndicator
|
// NOT use Offstage to wrap LinearProgressIndicator
|
||||||
if (gFFI.abModel.retrying.value) LinearProgressIndicator(),
|
if (gFFI.abModel.currentAbLoading.value &&
|
||||||
_buildErrorBanner(
|
gFFI.abModel.currentAbEmpty)
|
||||||
err: gFFI.abModel.pullError,
|
const LinearProgressIndicator(),
|
||||||
|
buildErrorBanner(context,
|
||||||
|
loading: gFFI.abModel.currentAbLoading,
|
||||||
|
err: gFFI.abModel.currentAbPullError,
|
||||||
retry: null,
|
retry: null,
|
||||||
close: () => gFFI.abModel.pullError.value = ''),
|
close: () => gFFI.abModel.currentAbPullError.value = ''),
|
||||||
_buildErrorBanner(
|
buildErrorBanner(context,
|
||||||
err: gFFI.abModel.pushError,
|
loading: gFFI.abModel.currentAbLoading,
|
||||||
retry: () => gFFI.abModel.pushAb(isRetry: true),
|
err: gFFI.abModel.currentAbPushError,
|
||||||
close: () => gFFI.abModel.pushError.value = ''),
|
retry: null, // remove retry
|
||||||
|
close: () => gFFI.abModel.currentAbPushError.value = ''),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: isDesktop
|
child: (isDesktop || isWebDesktop)
|
||||||
? _buildAddressBookDesktop()
|
? _buildAddressBookDesktop()
|
||||||
: _buildAddressBookMobile())
|
: _buildAddressBookMobile())
|
||||||
],
|
],
|
||||||
@@ -65,61 +72,6 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
Widget _buildAddressBookDesktop() {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -131,19 +83,23 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).colorScheme.background)),
|
color: Theme.of(context).colorScheme.background)),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 150,
|
width: 200,
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
_buildAbDropdown(),
|
||||||
|
_buildTagHeader().marginOnly(
|
||||||
|
left: 8.0,
|
||||||
|
right: gFFI.abModel.legacyMode.value ? 8.0 : 0,
|
||||||
|
top: gFFI.abModel.legacyMode.value ? 8.0 : 0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
child: _buildTags(),
|
child: _buildTags(),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
_buildAbPermission(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -168,11 +124,13 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
_buildAbDropdown(),
|
||||||
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
_buildTagHeader().marginOnly(left: 8.0, right: 0),
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: _buildTags(),
|
child: _buildTags(),
|
||||||
),
|
),
|
||||||
|
_buildAbPermission(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -182,6 +140,150 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildAbPermission() {
|
||||||
|
icon(IconData data, String tooltip) {
|
||||||
|
return Tooltip(
|
||||||
|
message: translate(tooltip),
|
||||||
|
waitDuration: Duration.zero,
|
||||||
|
child: Icon(data, size: 12.0).marginSymmetric(horizontal: 2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Obx(() {
|
||||||
|
if (gFFI.abModel.legacyMode.value) return Offstage();
|
||||||
|
if (gFFI.abModel.current.isPersonal()) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
icon(Icons.cloud_off, "Personal"),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
List<Widget> children = [];
|
||||||
|
final rule = gFFI.abModel.current.sharedProfile()?.rule;
|
||||||
|
if (rule == ShareRule.read.value) {
|
||||||
|
children.add(
|
||||||
|
icon(Icons.visibility, ShareRule.desc(ShareRule.read.value)));
|
||||||
|
} else if (rule == ShareRule.readWrite.value) {
|
||||||
|
children
|
||||||
|
.add(icon(Icons.edit, ShareRule.desc(ShareRule.readWrite.value)));
|
||||||
|
} else if (rule == ShareRule.fullControl.value) {
|
||||||
|
children.add(icon(
|
||||||
|
Icons.security, ShareRule.desc(ShareRule.fullControl.value)));
|
||||||
|
}
|
||||||
|
final owner = gFFI.abModel.current.sharedProfile()?.owner;
|
||||||
|
if (owner != null) {
|
||||||
|
children.add(icon(Icons.person, "${translate("Owner")}: $owner"));
|
||||||
|
}
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAbDropdown() {
|
||||||
|
if (gFFI.abModel.legacyMode.value) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
|
final names = gFFI.abModel.addressBookNames();
|
||||||
|
if (!names.contains(gFFI.abModel.currentName.value)) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
|
// order: personal, divider, character order
|
||||||
|
// https://pub.dev/packages/dropdown_button2#3-dropdownbutton2-with-items-of-different-heights-like-dividers
|
||||||
|
final personalAddressBookName = gFFI.abModel.personalAddressBookName();
|
||||||
|
bool contains = names.remove(personalAddressBookName);
|
||||||
|
names.sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
|
||||||
|
if (contains) {
|
||||||
|
names.insert(0, personalAddressBookName);
|
||||||
|
}
|
||||||
|
final items = names
|
||||||
|
.map((e) => DropdownMenuItem(
|
||||||
|
value: e,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Tooltip(
|
||||||
|
waitDuration: Duration(milliseconds: 500),
|
||||||
|
message: gFFI.abModel.translatedName(e),
|
||||||
|
child: Text(
|
||||||
|
gFFI.abModel.translatedName(e),
|
||||||
|
style: TextStyle(fontSize: 14.0),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)))
|
||||||
|
.toList();
|
||||||
|
var menuItemStyleData = MenuItemStyleData(height: 36);
|
||||||
|
if (contains && items.length > 1) {
|
||||||
|
items.insert(1, DropdownMenuItem(enabled: false, child: Divider()));
|
||||||
|
List<double> customHeights = List.filled(items.length, 36);
|
||||||
|
customHeights[1] = 4;
|
||||||
|
menuItemStyleData = MenuItemStyleData(customHeights: customHeights);
|
||||||
|
}
|
||||||
|
final TextEditingController textEditingController = TextEditingController();
|
||||||
|
|
||||||
|
final isOptFixed = isOptionFixed(kOptionCurrentAbName);
|
||||||
|
return DropdownButton2<String>(
|
||||||
|
value: gFFI.abModel.currentName.value,
|
||||||
|
onChanged: isOptFixed
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
|
if (value != null) {
|
||||||
|
gFFI.abModel.setCurrentName(value);
|
||||||
|
bind.setLocalFlutterOption(k: kOptionCurrentAbName, v: value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
underline: Container(
|
||||||
|
height: 0.7,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
|
),
|
||||||
|
buttonStyleData: ButtonStyleData(height: 48),
|
||||||
|
menuItemStyleData: menuItemStyleData,
|
||||||
|
items: items,
|
||||||
|
isExpanded: true,
|
||||||
|
dropdownSearchData: DropdownSearchData(
|
||||||
|
searchController: textEditingController,
|
||||||
|
searchInnerWidgetHeight: 50,
|
||||||
|
searchInnerWidget: Container(
|
||||||
|
height: 50,
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 8,
|
||||||
|
bottom: 4,
|
||||||
|
right: 8,
|
||||||
|
left: 8,
|
||||||
|
),
|
||||||
|
child: TextFormField(
|
||||||
|
expands: true,
|
||||||
|
maxLines: null,
|
||||||
|
controller: textEditingController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
hintText: translate('Search'),
|
||||||
|
hintStyle: const TextStyle(fontSize: 12),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
searchMatchFn: (item, searchValue) {
|
||||||
|
return item.value
|
||||||
|
.toString()
|
||||||
|
.toLowerCase()
|
||||||
|
.contains(searchValue.toLowerCase());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildTagHeader() {
|
Widget _buildTagHeader() {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
@@ -203,25 +305,38 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
return Obx(() {
|
return Obx(() {
|
||||||
final List tags;
|
final List tags;
|
||||||
if (gFFI.abModel.sortTags.value) {
|
if (gFFI.abModel.sortTags.value) {
|
||||||
tags = gFFI.abModel.tags.toList();
|
tags = gFFI.abModel.currentAbTags.toList();
|
||||||
tags.sort();
|
tags.sort();
|
||||||
} else {
|
} else {
|
||||||
tags = gFFI.abModel.tags;
|
tags = gFFI.abModel.currentAbTags;
|
||||||
}
|
}
|
||||||
return Wrap(
|
final editPermission = gFFI.abModel.current.canWrite();
|
||||||
children: tags
|
tagBuilder(String e) {
|
||||||
.map((e) => AddressBookTag(
|
return AddressBookTag(
|
||||||
name: e,
|
name: e,
|
||||||
tags: gFFI.abModel.selectedTags,
|
tags: gFFI.abModel.selectedTags,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (gFFI.abModel.selectedTags.contains(e)) {
|
if (gFFI.abModel.selectedTags.contains(e)) {
|
||||||
gFFI.abModel.selectedTags.remove(e);
|
gFFI.abModel.selectedTags.remove(e);
|
||||||
} else {
|
} else {
|
||||||
gFFI.abModel.selectedTags.add(e);
|
gFFI.abModel.selectedTags.add(e);
|
||||||
}
|
}
|
||||||
}))
|
},
|
||||||
.toList(),
|
showActionMenu: editPermission);
|
||||||
);
|
}
|
||||||
|
|
||||||
|
final gridView = DynamicGridView.builder(
|
||||||
|
shrinkWrap: isMobile,
|
||||||
|
gridDelegate: SliverGridDelegateWithWrapping(),
|
||||||
|
itemCount: tags.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
final e = tags[index];
|
||||||
|
return tagBuilder(e);
|
||||||
|
});
|
||||||
|
final maxHeight = max(MediaQuery.of(context).size.height / 6, 100.0);
|
||||||
|
return (isDesktop || isWebDesktop)
|
||||||
|
? gridView
|
||||||
|
: LimitedBox(maxHeight: maxHeight, child: gridView);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,16 +344,16 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
return Expanded(
|
return Expanded(
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
child: Obx(() => AddressBookPeersView(
|
child: AddressBookPeersView(
|
||||||
menuPadding: widget.menuPadding,
|
menuPadding: widget.menuPadding,
|
||||||
// ignore: invalid_use_of_protected_member
|
getInitPeers: () => gFFI.abModel.currentAbPeers,
|
||||||
initPeers: gFFI.abModel.peers.value,
|
)),
|
||||||
))),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MenuEntryBase<String> syncMenuItem() {
|
MenuEntryBase<String> syncMenuItem() {
|
||||||
|
final isOptFixed = isOptionFixed(syncAbOption);
|
||||||
return MenuEntrySwitch<String>(
|
return MenuEntrySwitch<String>(
|
||||||
switchType: SwitchType.scheckbox,
|
switchType: SwitchType.scheckbox,
|
||||||
text: translate('Sync with recent sessions'),
|
text: translate('Sync with recent sessions'),
|
||||||
@@ -246,14 +361,16 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
return shouldSyncAb();
|
return shouldSyncAb();
|
||||||
},
|
},
|
||||||
setter: (bool v) async {
|
setter: (bool v) async {
|
||||||
bind.mainSetLocalOption(key: syncAbOption, value: v ? 'Y' : '');
|
gFFI.abModel.setShouldAsync(v);
|
||||||
},
|
},
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
|
enabled: (!isOptFixed).obs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MenuEntryBase<String> sortMenuItem() {
|
MenuEntryBase<String> sortMenuItem() {
|
||||||
|
final isOptFixed = isOptionFixed(sortAbTagsOption);
|
||||||
return MenuEntrySwitch<String>(
|
return MenuEntrySwitch<String>(
|
||||||
switchType: SwitchType.scheckbox,
|
switchType: SwitchType.scheckbox,
|
||||||
text: translate('Sort tags'),
|
text: translate('Sort tags'),
|
||||||
@@ -261,20 +378,52 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
return shouldSortTags();
|
return shouldSortTags();
|
||||||
},
|
},
|
||||||
setter: (bool v) async {
|
setter: (bool v) async {
|
||||||
bind.mainSetLocalOption(key: sortAbTagsOption, value: v ? 'Y' : '');
|
bind.mainSetLocalOption(
|
||||||
|
key: sortAbTagsOption, value: v ? 'Y' : defaultOptionNo);
|
||||||
gFFI.abModel.sortTags.value = v;
|
gFFI.abModel.sortTags.value = v;
|
||||||
},
|
},
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
|
enabled: (!isOptFixed).obs,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MenuEntryBase<String> filterMenuItem() {
|
||||||
|
final isOptFixed = isOptionFixed(filterAbTagOption);
|
||||||
|
return MenuEntrySwitch<String>(
|
||||||
|
switchType: SwitchType.scheckbox,
|
||||||
|
text: translate('Filter by intersection'),
|
||||||
|
getter: () async {
|
||||||
|
return filterAbTagByIntersection();
|
||||||
|
},
|
||||||
|
setter: (bool v) async {
|
||||||
|
bind.mainSetLocalOption(
|
||||||
|
key: filterAbTagOption, value: v ? 'Y' : defaultOptionNo);
|
||||||
|
gFFI.abModel.filterByIntersection.value = v;
|
||||||
|
},
|
||||||
|
dismissOnClicked: true,
|
||||||
|
enabled: (!isOptFixed).obs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showMenu(RelativeRect pos) {
|
void _showMenu(RelativeRect pos) {
|
||||||
|
final canWrite = gFFI.abModel.current.canWrite();
|
||||||
final items = [
|
final items = [
|
||||||
getEntry(translate("Add ID"), abAddId),
|
if (canWrite) getEntry(translate("Add ID"), addIdToCurrentAb),
|
||||||
getEntry(translate("Add Tag"), abAddTag),
|
if (canWrite) getEntry(translate("Add Tag"), abAddTag),
|
||||||
getEntry(translate("Unselect all tags"), gFFI.abModel.unsetSelectedTags),
|
getEntry(translate("Unselect all tags"), gFFI.abModel.unsetSelectedTags),
|
||||||
sortMenuItem(),
|
sortMenuItem(),
|
||||||
syncMenuItem(),
|
if (canWrite) syncMenuItem(),
|
||||||
|
filterMenuItem(),
|
||||||
|
if (!gFFI.abModel.legacyMode.value && canWrite)
|
||||||
|
MenuEntryDivider<String>(),
|
||||||
|
if (!gFFI.abModel.legacyMode.value && canWrite)
|
||||||
|
getEntry(translate("ab_web_console_tip"), () async {
|
||||||
|
final url = await bind.mainGetApiServer();
|
||||||
|
if (await canLaunchUrlString(url)) {
|
||||||
|
launchUrlString(url);
|
||||||
|
}
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
mod_menu.showMenu(
|
mod_menu.showMenu(
|
||||||
@@ -293,17 +442,20 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void abAddId() async {
|
void addIdToCurrentAb() async {
|
||||||
if (gFFI.abModel.isFull(true)) {
|
if (gFFI.abModel.isCurrentAbFull(true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var isInProgress = false;
|
var isInProgress = false;
|
||||||
|
var passwordVisible = false;
|
||||||
IDTextEditingController idController = IDTextEditingController(text: '');
|
IDTextEditingController idController = IDTextEditingController(text: '');
|
||||||
TextEditingController aliasController = TextEditingController(text: '');
|
TextEditingController aliasController = TextEditingController(text: '');
|
||||||
final tags = List.of(gFFI.abModel.tags);
|
TextEditingController passwordController = TextEditingController(text: '');
|
||||||
|
final tags = List.of(gFFI.abModel.currentAbTags);
|
||||||
var selectedTag = List<dynamic>.empty(growable: true).obs;
|
var selectedTag = List<dynamic>.empty(growable: true).obs;
|
||||||
final style = TextStyle(fontSize: 14.0);
|
final style = TextStyle(fontSize: 14.0);
|
||||||
String? errorMsg;
|
String? errorMsg;
|
||||||
|
final isCurrentAbShared = !gFFI.abModel.current.isPersonal();
|
||||||
|
|
||||||
gFFI.dialogManager.show((setState, close, context) {
|
gFFI.dialogManager.show((setState, close, context) {
|
||||||
submit() async {
|
submit() async {
|
||||||
@@ -315,22 +467,50 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
if (id.isEmpty) {
|
if (id.isEmpty) {
|
||||||
// pass
|
// pass
|
||||||
} else {
|
} else {
|
||||||
if (gFFI.abModel.idContainBy(id)) {
|
if (gFFI.abModel.idContainByCurrent(id)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isInProgress = false;
|
isInProgress = false;
|
||||||
errorMsg = translate('ID already exists');
|
errorMsg = translate('ID already exists');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gFFI.abModel.addId(id, aliasController.text.trim(), selectedTag);
|
var password = '';
|
||||||
gFFI.abModel.pushAb();
|
if (isCurrentAbShared) {
|
||||||
this.setState(() {});
|
password = passwordController.text;
|
||||||
|
}
|
||||||
|
String? errMsg2 = await gFFI.abModel.addIdToCurrent(
|
||||||
|
id, aliasController.text.trim(), password, selectedTag);
|
||||||
|
if (errMsg2 != null) {
|
||||||
|
setState(() {
|
||||||
|
isInProgress = false;
|
||||||
|
errorMsg = errMsg2;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
// final currentPeers
|
// final currentPeers
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
double marginBottom = 4;
|
double marginBottom = 4;
|
||||||
|
|
||||||
|
row({required Widget lable, required Widget input}) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
!isMobile
|
||||||
|
? ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(minWidth: 100),
|
||||||
|
child: lable.marginOnly(right: 10))
|
||||||
|
: SizedBox.shrink(),
|
||||||
|
Expanded(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(minWidth: 200),
|
||||||
|
child: input),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).marginOnly(bottom: !isMobile ? 8 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
return CustomAlertDialog(
|
return CustomAlertDialog(
|
||||||
title: Text(translate("Add ID")),
|
title: Text(translate("Add ID")),
|
||||||
content: Column(
|
content: Column(
|
||||||
@@ -338,66 +518,103 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Align(
|
row(
|
||||||
alignment: Alignment.centerLeft,
|
lable: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
Text(
|
||||||
Text(
|
'*',
|
||||||
'*',
|
style: TextStyle(color: Colors.red, fontSize: 14),
|
||||||
style: TextStyle(color: Colors.red, fontSize: 14),
|
),
|
||||||
),
|
Text(
|
||||||
Text(
|
'ID',
|
||||||
'ID',
|
style: style,
|
||||||
style: style,
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
input: TextField(
|
||||||
).marginOnly(bottom: marginBottom),
|
controller: idController,
|
||||||
TextField(
|
inputFormatters: [IDTextInputFormatter()],
|
||||||
controller: idController,
|
decoration: InputDecoration(
|
||||||
inputFormatters: [IDTextInputFormatter()],
|
labelText: !isMobile ? null : translate('ID'),
|
||||||
decoration: InputDecoration(errorText: errorMsg),
|
errorText: errorMsg,
|
||||||
),
|
errorMaxLines: 5),
|
||||||
Align(
|
)),
|
||||||
alignment: Alignment.centerLeft,
|
row(
|
||||||
child: Text(
|
lable: Text(
|
||||||
translate('Alias'),
|
translate('Alias'),
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
).marginOnly(top: 8, bottom: marginBottom),
|
input: TextField(
|
||||||
TextField(
|
controller: aliasController,
|
||||||
controller: aliasController,
|
decoration: InputDecoration(
|
||||||
|
labelText: !isMobile ? null : translate('Alias'),
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
Align(
|
if (isCurrentAbShared)
|
||||||
alignment: Alignment.centerLeft,
|
row(
|
||||||
child: Text(
|
lable: Text(
|
||||||
translate('Tags'),
|
translate('Password'),
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
).marginOnly(top: 8, bottom: marginBottom),
|
input: TextField(
|
||||||
Align(
|
controller: passwordController,
|
||||||
alignment: Alignment.centerLeft,
|
obscureText: !passwordVisible,
|
||||||
child: Wrap(
|
decoration: InputDecoration(
|
||||||
children: tags
|
labelText: !isMobile ? null : translate('Password'),
|
||||||
.map((e) => AddressBookTag(
|
suffixIcon: IconButton(
|
||||||
name: e,
|
icon: Icon(
|
||||||
tags: selectedTag,
|
passwordVisible
|
||||||
onTap: () {
|
? Icons.visibility
|
||||||
if (selectedTag.contains(e)) {
|
: Icons.visibility_off,
|
||||||
selectedTag.remove(e);
|
color: MyTheme.lightTheme.primaryColor),
|
||||||
} else {
|
onPressed: () {
|
||||||
selectedTag.add(e);
|
setState(() {
|
||||||
}
|
passwordVisible = !passwordVisible;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
showActionMenu: false))
|
),
|
||||||
.toList(growable: false),
|
),
|
||||||
|
)),
|
||||||
|
if (gFFI.abModel.currentAbTags.isNotEmpty)
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
translate('Tags'),
|
||||||
|
style: style,
|
||||||
|
),
|
||||||
|
).marginOnly(top: 8, bottom: marginBottom),
|
||||||
|
if (gFFI.abModel.currentAbTags.isNotEmpty)
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
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),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4.0,
|
height: 4.0,
|
||||||
),
|
),
|
||||||
|
if (!gFFI.abModel.current.isPersonal())
|
||||||
|
Row(children: [
|
||||||
|
Icon(Icons.info, color: Colors.amber).marginOnly(right: 4),
|
||||||
|
Text(
|
||||||
|
translate('share_warning_tip'),
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
)
|
||||||
|
]).marginSymmetric(vertical: 10),
|
||||||
// NOT use Offstage to wrap LinearProgressIndicator
|
// NOT use Offstage to wrap LinearProgressIndicator
|
||||||
if (isInProgress) const LinearProgressIndicator(),
|
if (isInProgress) const LinearProgressIndicator(),
|
||||||
],
|
],
|
||||||
@@ -429,10 +646,7 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
} else {
|
} else {
|
||||||
final tags = field.trim().split(RegExp(r"[\s,;\n]+"));
|
final tags = field.trim().split(RegExp(r"[\s,;\n]+"));
|
||||||
field = tags.join(',');
|
field = tags.join(',');
|
||||||
for (final tag in tags) {
|
gFFI.abModel.addTags(tags);
|
||||||
gFFI.abModel.addTag(tag);
|
|
||||||
}
|
|
||||||
gFFI.abModel.pushAb();
|
|
||||||
// final currentPeers
|
// final currentPeers
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
@@ -513,7 +727,7 @@ class AddressBookTag extends StatelessWidget {
|
|||||||
child: Obx(() => Container(
|
child: Obx(() => Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: tags.contains(name)
|
color: tags.contains(name)
|
||||||
? str2color2(name, 0xFF)
|
? gFFI.abModel.getCurrentAbTagColor(name)
|
||||||
: Theme.of(context).colorScheme.background,
|
: Theme.of(context).colorScheme.background,
|
||||||
borderRadius: BorderRadius.circular(4)),
|
borderRadius: BorderRadius.circular(4)),
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
|
margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
|
||||||
@@ -528,7 +742,7 @@ class AddressBookTag extends StatelessWidget {
|
|||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: tags.contains(name)
|
color: tags.contains(name)
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: str2color2(name)),
|
: gFFI.abModel.getCurrentAbTagColor(name)),
|
||||||
).marginOnly(right: radius / 2),
|
).marginOnly(right: radius / 2),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(name,
|
child: Text(name,
|
||||||
@@ -552,7 +766,8 @@ class AddressBookTag extends StatelessWidget {
|
|||||||
if (newName == null || newName.isEmpty) {
|
if (newName == null || newName.isEmpty) {
|
||||||
return translate('Can not be empty');
|
return translate('Can not be empty');
|
||||||
}
|
}
|
||||||
if (newName != name && gFFI.abModel.tags.contains(newName)) {
|
if (newName != name &&
|
||||||
|
gFFI.abModel.currentAbTags.contains(newName)) {
|
||||||
return translate('Already exists');
|
return translate('Already exists');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -560,7 +775,6 @@ class AddressBookTag extends StatelessWidget {
|
|||||||
onSubmit: (String newName) {
|
onSubmit: (String newName) {
|
||||||
if (name != newName) {
|
if (name != newName) {
|
||||||
gFFI.abModel.renameTag(name, newName);
|
gFFI.abModel.renameTag(name, newName);
|
||||||
gFFI.abModel.pushAb();
|
|
||||||
}
|
}
|
||||||
Future.delayed(Duration.zero, () => Get.back());
|
Future.delayed(Duration.zero, () => Get.back());
|
||||||
},
|
},
|
||||||
@@ -568,9 +782,31 @@ class AddressBookTag extends StatelessWidget {
|
|||||||
Future.delayed(Duration.zero, () => Get.back());
|
Future.delayed(Duration.zero, () => Get.back());
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
getEntry(translate(translate('Change Color')), () async {
|
||||||
|
final model = gFFI.abModel;
|
||||||
|
Color oldColor = model.getCurrentAbTagColor(name);
|
||||||
|
Color newColor = await showColorPickerDialog(
|
||||||
|
context,
|
||||||
|
oldColor,
|
||||||
|
pickersEnabled: {
|
||||||
|
ColorPickerType.accent: false,
|
||||||
|
ColorPickerType.wheel: true,
|
||||||
|
},
|
||||||
|
pickerTypeLabels: {
|
||||||
|
ColorPickerType.primary: translate("Primary Color"),
|
||||||
|
ColorPickerType.wheel: translate("HSV Color"),
|
||||||
|
},
|
||||||
|
actionButtons: ColorPickerActionButtons(
|
||||||
|
dialogOkButtonLabel: translate("OK"),
|
||||||
|
dialogCancelButtonLabel: translate("Cancel")),
|
||||||
|
showColorCode: true,
|
||||||
|
);
|
||||||
|
if (oldColor != newColor) {
|
||||||
|
model.setTagColor(name, newColor);
|
||||||
|
}
|
||||||
|
}),
|
||||||
getEntry(translate("Delete"), () {
|
getEntry(translate("Delete"), () {
|
||||||
gFFI.abModel.deleteTag(name);
|
gFFI.abModel.deleteTag(name);
|
||||||
gFFI.abModel.pushAb();
|
|
||||||
Future.delayed(Duration.zero, () => Get.back());
|
Future.delayed(Duration.zero, () => Get.back());
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|||||||
56
flutter/lib/common/widgets/audio_input.dart
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hbb/common.dart';
|
||||||
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||||||
|
|
||||||
|
typedef AudioINputSetDevice = void Function(String device);
|
||||||
|
typedef AudioInputBuilder = Widget Function(
|
||||||
|
List<String> devices, String currentDevice, AudioINputSetDevice setDevice);
|
||||||
|
|
||||||
|
class AudioInput extends StatelessWidget {
|
||||||
|
final AudioInputBuilder builder;
|
||||||
|
|
||||||
|
const AudioInput({Key? key, required this.builder}) : super(key: key);
|
||||||
|
|
||||||
|
static String getDefault() {
|
||||||
|
if (isWindows) return translate('System Sound');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> getValue() async {
|
||||||
|
String device = await bind.mainGetOption(key: 'audio-input');
|
||||||
|
if (device.isNotEmpty) {
|
||||||
|
return device;
|
||||||
|
} else {
|
||||||
|
return getDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> setDevice(String device) async {
|
||||||
|
if (device == getDefault()) device = '';
|
||||||
|
await bind.mainSetOption(key: 'audio-input', value: device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, Object>> getDevicesInfo() async {
|
||||||
|
List<String> devices = (await bind.mainGetSoundInputs()).toList();
|
||||||
|
if (isWindows) {
|
||||||
|
devices.insert(0, translate('System Sound'));
|
||||||
|
}
|
||||||
|
String current = await getValue();
|
||||||
|
return {'devices': devices, 'current': current};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return futureBuilder(
|
||||||
|
future: getDevicesInfo(),
|
||||||
|
hasData: (data) {
|
||||||
|
String currentDevice = data['current'];
|
||||||
|
List<String> devices = data['devices'] as List<String>;
|
||||||
|
if (devices.isEmpty) {
|
||||||
|
return const Offstage();
|
||||||
|
}
|
||||||
|
return builder(devices, currentDevice, setDevice);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
210
flutter/lib/common/widgets/autocomplete.dart
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||||
|
import '../../../models/platform_model.dart';
|
||||||
|
import 'package:flutter_hbb/models/peer_model.dart';
|
||||||
|
import 'package:flutter_hbb/common.dart';
|
||||||
|
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||||
|
|
||||||
|
Future<List<Peer>> getAllPeers() async {
|
||||||
|
Map<String, dynamic> recentPeers = jsonDecode(bind.mainLoadRecentPeersSync());
|
||||||
|
Map<String, dynamic> lanPeers = jsonDecode(bind.mainLoadLanPeersSync());
|
||||||
|
Map<String, dynamic> combinedPeers = {};
|
||||||
|
|
||||||
|
void mergePeers(Map<String, dynamic> peers) {
|
||||||
|
if (peers.containsKey("peers")) {
|
||||||
|
dynamic peerData = peers["peers"];
|
||||||
|
|
||||||
|
if (peerData is String) {
|
||||||
|
try {
|
||||||
|
peerData = jsonDecode(peerData);
|
||||||
|
} catch (e) {
|
||||||
|
print("Error decoding peers: $e");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peerData is List) {
|
||||||
|
for (var peer in peerData) {
|
||||||
|
if (peer is Map && peer.containsKey("id")) {
|
||||||
|
String id = peer["id"];
|
||||||
|
if (!combinedPeers.containsKey(id)) {
|
||||||
|
combinedPeers[id] = peer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mergePeers(recentPeers);
|
||||||
|
mergePeers(lanPeers);
|
||||||
|
for (var p in gFFI.abModel.allPeers()) {
|
||||||
|
if (!combinedPeers.containsKey(p.id)) {
|
||||||
|
combinedPeers[p.id] = p.toJson();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var p in gFFI.groupModel.peers.map((e) => Peer.copy(e)).toList()) {
|
||||||
|
if (!combinedPeers.containsKey(p.id)) {
|
||||||
|
combinedPeers[p.id] = p.toJson();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Peer> parsedPeers = [];
|
||||||
|
|
||||||
|
for (var peer in combinedPeers.values) {
|
||||||
|
parsedPeers.add(Peer.fromJson(peer));
|
||||||
|
}
|
||||||
|
return parsedPeers;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutocompletePeerTile extends StatefulWidget {
|
||||||
|
final VoidCallback onSelect;
|
||||||
|
final Peer peer;
|
||||||
|
|
||||||
|
const AutocompletePeerTile({
|
||||||
|
Key? key,
|
||||||
|
required this.onSelect,
|
||||||
|
required this.peer,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutocompletePeerTileState createState() => AutocompletePeerTileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutocompletePeerTileState extends State<AutocompletePeerTile> {
|
||||||
|
List _frontN<T>(List list, int n) {
|
||||||
|
if (list.length <= n) {
|
||||||
|
return list;
|
||||||
|
} else {
|
||||||
|
return list.sublist(0, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double tileRadius = 5;
|
||||||
|
final name =
|
||||||
|
'${widget.peer.username}${widget.peer.username.isNotEmpty && widget.peer.hostname.isNotEmpty ? '@' : ''}${widget.peer.hostname}';
|
||||||
|
final greyStyle = TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6));
|
||||||
|
final child = GestureDetector(
|
||||||
|
onTap: () => widget.onSelect(),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 5, right: 5),
|
||||||
|
child: Container(
|
||||||
|
height: 42,
|
||||||
|
margin: EdgeInsets.only(bottom: 5),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: str2color(
|
||||||
|
'${widget.peer.id}${widget.peer.platform}', 0x7f),
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(tileRadius),
|
||||||
|
bottomLeft: Radius.circular(tileRadius),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
width: 42,
|
||||||
|
height: null,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(6),
|
||||||
|
child: getPlatformImage(widget.peer.platform,
|
||||||
|
size: 30))),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(left: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topRight: Radius.circular(tileRadius),
|
||||||
|
bottomRight: Radius.circular(tileRadius),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(top: 2),
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(top: 2),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin:
|
||||||
|
EdgeInsets.only(top: 2),
|
||||||
|
child: Row(children: [
|
||||||
|
getOnline(
|
||||||
|
8, widget.peer.online),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
widget.peer.alias.isEmpty
|
||||||
|
? formatID(
|
||||||
|
widget.peer.id)
|
||||||
|
: widget.peer.alias,
|
||||||
|
overflow:
|
||||||
|
TextOverflow.ellipsis,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleSmall,
|
||||||
|
)),
|
||||||
|
widget.peer.alias.isNotEmpty
|
||||||
|
? Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets
|
||||||
|
.only(
|
||||||
|
left: 5,
|
||||||
|
right: 5),
|
||||||
|
child: Text(
|
||||||
|
"(${widget.peer.id})",
|
||||||
|
style: greyStyle,
|
||||||
|
overflow:
|
||||||
|
TextOverflow
|
||||||
|
.ellipsis,
|
||||||
|
))
|
||||||
|
: Container(),
|
||||||
|
])),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
name,
|
||||||
|
style: greyStyle,
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
overflow:
|
||||||
|
TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)))),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
))));
|
||||||
|
final colors = _frontN(widget.peer.tags, 25)
|
||||||
|
.map((e) => gFFI.abModel.getCurrentAbTagColor(e))
|
||||||
|
.toList();
|
||||||
|
return Tooltip(
|
||||||
|
message: isMobile
|
||||||
|
? ''
|
||||||
|
: widget.peer.tags.isNotEmpty
|
||||||
|
? '${translate('Tags')}: ${widget.peer.tags.join(', ')}'
|
||||||
|
: '',
|
||||||
|
child: Stack(children: [
|
||||||
|
child,
|
||||||
|
if (colors.isNotEmpty)
|
||||||
|
Positioned(
|
||||||
|
top: 5,
|
||||||
|
right: 10,
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: TagPainter(radius: 3, colors: colors),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||