Compare commits
637 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15efd91769 | ||
|
|
28fe132012 | ||
|
|
db93c7b610 | ||
|
|
3bae614d7e | ||
|
|
3e3a452ceb | ||
|
|
4dc11191f0 | ||
|
|
3e626c6390 | ||
|
|
5b44295418 | ||
|
|
95b9059bed | ||
|
|
163a0d9fce | ||
|
|
af84f2cf8c | ||
|
|
9f2e824df2 | ||
|
|
f21efcd476 | ||
|
|
50b52d963b | ||
|
|
61e6c143fa | ||
|
|
60d68cbc8c | ||
|
|
93ed359ed1 | ||
|
|
8bd7efc22e | ||
|
|
07957d93fe | ||
|
|
f91ee27c35 | ||
|
|
d8cc5dc539 | ||
|
|
ed17322983 | ||
|
|
0970b73fe7 | ||
|
|
7cc437309a | ||
|
|
a050d82c8b | ||
|
|
4c5a651b2b | ||
|
|
af17f5bb12 | ||
|
|
670ace1963 | ||
|
|
77cfb81545 | ||
|
|
3d241cc634 | ||
|
|
187f1d3689 | ||
|
|
6ccaf06ab4 | ||
|
|
f289026438 | ||
|
|
de6b0e4c70 | ||
|
|
debb204719 | ||
|
|
f80d5f841c | ||
|
|
38a1968c42 | ||
|
|
b92def0283 | ||
|
|
62343f8cf6 | ||
|
|
fdb091cee6 | ||
|
|
3993e574a8 | ||
|
|
fb36826091 | ||
|
|
84ddce1423 | ||
|
|
f363550351 | ||
|
|
02ab0f0e2a | ||
|
|
5819bc8083 | ||
|
|
311f0cfb7e | ||
|
|
58cb75c38c | ||
|
|
4383b9d398 | ||
|
|
b3ce3ab214 | ||
|
|
ae72432aee | ||
|
|
5a939d6234 | ||
|
|
e6ce947700 | ||
|
|
d24df061df | ||
|
|
1b06ab7981 | ||
|
|
5f4cfc09fe | ||
|
|
1de339da75 | ||
|
|
4f653f2131 | ||
|
|
3148ddcfa3 | ||
|
|
b793d2a140 | ||
|
|
5f16ad13e2 | ||
|
|
ddb503feec | ||
|
|
1bcfbd132d | ||
|
|
9862a6a8ca | ||
|
|
9ef3c9264e | ||
|
|
12c371da84 | ||
|
|
782ead1c1e | ||
|
|
e9f77449f0 | ||
|
|
fd77c4db8b | ||
|
|
d9a8d1c460 | ||
|
|
c5b151471a | ||
|
|
2f843bc458 | ||
|
|
f528520024 | ||
|
|
a92d4c0267 | ||
|
|
acaea1d243 | ||
|
|
c48043a178 | ||
|
|
15f0c1ee72 | ||
|
|
44df1666f4 | ||
|
|
6cbfdbe52c | ||
|
|
75d22ab504 | ||
|
|
0c20841db3 | ||
|
|
b33251d98b | ||
|
|
3ef0652a85 | ||
|
|
2ced3aa961 | ||
|
|
0ecb4255e9 | ||
|
|
f8dea1e135 | ||
|
|
f714d2cb92 | ||
|
|
f3a93afccc | ||
|
|
123fb7261c | ||
|
|
79225fe21d | ||
|
|
062d702877 | ||
|
|
e9e8c1298e | ||
|
|
9b6104c350 | ||
|
|
3db36a16c7 | ||
|
|
b06ee70c38 | ||
|
|
769358b999 | ||
|
|
66058b3134 | ||
|
|
a65b369836 | ||
|
|
5b16ec4ef7 | ||
|
|
3e950833f9 | ||
|
|
4c333453b4 | ||
|
|
3e4787d1a2 | ||
|
|
047f84e9e7 | ||
|
|
eb0245dfe2 | ||
|
|
602fafe779 | ||
|
|
bbe4050b40 | ||
|
|
a25ae6dbb7 | ||
|
|
d89c9dd739 | ||
|
|
9f719672ac | ||
|
|
8962cf6d4f | ||
|
|
ef3ef7d714 | ||
|
|
2c1f0ec259 | ||
|
|
31b19ca0f6 | ||
|
|
4682646d36 | ||
|
|
352a86334f | ||
|
|
6c6732c8d1 | ||
|
|
b5dfcef34f | ||
|
|
fea63cc03e | ||
|
|
39b946b94b | ||
|
|
de6c96a7ac | ||
|
|
2590eebfff | ||
|
|
b63c2c0466 | ||
|
|
dbaeea4e8b | ||
|
|
b120d18014 | ||
|
|
85804ee69c | ||
|
|
2b770b30a8 | ||
|
|
e6d178cb2a | ||
|
|
c2f5b20e83 | ||
|
|
952251be35 | ||
|
|
385fe45d5d | ||
|
|
5db0ea301d | ||
|
|
5dc8c947c9 | ||
|
|
523efba81c | ||
|
|
06dc91f130 | ||
|
|
252955da0a | ||
|
|
bd193c0d3f | ||
|
|
630fe98d31 | ||
|
|
0edc1deed0 | ||
|
|
413113e732 | ||
|
|
26f7044053 | ||
|
|
5a7c4971df | ||
|
|
a397a1a985 | ||
|
|
44e8bdef7b | ||
|
|
6aa5c7baea | ||
|
|
da09545168 | ||
|
|
e07e9a09fa | ||
|
|
49deba5771 | ||
|
|
56947d0648 | ||
|
|
f2c285c141 | ||
|
|
b4b2a42db5 | ||
|
|
3195116fdf | ||
|
|
5df51cfcba | ||
|
|
a6525bf885 | ||
|
|
516618bd5a | ||
|
|
098c0a07a3 | ||
|
|
74fcf91572 | ||
|
|
1fb77054d1 | ||
|
|
c53db4bfc3 | ||
|
|
19909a82cb | ||
|
|
46196d128b | ||
|
|
f32bd15d98 | ||
|
|
ce4cd9ad46 | ||
|
|
d91c41b19c | ||
|
|
b38b8d1771 | ||
|
|
51941f2b73 | ||
|
|
5907e48018 | ||
|
|
8d4d2c9711 | ||
|
|
2c513ac7a8 | ||
|
|
9a17dd70c1 | ||
|
|
72d2db3fcc | ||
|
|
05cff37dd5 | ||
|
|
094d996249 | ||
|
|
c079f87fc6 | ||
|
|
288da1736e | ||
|
|
1160c24ad2 | ||
|
|
b2c8dd7d10 | ||
|
|
59674fe781 | ||
|
|
4b3b9b0558 | ||
|
|
866f8821a5 | ||
|
|
2b4ec9af38 | ||
|
|
6527a7ce31 | ||
|
|
aa9babfb18 | ||
|
|
6e9b8a19f5 | ||
|
|
62515ef59c | ||
|
|
1d3830e0b2 | ||
|
|
b62307310c | ||
|
|
6b2841cd0c | ||
|
|
a5b0e60acc | ||
|
|
c084cf9bfb | ||
|
|
005918aec0 | ||
|
|
5eaf7d5498 | ||
|
|
b3ca9bcd66 | ||
|
|
9aed677d3a | ||
|
|
1b66beb957 | ||
|
|
0e092df064 | ||
|
|
d80dc1c465 | ||
|
|
eed21ff56f | ||
|
|
1471b6bb0b | ||
|
|
f85d43d701 | ||
|
|
73f0a840e9 | ||
|
|
a09e469491 | ||
|
|
1db593c634 | ||
|
|
eb88d746c1 | ||
|
|
f7b5c94136 | ||
|
|
58aa1be7c5 | ||
|
|
426d99e519 | ||
|
|
8dec5d906a | ||
|
|
ae02b5c135 | ||
|
|
fe94119627 | ||
|
|
ee13bd08cb | ||
|
|
6a464ad3e7 | ||
|
|
f0d2a42ee3 | ||
|
|
b18ce51e4c | ||
|
|
535b3826f8 | ||
|
|
f1a884e200 | ||
|
|
072e2246a8 | ||
|
|
2c3ecf654a | ||
|
|
8699136d6d | ||
|
|
35803b7014 | ||
|
|
af358f8f99 | ||
|
|
138183798c | ||
|
|
8b3066cf99 | ||
|
|
91e21f59af | ||
|
|
85144e339f | ||
|
|
dbd9b145ea | ||
|
|
287181622d | ||
|
|
7f76bba866 | ||
|
|
4b791fe86b | ||
|
|
e17a582ae7 | ||
|
|
a271088e9a | ||
|
|
712d686559 | ||
|
|
481dd1b3e2 | ||
|
|
bd435094b6 | ||
|
|
16fa08d952 | ||
|
|
aa89953bf5 | ||
|
|
06cba22ad8 | ||
|
|
5923ce5ebc | ||
|
|
01eac1aec6 | ||
|
|
46189dcd43 | ||
|
|
1d9f304735 | ||
|
|
362b74e6a5 | ||
|
|
ee68e3f01b | ||
|
|
09e2de0390 | ||
|
|
12c9972b24 | ||
|
|
df32f93095 | ||
|
|
70d95b353e | ||
|
|
13eba3b3a6 | ||
|
|
1afdc9e7e3 | ||
|
|
38a113b5fb | ||
|
|
25f478e265 | ||
|
|
6a25662566 | ||
|
|
55af990071 | ||
|
|
927a4bbaa4 | ||
|
|
a101c621ec | ||
|
|
e25338e817 | ||
|
|
ecb1751cf5 | ||
|
|
aa54047d44 | ||
|
|
e02f82ee31 | ||
|
|
e8ff31d8d9 | ||
|
|
072805dd8f | ||
|
|
5626e0f5bc | ||
|
|
9fee7dc787 | ||
|
|
f86d97a96f | ||
|
|
6b0e8efadc | ||
|
|
7dba65c2cc | ||
|
|
497c670a98 | ||
|
|
d77790c6fa | ||
|
|
2c8311a0ff | ||
|
|
7bf5a8eaec | ||
|
|
bdffbc0757 | ||
|
|
c085eaa0a3 | ||
|
|
5580e0b29e | ||
|
|
3b174c6b4b | ||
|
|
d5acdde3c4 | ||
|
|
a1afa2ddee | ||
|
|
66d2c04834 | ||
|
|
81559b6a8f | ||
|
|
3d8c06e726 | ||
|
|
32d30df8a3 | ||
|
|
1b0746df6d | ||
|
|
a0b9a43e15 | ||
|
|
58f770cb6d | ||
|
|
0db624c3c6 | ||
|
|
79718d6ade | ||
|
|
2bcad00193 | ||
|
|
b22893eb54 | ||
|
|
9a8a97dbac | ||
|
|
9d1f05eab4 | ||
|
|
cb74756752 | ||
|
|
2ea00d12f3 | ||
|
|
b59a816a8b | ||
|
|
9363b2e26c | ||
|
|
0932602bbb | ||
|
|
85ad2c0097 | ||
|
|
19916388f2 | ||
|
|
d604107b7f | ||
|
|
f329965b3b | ||
|
|
c4e8c9048d | ||
|
|
da8e1d1183 | ||
|
|
b1bf8462da | ||
|
|
665a288af5 | ||
|
|
ec3e0ccf6d | ||
|
|
ea8e16c418 | ||
|
|
0b8ca66692 | ||
|
|
921b8340f0 | ||
|
|
873be55e78 | ||
|
|
772fa9a4df | ||
|
|
121d9e2c58 | ||
|
|
bca3488748 | ||
|
|
0af6a30347 | ||
|
|
d38d775cc9 | ||
|
|
5fc1151e90 | ||
|
|
737a61a3e9 | ||
|
|
4c8caec6bc | ||
|
|
9cccc9f0cc | ||
|
|
7cfee896b1 | ||
|
|
1dddf5c41a | ||
|
|
dc75776d3f | ||
|
|
018c30b73f | ||
|
|
0d8f776e8d | ||
|
|
df0a8b10d1 | ||
|
|
aeaec5465b | ||
|
|
8f15d65c5b | ||
|
|
7e19403aa9 | ||
|
|
bd18acc6a1 | ||
|
|
7046458db6 | ||
|
|
beab57218c | ||
|
|
46cd27c012 | ||
|
|
18123b2755 | ||
|
|
bbda0f33bd | ||
|
|
1edd364a33 | ||
|
|
89d6acb623 | ||
|
|
ff2f648379 | ||
|
|
0d9cf1cd91 | ||
|
|
40505f7628 | ||
|
|
3dee5372f2 | ||
|
|
6ee5b1014b | ||
|
|
189ba62385 | ||
|
|
b09e7ff2bc | ||
|
|
31492a0af3 | ||
|
|
f3d81252f0 | ||
|
|
e795b85ab8 | ||
|
|
3c4e4677d4 | ||
|
|
9f584da9ab | ||
|
|
a440848584 | ||
|
|
2301aa6425 | ||
|
|
263f2bf4c1 | ||
|
|
59d0c9a7ce | ||
|
|
19432a6362 | ||
|
|
97ec1cd385 | ||
|
|
162d60bbdc | ||
|
|
3bcdc7871d | ||
|
|
1f845a3682 | ||
|
|
a0a97a9451 | ||
|
|
c6261687b3 | ||
|
|
6deb311ecc | ||
|
|
0c6c8d5546 | ||
|
|
4e391c0e56 | ||
|
|
9788aa494a | ||
|
|
4f0cc7ab71 | ||
|
|
0bf9a00af2 | ||
|
|
fa9baced7a | ||
|
|
1f51f41954 | ||
|
|
bc8599315e | ||
|
|
1c49a33651 | ||
|
|
13ab8a74d6 | ||
|
|
51155f105c | ||
|
|
af46aa7c78 | ||
|
|
a7d46753aa | ||
|
|
161f257985 | ||
|
|
223de0ba4a | ||
|
|
2fa9c34e98 | ||
|
|
5d5011e409 | ||
|
|
fd4357bdad | ||
|
|
1a073f9661 | ||
|
|
e73c204d1c | ||
|
|
80cb0b46bc | ||
|
|
680a5f256a | ||
|
|
2b02d04219 | ||
|
|
7a61d73e65 | ||
|
|
972116ee96 | ||
|
|
d780607363 | ||
|
|
236004aef9 | ||
|
|
07bc133096 | ||
|
|
50427ef2d3 | ||
|
|
63eef42ca0 | ||
|
|
8723b195df | ||
|
|
ae86b47268 | ||
|
|
9901a0d770 | ||
|
|
da48607154 | ||
|
|
35f3a80eb1 | ||
|
|
0da1bf7a3b | ||
|
|
c027fca339 | ||
|
|
5ac98f5ef8 | ||
|
|
3cb0cca801 | ||
|
|
b4fd4c76a0 | ||
|
|
ecf19115c6 | ||
|
|
d475936bbb | ||
|
|
c404d69b54 | ||
|
|
6edc9cf7e9 | ||
|
|
71d89284f1 | ||
|
|
39473ba15c | ||
|
|
3f3fa3dc11 | ||
|
|
3f06099d38 | ||
|
|
450cf282aa | ||
|
|
804c452f6d | ||
|
|
c576f62d28 | ||
|
|
73651723dd | ||
|
|
82cc713372 | ||
|
|
6d0788268d | ||
|
|
c183cb6d7a | ||
|
|
3b83db0177 | ||
|
|
03f4dcb687 | ||
|
|
9415daba07 | ||
|
|
553571027d | ||
|
|
273ddda076 | ||
|
|
3c8f08a380 | ||
|
|
b5ac8175dc | ||
|
|
d765a9b6eb | ||
|
|
409afd8eac | ||
|
|
d7640d4c5d | ||
|
|
3828da4864 | ||
|
|
a45f7db85c | ||
|
|
df6a9e9286 | ||
|
|
c516f80dc1 | ||
|
|
0ef2f296f5 | ||
|
|
48597983e2 | ||
|
|
a6a4a057fe | ||
|
|
c7cfc07c9b | ||
|
|
51ad390584 | ||
|
|
b4c7795d25 | ||
|
|
78ef2a0355 | ||
|
|
4530424dec | ||
|
|
3543314ff0 | ||
|
|
4ade18bd31 | ||
|
|
951a899705 | ||
|
|
6d678a2e6e | ||
|
|
8b912e68ee | ||
|
|
8059834e91 | ||
|
|
4349603f51 | ||
|
|
160f254e57 | ||
|
|
45497396d1 | ||
|
|
d041ea6b6a | ||
|
|
a2e601ced0 | ||
|
|
35277ca729 | ||
|
|
f3ffe5d037 | ||
|
|
38866547ec | ||
|
|
f4cd9b3b9f | ||
|
|
e687c3f2ba | ||
|
|
97cbfdea4e | ||
|
|
af97e8aef1 | ||
|
|
2094ecb0ba | ||
|
|
928436eda3 | ||
|
|
5b1a7de921 | ||
|
|
e679f2a1b2 | ||
|
|
9113b376b9 | ||
|
|
9169ec9b81 | ||
|
|
41605aabb7 | ||
|
|
fe56be4ea1 | ||
|
|
e916ef9b45 | ||
|
|
aa51f380b5 | ||
|
|
a9883261da | ||
|
|
314a06d43f | ||
|
|
0992636fa3 | ||
|
|
184b7c9cbb | ||
|
|
47fd128509 | ||
|
|
5f88c09b1c | ||
|
|
525c99c0ae | ||
|
|
46bcdf0adf | ||
|
|
4b2a0d7e4e | ||
|
|
53f2508941 | ||
|
|
cb0ddaf084 | ||
|
|
3dd9b2c694 | ||
|
|
8516b14d4a | ||
|
|
cdc8f43a66 | ||
|
|
ce5cf80f96 | ||
|
|
c7522ccf10 | ||
|
|
f817cb7be5 | ||
|
|
f22acb4bd6 | ||
|
|
26d894e02c | ||
|
|
32f37cd98a | ||
|
|
66bd13d5d5 | ||
|
|
31e294ae4f | ||
|
|
3b771408ae | ||
|
|
e55f19c7e5 | ||
|
|
e24f6ee0e4 | ||
|
|
d1e92391d4 | ||
|
|
c24829f6a4 | ||
|
|
7f9ddb4875 | ||
|
|
c644e3e675 | ||
|
|
a9864c7fb5 | ||
|
|
2d57e47d55 | ||
|
|
377e5a6751 | ||
|
|
c17cc3f601 | ||
|
|
8bfd84fa16 | ||
|
|
629d4c3ee9 | ||
|
|
50284d0eb6 | ||
|
|
6a848513b1 | ||
|
|
5b5d3abd2b | ||
|
|
c06d606164 | ||
|
|
6b6fb66a7d | ||
|
|
80a85f3858 | ||
|
|
ee5222165c | ||
|
|
73367c9698 | ||
|
|
ce370d4575 | ||
|
|
374685eeae | ||
|
|
3453ca1c5b | ||
|
|
650913f1e8 | ||
|
|
07683d2342 | ||
|
|
519ec07af8 | ||
|
|
d356b68c33 | ||
|
|
69f3509c17 | ||
|
|
23d68ac9cc | ||
|
|
d4219bdd3f | ||
|
|
ff396081e1 | ||
|
|
b65df31ff9 | ||
|
|
c88c2c58a5 | ||
|
|
1d72df573a | ||
|
|
0f6001b312 | ||
|
|
f9f33336db | ||
|
|
8ba8322836 | ||
|
|
1142a67f88 | ||
|
|
95eb1d545e | ||
|
|
f234bae2a3 | ||
|
|
5ea6a48ee1 | ||
|
|
e6ac747f5d | ||
|
|
11e637bcb7 | ||
|
|
89935e4f80 | ||
|
|
f1f9ec47be | ||
|
|
ca69e44f99 | ||
|
|
820f5d1bb5 | ||
|
|
ee9ed6386d | ||
|
|
a97ca0b240 | ||
|
|
b5dc15cb9a | ||
|
|
75a41fb028 | ||
|
|
7cf1baec25 | ||
|
|
0763917adf | ||
|
|
2344d7ce51 | ||
|
|
f8724bae66 | ||
|
|
b705c56948 | ||
|
|
60b9fe5809 | ||
|
|
32ea38867a | ||
|
|
dd1044ee3d | ||
|
|
7f4e828567 | ||
|
|
64ec55ba54 | ||
|
|
39fa784540 | ||
|
|
4a20f2fd89 | ||
|
|
1a860399d9 | ||
|
|
502b259b8c | ||
|
|
c010fda0db | ||
|
|
743b9d1d54 | ||
|
|
7506282950 | ||
|
|
2346accccc | ||
|
|
dd69b75c7f | ||
|
|
a71ebaedc3 | ||
|
|
1c85b91f32 | ||
|
|
b130644c47 | ||
|
|
0febf9ef0d | ||
|
|
c1e9a5dcfc | ||
|
|
3ddba35295 | ||
|
|
2aede4a341 | ||
|
|
19d6e25f06 | ||
|
|
0b5d3bfddd | ||
|
|
823c2607d9 | ||
|
|
d8bbac3096 | ||
|
|
8af2b7dd66 | ||
|
|
d480f13024 | ||
|
|
40a02cc8e0 | ||
|
|
505c145794 | ||
|
|
79648f2e07 | ||
|
|
02b03328d1 | ||
|
|
34046ecb4b | ||
|
|
6ecba949c2 | ||
|
|
3edadfa475 | ||
|
|
99aab8bc2e | ||
|
|
0c52656a5e | ||
|
|
1e0be54c43 | ||
|
|
bf91c1f9f3 | ||
|
|
3314228b9c | ||
|
|
8c26242af7 | ||
|
|
a75bd355cf | ||
|
|
ea19b936cb | ||
|
|
3dbd5cee3a | ||
|
|
07c312fa33 | ||
|
|
8d15dcb5c9 | ||
|
|
fd9d2bfccc | ||
|
|
3497270b26 | ||
|
|
1f505e1a28 | ||
|
|
96758aba7e | ||
|
|
b538244b6f | ||
|
|
04e7e54556 | ||
|
|
372002dfa5 | ||
|
|
401b21b715 | ||
|
|
e09d1fec5d | ||
|
|
2e8ab3bd43 | ||
|
|
c060038e50 | ||
|
|
d73f84dbb4 | ||
|
|
3e69119df2 | ||
|
|
a9e11e3734 | ||
|
|
ca742146d9 | ||
|
|
de47ab6ad3 | ||
|
|
9cff4a32b2 | ||
|
|
1744ef86bf | ||
|
|
46b3bafeb7 | ||
|
|
76b372f822 | ||
|
|
782485edd0 | ||
|
|
84f444ab55 | ||
|
|
83283d6bda | ||
|
|
4cd3769115 | ||
|
|
c44b4adf60 | ||
|
|
fa59f45184 | ||
|
|
79323dfe58 | ||
|
|
2bfb402c25 | ||
|
|
13e1866820 | ||
|
|
1462aaa30e | ||
|
|
5fbe50b2f9 | ||
|
|
d747596ce1 | ||
|
|
696fff3f5d | ||
|
|
87108d5640 | ||
|
|
8bc0b1cbaf | ||
|
|
b6110ad703 | ||
|
|
f48d2ef40d | ||
|
|
3e4bfe22d8 | ||
|
|
199e2cbaec | ||
|
|
24f9f961b9 | ||
|
|
e9b3f52f0e | ||
|
|
acf0649150 | ||
|
|
df2e35d683 | ||
|
|
19074465a0 | ||
|
|
7d8e143963 | ||
|
|
48c004794c | ||
|
|
b011b3e7a2 | ||
|
|
43daff617a | ||
|
|
ef6a1dc5a4 | ||
|
|
8c5b2d623b | ||
|
|
d3a2c4012c | ||
|
|
67a9089952 |
21
.gitignore
vendored
@@ -1,21 +1,8 @@
|
||||
################################################################################
|
||||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||
################################################################################
|
||||
*.pdb
|
||||
*.xml
|
||||
*.xsd
|
||||
bin/
|
||||
adb/
|
||||
rclone/
|
||||
thumbnails/
|
||||
notes/
|
||||
AndroidSideloader.csproj.user
|
||||
|
||||
.vs/
|
||||
/.vs/AndroidSideloader/v16/.suo
|
||||
/adb/adb.exe
|
||||
installedPackages.json
|
||||
AndroidSideloader.csproj.user
|
||||
AndroidSideloader.csproj.user
|
||||
AndroidSideloader.csproj.user
|
||||
/AndroidSideloader v2.1.exe
|
||||
/crashlog.txt
|
||||
/debuglog.txt
|
||||
bin/
|
||||
packages/
|
||||
244
AdbCommandForm.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class AdbCommandForm : Form
|
||||
{
|
||||
public string Command { get; private set; }
|
||||
public bool ToggleUpdatesClicked { get; private set; }
|
||||
|
||||
public AdbCommandForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
this.ShowIcon = true; // Enable icon
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.lblTitle = new Label();
|
||||
this.txtCommand = new TextBox();
|
||||
this.btnSend = new RoundButton();
|
||||
this.btnToggleUpdates = new RoundButton();
|
||||
this.btnClose = new RoundButton();
|
||||
this.separator = new Panel();
|
||||
this.lblHint = new Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lblTitle
|
||||
//
|
||||
this.lblTitle.AutoSize = true;
|
||||
this.lblTitle.Font = new Font("Segoe UI", 11F, FontStyle.Bold);
|
||||
this.lblTitle.ForeColor = Color.FromArgb(93, 203, 173);
|
||||
this.lblTitle.Location = new Point(20, 15);
|
||||
this.lblTitle.Name = "lblTitle";
|
||||
this.lblTitle.Size = new Size(140, 20);
|
||||
this.lblTitle.TabIndex = 0;
|
||||
this.lblTitle.Text = "Run ADB Command";
|
||||
//
|
||||
// txtCommand
|
||||
//
|
||||
this.txtCommand.BackColor = Color.FromArgb(40, 44, 52);
|
||||
this.txtCommand.BorderStyle = BorderStyle.FixedSingle;
|
||||
this.txtCommand.Font = new Font("Consolas", 10F);
|
||||
this.txtCommand.ForeColor = Color.White;
|
||||
this.txtCommand.Location = new Point(24, 50);
|
||||
this.txtCommand.Name = "txtCommand";
|
||||
this.txtCommand.Size = new Size(292, 23);
|
||||
this.txtCommand.TabIndex = 1;
|
||||
this.txtCommand.KeyPress += TxtCommand_KeyPress;
|
||||
//
|
||||
// lblHint
|
||||
//
|
||||
this.lblHint.AutoSize = true;
|
||||
this.lblHint.Font = new Font("Segoe UI", 8F);
|
||||
this.lblHint.ForeColor = Color.FromArgb(120, 120, 120);
|
||||
this.lblHint.Location = new Point(24, 78);
|
||||
this.lblHint.Name = "lblHint";
|
||||
this.lblHint.Size = new Size(200, 13);
|
||||
this.lblHint.TabIndex = 2;
|
||||
this.lblHint.Text = "Enter command without \"adb\" prefix";
|
||||
//
|
||||
// separator
|
||||
//
|
||||
this.separator.BackColor = Color.FromArgb(50, 55, 65);
|
||||
this.separator.Location = new Point(20, 105);
|
||||
this.separator.Name = "separator";
|
||||
this.separator.Size = new Size(300, 1);
|
||||
this.separator.TabIndex = 3;
|
||||
//
|
||||
// btnSend
|
||||
//
|
||||
this.btnSend.Active1 = Color.FromArgb(113, 223, 193);
|
||||
this.btnSend.Active2 = Color.FromArgb(113, 223, 193);
|
||||
this.btnSend.BackColor = Color.Transparent;
|
||||
this.btnSend.Cursor = Cursors.Hand;
|
||||
this.btnSend.DialogResult = DialogResult.OK;
|
||||
this.btnSend.Disabled1 = Color.FromArgb(32, 35, 45);
|
||||
this.btnSend.Disabled2 = Color.FromArgb(25, 28, 35);
|
||||
this.btnSend.DisabledStrokeColor = Color.FromArgb(50, 55, 65);
|
||||
this.btnSend.Font = new Font("Segoe UI", 9F, FontStyle.Bold);
|
||||
this.btnSend.ForeColor = Color.FromArgb(20, 24, 29);
|
||||
this.btnSend.Inactive1 = Color.FromArgb(93, 203, 173);
|
||||
this.btnSend.Inactive2 = Color.FromArgb(93, 203, 173);
|
||||
this.btnSend.Location = new Point(24, 120);
|
||||
this.btnSend.Name = "btnSend";
|
||||
this.btnSend.Radius = 5;
|
||||
this.btnSend.Size = new Size(140, 30);
|
||||
this.btnSend.Stroke = false;
|
||||
this.btnSend.StrokeColor = Color.FromArgb(93, 203, 173);
|
||||
this.btnSend.TabIndex = 4;
|
||||
this.btnSend.Text = "SEND COMMAND";
|
||||
this.btnSend.Transparency = false;
|
||||
this.btnSend.Click += BtnSend_Click;
|
||||
//
|
||||
// btnToggleUpdates
|
||||
//
|
||||
this.btnToggleUpdates.Active1 = Color.FromArgb(50, 55, 65);
|
||||
this.btnToggleUpdates.Active2 = Color.FromArgb(50, 55, 65);
|
||||
this.btnToggleUpdates.BackColor = Color.Transparent;
|
||||
this.btnToggleUpdates.Cursor = Cursors.Hand;
|
||||
this.btnToggleUpdates.DialogResult = DialogResult.None;
|
||||
this.btnToggleUpdates.Disabled1 = Color.FromArgb(32, 35, 45);
|
||||
this.btnToggleUpdates.Disabled2 = Color.FromArgb(25, 28, 35);
|
||||
this.btnToggleUpdates.DisabledStrokeColor = Color.FromArgb(50, 55, 65);
|
||||
this.btnToggleUpdates.Font = new Font("Segoe UI", 9F);
|
||||
this.btnToggleUpdates.ForeColor = Color.White;
|
||||
this.btnToggleUpdates.Inactive1 = Color.FromArgb(40, 44, 52);
|
||||
this.btnToggleUpdates.Inactive2 = Color.FromArgb(40, 44, 52);
|
||||
this.btnToggleUpdates.Location = new Point(176, 120);
|
||||
this.btnToggleUpdates.Name = "btnToggleUpdates";
|
||||
this.btnToggleUpdates.Radius = 5;
|
||||
this.btnToggleUpdates.Size = new Size(140, 30);
|
||||
this.btnToggleUpdates.Stroke = true;
|
||||
this.btnToggleUpdates.StrokeColor = Color.FromArgb(60, 65, 75);
|
||||
this.btnToggleUpdates.TabIndex = 5;
|
||||
this.btnToggleUpdates.Text = "Toggle OS Updates";
|
||||
this.btnToggleUpdates.Transparency = false;
|
||||
this.btnToggleUpdates.Click += BtnToggleUpdates_Click;
|
||||
//
|
||||
// btnClose
|
||||
//
|
||||
this.btnClose.Active1 = Color.FromArgb(60, 65, 75);
|
||||
this.btnClose.Active2 = Color.FromArgb(60, 65, 75);
|
||||
this.btnClose.BackColor = Color.Transparent;
|
||||
this.btnClose.Cursor = Cursors.Hand;
|
||||
this.btnClose.DialogResult = DialogResult.Cancel;
|
||||
this.btnClose.Disabled1 = Color.FromArgb(32, 35, 45);
|
||||
this.btnClose.Disabled2 = Color.FromArgb(25, 28, 35);
|
||||
this.btnClose.DisabledStrokeColor = Color.FromArgb(50, 55, 65);
|
||||
this.btnClose.Font = new Font("Segoe UI", 9F);
|
||||
this.btnClose.ForeColor = Color.White;
|
||||
this.btnClose.Inactive1 = Color.FromArgb(50, 55, 65);
|
||||
this.btnClose.Inactive2 = Color.FromArgb(50, 55, 65);
|
||||
this.btnClose.Location = new Point(24, 160);
|
||||
this.btnClose.Name = "btnClose";
|
||||
this.btnClose.Radius = 5;
|
||||
this.btnClose.Size = new Size(292, 30);
|
||||
this.btnClose.Stroke = true;
|
||||
this.btnClose.StrokeColor = Color.FromArgb(74, 74, 74);
|
||||
this.btnClose.TabIndex = 6;
|
||||
this.btnClose.Text = "Close";
|
||||
this.btnClose.Transparency = false;
|
||||
this.btnClose.Click += BtnClose_Click;
|
||||
//
|
||||
// AdbCommandForm
|
||||
//
|
||||
this.AcceptButton = this.btnSend;
|
||||
this.AutoScaleDimensions = new SizeF(6F, 13F);
|
||||
this.AutoScaleMode = AutoScaleMode.Font;
|
||||
this.BackColor = Color.FromArgb(20, 24, 29);
|
||||
this.CancelButton = this.btnClose;
|
||||
this.ClientSize = new Size(340, 210);
|
||||
this.Controls.Add(this.lblTitle);
|
||||
this.Controls.Add(this.txtCommand);
|
||||
this.Controls.Add(this.lblHint);
|
||||
this.Controls.Add(this.separator);
|
||||
this.Controls.Add(this.btnSend);
|
||||
this.Controls.Add(this.btnToggleUpdates);
|
||||
this.Controls.Add(this.btnClose);
|
||||
this.FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "AdbCommandForm";
|
||||
this.ShowIcon = false;
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
this.Text = "ADB Command";
|
||||
this.Load += AdbCommandForm_Load;
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
private void AdbCommandForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
txtCommand.Focus();
|
||||
}
|
||||
|
||||
private void TxtCommand_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == (char)Keys.Enter)
|
||||
{
|
||||
e.Handled = true;
|
||||
BtnSend_Click(sender, e);
|
||||
}
|
||||
else if (e.KeyChar == (char)Keys.Escape)
|
||||
{
|
||||
e.Handled = true;
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnSend_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(txtCommand.Text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Command = txtCommand.Text;
|
||||
ToggleUpdatesClicked = false;
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void BtnToggleUpdates_Click(object sender, EventArgs e)
|
||||
{
|
||||
// Check current state and set the appropriate command
|
||||
string adbResult = ADB.RunAdbCommandToString("shell pm list packages -d").Output;
|
||||
bool isUpdatesDisabled = adbResult.Contains("com.oculus.updater");
|
||||
|
||||
if (isUpdatesDisabled)
|
||||
{
|
||||
Command = "shell pm enable com.oculus.updater";
|
||||
}
|
||||
else
|
||||
{
|
||||
Command = "shell pm disable-user --user 0 com.oculus.updater";
|
||||
}
|
||||
|
||||
ToggleUpdatesClicked = true;
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void BtnClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private Label lblTitle;
|
||||
private TextBox txtCommand;
|
||||
private Label lblHint;
|
||||
private Panel separator;
|
||||
private RoundButton btnSend;
|
||||
private RoundButton btnToggleUpdates;
|
||||
private RoundButton btnClose;
|
||||
}
|
||||
}
|
||||
72
AddDefenderExceptions.ps1
Normal file
@@ -0,0 +1,72 @@
|
||||
# Run this script as Administrator
|
||||
# powershell -ExecutionPolicy Bypass -File "C:\RSL\Rookie\AddDefenderExceptions.ps1"
|
||||
|
||||
|
||||
################################################################
|
||||
## Auto Elevate to Admin if not running as admin
|
||||
################################################################
|
||||
|
||||
# Get the ID and security principal of the current user account
|
||||
$WindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal ($WindowsID)
|
||||
|
||||
# Get the security principal for the Administrator role
|
||||
$AdminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
|
||||
# Check to see if we are currently running "as Administrator"
|
||||
if ($WindowsPrincipal.IsInRole($AdminRole)) {
|
||||
# We are running "as Administrator" - so change the title and background color to indicate this
|
||||
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + " (Elevated)"
|
||||
$Host.UI.RawUI.BackgroundColor = "DarkBlue"
|
||||
Clear-Host
|
||||
} else {
|
||||
# We are not running "as Administrator" - so relaunch as administrator
|
||||
# Create a new process object that starts PowerShell
|
||||
$NewProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";
|
||||
# Specify the current script path and name as a parameter
|
||||
$NewProcess.Arguments = $myInvocation.MyCommand.Definition;
|
||||
# Indicate that the process should be elevated
|
||||
$NewProcess.Verb = "runas";
|
||||
# Start the new process
|
||||
[System.Diagnostics.Process]::Start($NewProcess);
|
||||
# Exit from the current unelevated process
|
||||
exit
|
||||
}
|
||||
|
||||
write-host "Run this script from the directory root with which Rookie will be run"
|
||||
start-sleep -s 5
|
||||
|
||||
$paths = @(
|
||||
"$PSScriptRoot", # Replaces 'C:\RSL' with the script's root directory
|
||||
"$PSScriptRoot\rclone",
|
||||
"$PSScriptRoot\Sideloader Launcher.exe",
|
||||
"$PSScriptRoot\AndroidSideloader*.exe",
|
||||
"$PSScriptRoot\rclone\rclone.exe"
|
||||
)
|
||||
|
||||
foreach ($path in $paths) {
|
||||
try {
|
||||
Add-MpPreference -ExclusionPath $Path -ErrorAction Stop
|
||||
Write-Host "Successfully added exclusion for: $path" -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host "Failed to add exclusion for: $path " -ForegroundColor Red
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
Start-Sleep -s 5
|
||||
Pause
|
||||
}
|
||||
}
|
||||
|
||||
# Verify the exclusions
|
||||
Write-Host "`nCurrent exclusions:" -ForegroundColor Cyan
|
||||
$defenderPreferences = Get-MpPreference
|
||||
$paths | ForEach-Object {
|
||||
if ($defenderPreferences.ExclusionPath -contains $_) {
|
||||
Write-Host "$_ is already excluded from Defender."
|
||||
} else {
|
||||
Write-Host "$_ is NOT excluded from Defender."
|
||||
}
|
||||
}
|
||||
Pause
|
||||
|
||||
Start-Sleep -s 5
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="packages\Costura.Fody.4.1.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" />
|
||||
<Import Project="packages\Costura.Fody.5.7.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -49,14 +49,14 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
@@ -136,25 +136,47 @@
|
||||
<ManifestKeyFile>AndroidSideloader_TemporaryKey.pfx</ManifestKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Costura, Version=4.1.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Costura.Fody.4.1.0\lib\net40\Costura.dll</HintPath>
|
||||
<Reference Include="AdvancedSharpAdbClient, Version=3.5.15.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>packages\AdvancedSharpAdbClient.3.5.15\lib\net45\AdvancedSharpAdbClient.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.2478.35, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.2478.35, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.2478.35, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SergeUtils">
|
||||
<HintPath>.\SergeUtils.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System">
|
||||
<HintPath>..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Drawing">
|
||||
<HintPath>..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.Drawing.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
@@ -162,6 +184,24 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ADB.cs" />
|
||||
<Compile Include="AdbCommandForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GalleryView.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ModernListView.cs" />
|
||||
<Compile Include="ModernProgessBar.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ModernQueuePanel.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="RoundButton.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
@@ -175,12 +215,8 @@
|
||||
</Compile>
|
||||
<Compile Include="FlexibleMessageBox.cs" />
|
||||
<Compile Include="RoundedRectangleF.cs" />
|
||||
<Compile Include="Splash.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Splash.Designer.cs">
|
||||
<DependentUpon>Splash.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Sideloader\GetDependencies.cs" />
|
||||
<Compile Include="Models\PublicConfig.cs" />
|
||||
<Compile Include="NewApps.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -188,6 +224,9 @@
|
||||
<Compile Include="NewApps.Designer.cs">
|
||||
<DependentUpon>NewApps.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ToggleSwitch.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Transparenter.cs" />
|
||||
<Compile Include="UpdateForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -204,6 +243,8 @@
|
||||
<Compile Include="Sideloader\ProcessOutput.cs" />
|
||||
<Compile Include="Sideloader\RCLONE.cs" />
|
||||
<Compile Include="Sideloader\Utilities.cs" />
|
||||
<Compile Include="Utilities\DnsHelper.cs" />
|
||||
<Compile Include="Utilities\FileSystemUtilities.cs" />
|
||||
<Compile Include="Utilities\Logger.cs" />
|
||||
<Compile Include="QuestForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -219,13 +260,6 @@
|
||||
<DependentUpon>SettingsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Sideloader.cs" />
|
||||
<Compile Include="spoofer.cs" />
|
||||
<Compile Include="SpoofForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SpoofForm.Designer.cs">
|
||||
<DependentUpon>SpoofForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Updater.cs" />
|
||||
<Compile Include="UsernameForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -236,17 +270,16 @@
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SelectFolder.cs" />
|
||||
<Compile Include="Utilities\SettingsManager.cs" />
|
||||
<Compile Include="Utilities\StringUtilities.cs" />
|
||||
<Compile Include="Utilities\GeneralUtilities.cs" />
|
||||
<Compile Include="Utilities\UpdateGameData.cs" />
|
||||
<Compile Include="Utilities\UploadGame.cs" />
|
||||
<Compile Include="Utilities\Zip.cs" />
|
||||
<Compile Include="Utilities\Metrics.cs" />
|
||||
<EmbeddedResource Include="DonorsListView.resx">
|
||||
<DependentUpon>DonorsListView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Splash.resx">
|
||||
<DependentUpon>Splash.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="NewApps.resx">
|
||||
<DependentUpon>NewApps.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -259,14 +292,9 @@
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="QuestForm.resx">
|
||||
<DependentUpon>QuestForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
@@ -275,13 +303,11 @@
|
||||
<DependentUpon>SettingsForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="SpoofForm.resx">
|
||||
<DependentUpon>SpoofForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UsernameForm.resx">
|
||||
<DependentUpon>UsernameForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<None Include="codenames" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\DataSources\AndroidSideloader.Properties.Resources.datasource" />
|
||||
<None Include="Properties\DataSources\AndroidSideloader.Properties.Settings.datasource" />
|
||||
@@ -297,6 +323,12 @@
|
||||
<None Include="Rookie Offline.cmd">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="CleanupInstall.cmd">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="AddDefenderExceptions.ps1">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="version" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -306,12 +338,7 @@
|
||||
<Content Include="changelog.txt" />
|
||||
<Content Include="icon.ico" />
|
||||
<Content Include="ChangelogHistory.txt" />
|
||||
<Content Include="Resources\pattern_cubes-1_1_1_0-0_0_1__000000_212121.png" />
|
||||
<Content Include="Resources\pattern_herringbone-2_1_3_0-0_90_1__000000_1c1c1c.png" />
|
||||
<Content Include="Resources\splash.jpg" />
|
||||
<None Include="Resources\battery11.png" />
|
||||
<None Include="Resources\battery.png" />
|
||||
<None Include="Resources\battery1.png" />
|
||||
<None Include="Resources\ajax-loader.gif" />
|
||||
<None Include="Resources\SearchGlass.PNG" />
|
||||
</ItemGroup>
|
||||
@@ -329,13 +356,14 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="packages\Fody.6.0.0\build\Fody.targets" Condition="Exists('packages\Fody.6.0.0\build\Fody.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\Fody.6.0.0\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.6.0.0\build\Fody.targets'))" />
|
||||
<Error Condition="!Exists('packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.4.1.0\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('packages\Fody.6.8.1\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.6.8.1\build\Fody.targets'))" />
|
||||
<Error Condition="!Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.5.7.0\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.5.7.0\build\Costura.Fody.targets'))" />
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>
|
||||
@@ -345,4 +373,7 @@
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets" Condition="Exists('packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="packages\Fody.6.8.1\build\Fody.targets" Condition="Exists('packages\Fody.6.8.1\build\Fody.targets')" />
|
||||
<Import Project="packages\Costura.Fody.5.7.0\build\Costura.Fody.targets" Condition="Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" />
|
||||
</Project>
|
||||
519
App.config
@@ -1,252 +1,267 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<section name="AndroidSideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
<section name="AndroidADB.Sideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
|
||||
</startup>
|
||||
<userSettings>
|
||||
<AndroidSideloader.Properties.Settings>
|
||||
<setting name="checkForUpdates" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="enableMessageBoxes" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="firstRun" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="deleteAllAfterInstall" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="autoUpdateConfig" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="userJsonOnGameInstall" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CallUpgrade" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="FontStyle" serializeAs="String">
|
||||
<value>Microsoft Sans Serif, 11.25pt</value>
|
||||
</setting>
|
||||
<setting name="BackPicturePath" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="SpoofGames" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="BandwithLimit" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="BigFontStyle" serializeAs="String">
|
||||
<value>Microsoft Sans Serif, 14pt</value>
|
||||
</setting>
|
||||
<setting name="ResignAPKs" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="IPAddress" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="InstalledApps" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="ADBPath" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="QUsett" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="QuChecked" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="QUhz" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="QUres" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="QUy" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="QUx" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="QUname" serializeAs="String">
|
||||
<value>Change Me</value>
|
||||
</setting>
|
||||
<setting name="QUString" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="MainDir" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="QUStringF" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="delsh" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CurrPckg" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="ADBFolder" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="WirelessADB" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CurrentGamename" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="PackageNameToCB" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="EnterKeyInstall" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="DownUpHeld" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CurrentLogPath" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="CurrentLogName" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="CurrentCrashPath" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="CurrentCrashName" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="QUturnedon" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="adbdebugwarned" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="nodevicemode" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="BMBFchecked" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="GamesList" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="UploadedGameList" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="GlobalUsername" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="lastTimeShared" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="AutoReinstall" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="NonAppPackages" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="LastLaunch" serializeAs="String">
|
||||
<value>04/20/1969 16:20:00</value>
|
||||
</setting>
|
||||
<setting name="SubmittedUpdates" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="ListUpped" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="LastLaunch2" serializeAs="String">
|
||||
<value>04/20/1969 16:20:00</value>
|
||||
</setting>
|
||||
<setting name="Wired" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="FontColor" serializeAs="String">
|
||||
<value>White</value>
|
||||
</setting>
|
||||
<setting name="ComboBoxColor" serializeAs="String">
|
||||
<value>50, 50, 50</value>
|
||||
</setting>
|
||||
<setting name="SubButtonColor" serializeAs="String">
|
||||
<value>40, 40, 40</value>
|
||||
</setting>
|
||||
<setting name="TextBoxColor" serializeAs="String">
|
||||
<value>29, 29, 29</value>
|
||||
</setting>
|
||||
<setting name="ButtonColor" serializeAs="String">
|
||||
<value>50, 50, 50</value>
|
||||
</setting>
|
||||
<setting name="BackColor" serializeAs="String">
|
||||
<value>50, 50, 50</value>
|
||||
</setting>
|
||||
<setting name="AppPackages" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
</AndroidSideloader.Properties.Settings>
|
||||
<AndroidADB.Sideloader.Properties.Settings>
|
||||
<setting name="checkForUpdates" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="enableMessageBoxes" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="logRclone" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="firstRun" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="deleteAllAfterInstall" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="autoUpdateConfig" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="userJsonOnGameInstall" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="CallUpgrade" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="BackColor" serializeAs="String">
|
||||
<value>45, 45, 45</value>
|
||||
</setting>
|
||||
<setting name="PanelColor" serializeAs="String">
|
||||
<value>ActiveCaptionText</value>
|
||||
</setting>
|
||||
<setting name="ButtonColor" serializeAs="String">
|
||||
<value>ActiveCaptionText</value>
|
||||
</setting>
|
||||
<setting name="SubButtonColor" serializeAs="String">
|
||||
<value>64, 64, 64</value>
|
||||
</setting>
|
||||
<setting name="TextBoxColor" serializeAs="String">
|
||||
<value>45, 45, 45</value>
|
||||
</setting>
|
||||
<setting name="ComboBoxColor" serializeAs="String">
|
||||
<value>45, 45, 45</value>
|
||||
</setting>
|
||||
<setting name="FontColor" serializeAs="String">
|
||||
<value>White</value>
|
||||
</setting>
|
||||
<setting name="FontStyle" serializeAs="String">
|
||||
<value>Microsoft Sans Serif, 11.25pt</value>
|
||||
</setting>
|
||||
<setting name="BackPicturePath" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="SpoofGames" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
</AndroidADB.Sideloader.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<section name="AndroidSideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
<section name="AndroidADB.Sideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
|
||||
</startup>
|
||||
<userSettings>
|
||||
<AndroidSideloader.Properties.Settings>
|
||||
<setting name="checkForUpdates" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="enableMessageBoxes" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="firstRun" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="deleteAllAfterInstall" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="autoUpdateConfig" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="userJsonOnGameInstall" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CallUpgrade" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="FontStyle" serializeAs="String">
|
||||
<value>Microsoft Sans Serif, 10pt</value>
|
||||
</setting>
|
||||
<setting name="BackPicturePath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="SpoofGames" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="BigFontStyle" serializeAs="String">
|
||||
<value>Microsoft Sans Serif, 14pt</value>
|
||||
</setting>
|
||||
<setting name="ResignAPKs" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="IPAddress" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="InstalledApps" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ADBPath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="MainDir" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="delsh" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CurrPckg" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ADBFolder" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="WirelessADB" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CurrentGamename" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="PackageNameToCB" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="DownUpHeld" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CurrentLogPath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="CurrentLogName" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="CurrentCrashPath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="CurrentCrashName" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="adbdebugwarned" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="nodevicemode" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="BMBFchecked" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="GamesList" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="UploadedGameList" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="GlobalUsername" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="lastTimeShared" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="AutoReinstall" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="NonAppPackages" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="LastLaunch" serializeAs="String">
|
||||
<value>04/20/1969 16:20:00</value>
|
||||
</setting>
|
||||
<setting name="SubmittedUpdates" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ListUpped" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="LastLaunch2" serializeAs="String">
|
||||
<value>04/20/1969 16:20:00</value>
|
||||
</setting>
|
||||
<setting name="Wired" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="FontColor" serializeAs="String">
|
||||
<value>White</value>
|
||||
</setting>
|
||||
<setting name="ComboBoxColor" serializeAs="String">
|
||||
<value>25, 25, 25</value>
|
||||
</setting>
|
||||
<setting name="SubButtonColor" serializeAs="String">
|
||||
<value>42, 45, 58</value>
|
||||
</setting>
|
||||
<setting name="TextBoxColor" serializeAs="String">
|
||||
<value>25, 25, 25</value>
|
||||
</setting>
|
||||
<setting name="ButtonColor" serializeAs="String">
|
||||
<value>32, 35, 45</value>
|
||||
</setting>
|
||||
<setting name="BackColor" serializeAs="String">
|
||||
<value>31, 34, 42</value>
|
||||
</setting>
|
||||
<setting name="AppPackages" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="TrailersOn" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="downloadDir" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="customDownloadDir" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="customBackupDir" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="backupDir" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="singleThreadMode" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="virtualFilesystemCompatibility" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="UpdateSettings" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="UUID" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="createPubMirrorFile" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="useDownloadedFiles" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="bandwidthLimit" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="useProxy" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="proxyAddress" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="proxyPort" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="selectedMirror" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
</AndroidSideloader.Properties.Settings>
|
||||
<AndroidADB.Sideloader.Properties.Settings>
|
||||
<setting name="checkForUpdates" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="enableMessageBoxes" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="logRclone" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="firstRun" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="deleteAllAfterInstall" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="autoUpdateConfig" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="singleThreadMode" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="userJsonOnGameInstall" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="CallUpgrade" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="BackColor" serializeAs="String">
|
||||
<value>45, 45, 45</value>
|
||||
</setting>
|
||||
<setting name="PanelColor" serializeAs="String">
|
||||
<value>ActiveCaptionText</value>
|
||||
</setting>
|
||||
<setting name="ButtonColor" serializeAs="String">
|
||||
<value>ActiveCaptionText</value>
|
||||
</setting>
|
||||
<setting name="SubButtonColor" serializeAs="String">
|
||||
<value>64, 64, 64</value>
|
||||
</setting>
|
||||
<setting name="TextBoxColor" serializeAs="String">
|
||||
<value>45, 45, 45</value>
|
||||
</setting>
|
||||
<setting name="ComboBoxColor" serializeAs="String">
|
||||
<value>45, 45, 45</value>
|
||||
</setting>
|
||||
<setting name="FontColor" serializeAs="String">
|
||||
<value>White</value>
|
||||
</setting>
|
||||
<setting name="FontStyle" serializeAs="String">
|
||||
<value>Microsoft Sans Serif, 11.25pt</value>
|
||||
</setting>
|
||||
<setting name="BackPicturePath" serializeAs="String">
|
||||
<value/>
|
||||
</setting>
|
||||
<setting name="SpoofGames" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
</AndroidADB.Sideloader.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
|
||||
@@ -1,4 +1,299 @@
|
||||
RSL 2.14
|
||||
RSL 3.0
|
||||
|
||||
Major Rookie overhaul with modernized UI, significant performance improvements and upgraded UX.
|
||||
|
||||
- Added high-performance Gallery View with search, filters, sorting, favorites, hover animations, smooth scrolling and uninstall buttons
|
||||
- Toggle seamlessly between List and Gallery views with your preference remembered across launches
|
||||
- Complete UI redesign with new dark theme, modernized components and subtle animations throughout
|
||||
- Refined navigation, layouts, sizing and color consistency across the entire application
|
||||
- Added uninstall buttons directly in List and Gallery views for quicker app management
|
||||
- Improved startup performance through overhaul of initialization logic, removal of splash screen, parallelized async loading, batched version retrieval, optimized metadata extraction and game list initialization
|
||||
- Instant list filtering through caching and streamlined filter logic (INSTALLED / UPDATE AVAILABLE / NEWER THAN LIST)
|
||||
- Improved search speed and responsiveness
|
||||
- Fixed and improved trailer handling with faster trailer loading
|
||||
- Fixed multiple startup issues including connection errors and zombie ADB instances
|
||||
- Added local blacklist support allowing users to permanently suppress donation prompts for specific apps
|
||||
- Reduced application size by removal of now unused assets
|
||||
|
||||
RSL 2.34
|
||||
|
||||
- Feature: Allow users to favorite games (right click on game)
|
||||
- Fix: Release Notes not showing with trailers enabled
|
||||
- Fix: Correct Discord Invite link on connection error
|
||||
|
||||
RSL 2.33
|
||||
|
||||
- Feature: Allow users to cancel backups
|
||||
- QoL: Lower ADB Version
|
||||
- QoL: Revert Add saving the ColumnWidths, Window Sizes/Position
|
||||
|
||||
RSL 2.32
|
||||
|
||||
- Feature: Allow switching between Public and Private configs
|
||||
- Feature: Switch to Offline Mode when unable to connect
|
||||
- Feature: Save window position and column sizes
|
||||
- Fix: An issue that caused the VIP mirror to fail
|
||||
- Fix: Make video window flexible
|
||||
- Fix: Issue when saving Settings file
|
||||
- Fix: Change Label position to avoid overlapping Queue/Notes windows
|
||||
- Chore: Bump aapt/aapt2/adb to latest
|
||||
- Chore: Bump 7z to 24.09
|
||||
- Chore: Add AddDefenderExceptions.ps1
|
||||
|
||||
RSL 2.31.1
|
||||
|
||||
- Fix: Filtering when Adult Content is shown
|
||||
|
||||
RSL 2.31
|
||||
|
||||
- Feature: Preserve download.config during rclone update
|
||||
- Feature: Added toggle to hide Adult Content
|
||||
- Fix: Changed settings configuration to settings.json
|
||||
- Fix: Always create debuglog on first-launch
|
||||
- Fix: Fixed numeric sorting
|
||||
- Fix: Wrap ADB commands to prevent crash
|
||||
- Fix: Update CleanupInstall to use UserProfile instead of Username
|
||||
- Fix: Fix to OBB pushing when Dragging and Dropping
|
||||
- Fix: Do not show ShowPrcOutput messages when "Enable Message Boxes" is disabled
|
||||
- Fix: Add safeguard to prevent deletion of current directory
|
||||
- Fix: Case insensitive package matching
|
||||
- Chore: Add build batch
|
||||
- Chore: Bump rclone to 1.68.2 (from 1.67.0)
|
||||
|
||||
RSL 2.30
|
||||
|
||||
- Feature: Added Download Metrics
|
||||
-- Upon downloading a game, Rookie will attempt to log the download count with our server
|
||||
-- No additional data is collected except for the Package Name and VersionCode of the Game being downloaded
|
||||
- Feature: Added Downloads column to Gamelist
|
||||
-- Downloads counts are updated nightly
|
||||
- Feature: Added "Send Command" button to ADB Commands prompt (Enter still works)
|
||||
- Feature: Small changes to how the Upload Mirror works
|
||||
-- Rookie can now verify game uploads are successful
|
||||
- Feature: Add Cleanup Install script
|
||||
- Feature: Added additional Splashes to indicate loading status
|
||||
- Feature: Added setting to supress Re-Download prompt
|
||||
- Feature: Added "Disable Checking for New Apps" argument (for Testers sanity)
|
||||
- Feature: Added Bandwidth Limiter to Settings
|
||||
- Fix: Fixes for using Sponsored Mirrors
|
||||
-- Eliminated downloading of vrp.download.config from the wiki
|
||||
-- Fixed issue where Rookie would check for the mirror before it was loaded in
|
||||
- Fix: Add quotes around all ADB path commands
|
||||
- Fix: Public Mirror label not displaying
|
||||
- Fix: Allow spaces when setting username
|
||||
- Fix: Prevent Rookie from constantly prompting for the Public Config
|
||||
- Fix: Fixed issue where the Game List doesn't copy/export properly
|
||||
- Fix: Fixed issue where dropping an entire folder doesn't read the install.txt
|
||||
- Chore: Remove random mirror picker (no longer used)
|
||||
- Chore: Changed unable to connect message
|
||||
- Chore: Remove Offline Mode popup
|
||||
- Chore: Remove unused dependencies
|
||||
- Chore: Rename random assets
|
||||
- Chore: Bump rclone to 1.67.0 (from 1.66.0)
|
||||
|
||||
RSL 2.29
|
||||
|
||||
- Feature: Prompt to keep temporary files and allow resuming of downloads
|
||||
- Feature: Fixed progress bar jump-back
|
||||
- Feature: Added part tracking during download
|
||||
- Fix: Change UUID calculation. No longer uses system details (caused virus flags)
|
||||
- Fix: Added rclone fallback download
|
||||
- Fix: Additional connect/startup troubleshooting steps
|
||||
- Chore: Bump rclone to 1.66.0
|
||||
|
||||
RSL 2.29.1
|
||||
- Fix: Correct initilization sequence to prevent crashes
|
||||
- Chore: bump package dependencies
|
||||
- Chore: Fix initial GUI name
|
||||
|
||||
RSL 2.29.2
|
||||
- Fix: Fix for failed uploads using new rclone version
|
||||
- Fix: Changes to initilization order to prevent crashes and display splash
|
||||
|
||||
|
||||
RSL 2.28
|
||||
|
||||
- Feature: Added ADB-Backup Support. Now supports creation and restoration of .AB backups
|
||||
- Feature: Added OS-Updates toggle to ADB-Command window (Click to toggle on/off)
|
||||
- Feature: Allow ADB Commands with or without prefix
|
||||
- Fix: Left-Navigation UI Reorganization
|
||||
- Fix: 7zip crash, empty device list crash
|
||||
- Fix: Update settings after version update
|
||||
- Fix: Crashlog naming
|
||||
- Fix: Disable searchbar until Rookie is fully loaded
|
||||
- Chore: Add public mirror as a default to Git-downloads
|
||||
- Chore: Readme Updates
|
||||
- Chore: Code Cleanup / Beautification
|
||||
- Chore: Change from _adb dependency files to dependencies.7z file
|
||||
- Chore: Remove unused files
|
||||
- Chore: Default to Single-Thread Mode
|
||||
|
||||
RSL 2.27.2
|
||||
|
||||
- Feature: Searchbar can now also search release names
|
||||
- Feature: Rookie will now download 64 bit 7zip binaries for faster extractions (when possible)
|
||||
- Fix: 7zip error handler
|
||||
- Fix: Crash when downloading without enough space
|
||||
- Fix: Rookie will no longer deny game donations.
|
||||
- Chore: Cleanup code
|
||||
|
||||
RSL 2.26
|
||||
|
||||
- Feature: Top right update labels will now show the amount of games per state
|
||||
- Feature: Open Download Dir and Run ADB Commands added to left sidebar
|
||||
- Feature: Toggle sideloading button
|
||||
- Feature: Show progress of extraction
|
||||
- Fix: Crash when failing to write to the StoredIP.txt
|
||||
- Fix: Drag and drop + Copy OBB for Quest 3 users
|
||||
- Fix: Properly kill off WebView2 instances
|
||||
- Fix: Added parents to dialogs
|
||||
- Fix: GUI freezing on launch
|
||||
- Fix: No Device Mode output
|
||||
- Chore: Make missing space message more user-friendly
|
||||
- Chore: Remove QU Settings
|
||||
|
||||
RSL 2.25.1
|
||||
|
||||
- Fix: Device not authorized prompt showing up after authorization.
|
||||
|
||||
RSL 2.25
|
||||
|
||||
- Fix: Fix to unauthorized device bug
|
||||
- Chore: Update Wiki URL
|
||||
|
||||
|
||||
RSL 2.24
|
||||
|
||||
- Feature: Added "Open Download" and "Open Backup" Directory buttons to Settings Menu
|
||||
- Fix: OBB Pushes for Quest 3 Devices
|
||||
- Fix: Crash when attempting to backup
|
||||
- Fix: Searchbar Anchoring when resizing
|
||||
- Fix: Remove instances where OBBs are pushed multiple times
|
||||
- Fix: Additional Logging and Startup Optimizations
|
||||
|
||||
RSL 2.23
|
||||
|
||||
- Fix: Rookie should now only prompt for newer versions of all games
|
||||
- Fix: Crash when attempting to delete invalid directories or files
|
||||
- Feature: Enable Maximize Button
|
||||
|
||||
RSL 2.22
|
||||
|
||||
- Fix: Crash on failed extractions.
|
||||
- Fix: Trailers controls not functioning properly.
|
||||
- Fix: No Device Mode having the wrong output message.
|
||||
- Chore: Remove ADB.WakeDevice() due to being non-functional.
|
||||
- Chore: Make changeTitlebarToDevice less prone to crashes and more robust.
|
||||
|
||||
RSL 2.21
|
||||
|
||||
- Feature: Search now shows all results found
|
||||
- Feature: Add --no-rclone-updating launch flag
|
||||
- Feature: Add lime-green color to various after download jobs
|
||||
- Feature: Update Sideloader Launcher to check for Rookie
|
||||
- Feature: Add the ability to download into virtual filesystems (Settings)
|
||||
- Feature: Add stacktrace & innerexception to crashlog
|
||||
- Feature: Add CallerInfo to debuglog
|
||||
- Feature: Rookie will now tell the user when there's a running RCLONE Job
|
||||
- Fix: Rookie will no longer repeat "All tasks finished." in No Device Mode
|
||||
- Fix: Rookie should no longer delete the entire OBB/Data folder when uninstalling a game
|
||||
- Fix: Rookie should no longer freeze on the OBB Comparison
|
||||
- Fix: The free disclaimer on launch is no longer broken
|
||||
- Fix: Use new process for every ADB command
|
||||
- Fix: Do not delete game files on an OBB Mismatch anymore
|
||||
- Fix: Change all hardcoded C:/ paths to dynamically grab the system drive for further compatability
|
||||
- Fix: Rookie should now function on 32 Bit again
|
||||
- Fix: Fix crash on failed extraction
|
||||
- Chore: Update quota message to be up to date
|
||||
- Chore: Code rewrites for logging system, obb comparison, updater
|
||||
- Chore: Several redundant code removals
|
||||
- Chore: Change Install w/ Enter Key to Download w/ Enter Key
|
||||
- Chore: Several code cleanups & optimizations
|
||||
~ Chax
|
||||
|
||||
RSL 2.20
|
||||
|
||||
- Feature: Added manual IP on Wireless ADB
|
||||
- Feature: Rookie will now delete old OBB Folders before pushing new obb folders
|
||||
- Feature: Add Single-Thread mode in settings (For users with download issues using multiple threads)
|
||||
- Fix: Device Storage display
|
||||
- Fix: Games that come with install.txt will now check for a device to avoid freezes
|
||||
- Fix: "No Device Mode" checkbox can't have "Delete after Download and Install" enabled at the same time anymore
|
||||
- Fix: Removing Queue Items should no longer ever crash Rookie
|
||||
- Fix: Rookie will no longer reload the gamelist if you have filtered it
|
||||
- Fix: Check if the rclone we are killing is ours
|
||||
- Fix: Put zip extraction into a thread to avoid freezing the UI
|
||||
- Fix: Filters should no longer cause crashes.
|
||||
- Chore: Update RCLONE to 1.62.2
|
||||
- Chore: Cleaning up the code for the Trailers, progress bar, dropdown categories, redundant internet checks, and other code cleanup
|
||||
- Chore: Other UI and message box display cleanup
|
||||
- Chore: Optimize the code for getting the thumbnail paths
|
||||
- Chore: Log Levels added to Debuglog
|
||||
|
||||
- Thank you to Chax for the new features and fixes!
|
||||
~ fenopy
|
||||
|
||||
RSL 2.19
|
||||
|
||||
- Feature: Added streaming Game Trailers (enable in Settings)
|
||||
- Feature: Added custom Download Directories
|
||||
- Feature: Added custom Backup Directories
|
||||
- Feature: Added Game Filtering (click on the Colored-Labels in the Top-Right)
|
||||
- Feature: When uninstalling games, Rookie will now ask if you want to back up save data
|
||||
- Feature: "No Device Mode" now automatically disables "Delete after Download and Install"
|
||||
- Feature: Offline Mode now has the ability to donate new games/updates
|
||||
- Fix: OBBs will no longer be attempted to push in "No Device Mode"
|
||||
- Fix: Comparing OBB sizes will no longer error during "No Device Mode"
|
||||
- Fix: Comparing OBB Sizes will no longer state "Input string was not in a correct format", it will now properly tell the user what is wrong
|
||||
- Fix: The GitHub Error when starting up will now show the actual URL it tries to access
|
||||
- Fix: Added a check to make Rookie not attempt to get available space when no devices are connected
|
||||
- Removed Bandwidth Limit settings
|
||||
|
||||
- Thank you to Chax for the new features!
|
||||
- Thank you to JP for the Trailers framework!
|
||||
~ fenopy
|
||||
|
||||
RSL 2.18
|
||||
|
||||
- Moving Rookie onto a different Directory than C: will not break Pull App To Desktop anymore
|
||||
- Rookie should now tell the user why it couldnt get the Rclone/ADB etc. Files
|
||||
- Dialogs will should now no longer hide behind Rookie.
|
||||
- ADB was updated to the latest version.
|
||||
|
||||
~ Chax & fenopy
|
||||
|
||||
RSL 2.17
|
||||
|
||||
- Various bugfixes
|
||||
|
||||
~SytheZN
|
||||
~fenopy
|
||||
|
||||
RSL 2.16
|
||||
|
||||
- Fix misleading error message when not enough disk space
|
||||
- Fix downloads silently failing in some cases
|
||||
- Fix failure to detect failed extraction when archive corrupt
|
||||
- Fix UI issues when resizing main form
|
||||
- Various code cleanups
|
||||
|
||||
~SytheZN
|
||||
~fenopy
|
||||
|
||||
RSL 2.15
|
||||
|
||||
- Massive UI Changes:
|
||||
- Rounded buttons
|
||||
- Added version Number at Bottom Left
|
||||
- Changed fonts to some extend
|
||||
- Added background pattern to category buttons and MainForm background
|
||||
- Added an animation when opening/closing category
|
||||
- Overall darker theme
|
||||
- New splash
|
||||
|
||||
~Chax
|
||||
|
||||
RSL 2.14
|
||||
|
||||
- Added upload config for easier config management
|
||||
- Improved upload logic to handle failures better
|
||||
|
||||
26
CleanupInstall.cmd
Normal file
@@ -0,0 +1,26 @@
|
||||
@echo off
|
||||
|
||||
echo Killing AndroidSideloader processes...
|
||||
taskkill /F /FI "IMAGENAME eq AndroidSideloader*" /T
|
||||
|
||||
echo Killing adb.exe processes...
|
||||
taskkill /F /FI "IMAGENAME eq adb.exe" /T
|
||||
|
||||
|
||||
set "folderPath=%userprofile%\AppData\Local\Rookie.WTF\"
|
||||
echo Deleting contents of %folderPath%...
|
||||
for /D %%i in ("%folderPath%\*") do (
|
||||
rd /s /q "%%i"
|
||||
)
|
||||
del /q "%folderPath%\*.*"
|
||||
|
||||
|
||||
set "folderPath=%userprofile%\AppData\Local\Rookie.AndroidSideloader\"
|
||||
echo Deleting contents of %folderPath%...
|
||||
for /D %%i in ("%folderPath%\*") do (
|
||||
rd /s /q "%%i"
|
||||
)
|
||||
del /q "%folderPath%\*.*"
|
||||
|
||||
echo Cleanup complete.
|
||||
pause
|
||||
212
ColumnSort.cs
@@ -1,129 +1,165 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// This class is an implementation of the 'IComparer' interface.
|
||||
/// A custom comparer for sorting ListView columns, implementing the 'IComparer' interface.
|
||||
/// </summary>
|
||||
public class ListViewColumnSorter : IComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the column to be sorted
|
||||
/// Case-insensitive comparer object used for comparing strings.
|
||||
/// </summary>
|
||||
private int ColumnToSort;
|
||||
private readonly CaseInsensitiveComparer ObjectCompare;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the order in which to sort (i.e. 'Ascending').
|
||||
/// </summary>
|
||||
private SortOrder OrderOfSort;
|
||||
|
||||
/// <summary>
|
||||
/// Case insensitive comparer object
|
||||
/// </summary>
|
||||
private CaseInsensitiveComparer ObjectCompare;
|
||||
|
||||
/// <summary>
|
||||
/// Class constructor. Initializes various elements
|
||||
/// Initializes a new instance of the ListViewColumnSorter class and sets default sorting parameters.
|
||||
/// </summary>
|
||||
public ListViewColumnSorter()
|
||||
{
|
||||
// Initialize the column to '0'
|
||||
ColumnToSort = 0;
|
||||
// Default column index for sorting
|
||||
SortColumn = 0;
|
||||
|
||||
// Initialize the sort order to 'none'
|
||||
OrderOfSort = SortOrder.Ascending;
|
||||
// Default sorting order
|
||||
Order = SortOrder.Ascending;
|
||||
|
||||
// Initialize the CaseInsensitiveComparer object
|
||||
// Initialize the case-insensitive comparer
|
||||
ObjectCompare = new CaseInsensitiveComparer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
|
||||
/// Compares two ListViewItem objects based on the specified column index and sorting order.
|
||||
/// </summary>
|
||||
/// <param name="x">First object to be compared</param>
|
||||
/// <param name="y">Second object to be compared</param>
|
||||
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
|
||||
/// <param name="x">First ListViewItem object to compare.</param>
|
||||
/// <param name="y">Second ListViewItem object to compare.</param>
|
||||
/// <returns>
|
||||
/// A signed integer indicating the relative values of x and y:
|
||||
/// "0" if equal, a negative number if x is less than y, and a positive number if x is greater than y.
|
||||
/// </returns>
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
int compareResult;
|
||||
ListViewItem listviewX, listviewY;
|
||||
ListViewItem listviewX = (ListViewItem)x;
|
||||
ListViewItem listviewY = (ListViewItem)y;
|
||||
|
||||
// Cast the objects to be compared to ListViewItem objects
|
||||
listviewX = (ListViewItem)x;
|
||||
listviewY = (ListViewItem)y;
|
||||
if (ColumnToSort == 5 ) {
|
||||
try
|
||||
// Special handling for column 6 (Popularity ranking)
|
||||
if (SortColumn == 6)
|
||||
{
|
||||
string textX = listviewX.SubItems[SortColumn].Text;
|
||||
string textY = listviewY.SubItems[SortColumn].Text;
|
||||
|
||||
// Extract numeric values from "#1", "#10", etc.
|
||||
// "-" represents unranked and should go to the end
|
||||
int rankX = int.MaxValue; // Default for unranked (-)
|
||||
int rankY = int.MaxValue;
|
||||
|
||||
if (textX.StartsWith("#") && int.TryParse(textX.Substring(1), out int parsedX))
|
||||
{
|
||||
int yNum = int.Parse(cleanNumber(listviewY.SubItems[ColumnToSort].Text));
|
||||
int xNum = int.Parse(cleanNumber(listviewX.SubItems[ColumnToSort].Text));
|
||||
if (xNum == yNum )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if(xNum > yNum && OrderOfSort == SortOrder.Ascending)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
rankX = parsedX;
|
||||
}
|
||||
|
||||
// Compare the two items
|
||||
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
|
||||
if (textY.StartsWith("#") && int.TryParse(textY.Substring(1), out int parsedY))
|
||||
{
|
||||
rankY = parsedY;
|
||||
}
|
||||
|
||||
// Calculate correct return value based on object comparison
|
||||
if (OrderOfSort == SortOrder.Ascending)
|
||||
{
|
||||
// Ascending sort is selected, return normal result of compare operation
|
||||
return compareResult;
|
||||
// Compare the numeric ranks
|
||||
compareResult = rankX.CompareTo(rankY);
|
||||
}
|
||||
else if (OrderOfSort == SortOrder.Descending)
|
||||
// Special handling for column 5 (Size)
|
||||
else if (SortColumn == 5)
|
||||
{
|
||||
// Descending sort is selected, return negative result of compare operation
|
||||
return (-compareResult);
|
||||
string textX = listviewX.SubItems[SortColumn].Text;
|
||||
string textY = listviewY.SubItems[SortColumn].Text;
|
||||
|
||||
double sizeX = ParseSize(textX);
|
||||
double sizeY = ParseSize(textY);
|
||||
|
||||
// Compare the numeric sizes
|
||||
compareResult = sizeX.CompareTo(sizeY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return '0' to indicate they are equal
|
||||
// Default to string comparison for non-numeric columns
|
||||
compareResult = ObjectCompare.Compare(listviewX.SubItems[SortColumn].Text, listviewY.SubItems[SortColumn].Text);
|
||||
}
|
||||
|
||||
// Determine the return value based on the specified sort order
|
||||
if (Order == SortOrder.Ascending)
|
||||
{
|
||||
return compareResult;
|
||||
}
|
||||
else if (Order == SortOrder.Descending)
|
||||
{
|
||||
return -compareResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // Indicate equality
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a numeric value from a string for accurate numeric comparison.
|
||||
/// </summary>
|
||||
/// <param name="text">The string representation of the number.</param>
|
||||
/// <returns>The parsed integer value; returns 0 if parsing fails.</returns>
|
||||
private int ParseNumber(string text)
|
||||
{
|
||||
// Directly attempt to parse the string as an integer
|
||||
return int.TryParse(text, out int result) ? result : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses size strings with units (GB/MB) and converts them to MB for comparison.
|
||||
/// </summary>
|
||||
/// <param name="sizeStr">Size string (e.g., "1.23 GB", "123 MB")</param>
|
||||
/// <returns>Size in MB as a double</returns>
|
||||
private double ParseSize(string sizeStr)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sizeStr))
|
||||
return 0;
|
||||
|
||||
// Remove whitespace
|
||||
sizeStr = sizeStr.Trim();
|
||||
|
||||
// Handle new format: "1.23 GB" or "123 MB"
|
||||
if (sizeStr.EndsWith(" GB", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string numPart = sizeStr.Substring(0, sizeStr.Length - 3).Trim();
|
||||
if (double.TryParse(numPart, System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out double gb))
|
||||
{
|
||||
return gb * 1024.0; // Convert GB to MB for consistent sorting
|
||||
}
|
||||
}
|
||||
else if (sizeStr.EndsWith(" MB", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string numPart = sizeStr.Substring(0, sizeStr.Length - 3).Trim();
|
||||
if (double.TryParse(numPart, System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out double mb))
|
||||
{
|
||||
return mb;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try parsing as raw number
|
||||
if (double.TryParse(sizeStr, System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out double rawMb))
|
||||
{
|
||||
return rawMb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
|
||||
/// Gets or sets the index of the column to be sorted (default is '0').
|
||||
/// </summary>
|
||||
public int SortColumn
|
||||
{
|
||||
set
|
||||
{
|
||||
ColumnToSort = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return ColumnToSort;
|
||||
}
|
||||
}
|
||||
public int SortColumn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
|
||||
/// Gets or sets the order of sorting (Ascending or Descending).
|
||||
/// </summary>
|
||||
public SortOrder Order
|
||||
{
|
||||
set
|
||||
{
|
||||
OrderOfSort = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return OrderOfSort;
|
||||
}
|
||||
}
|
||||
|
||||
private string cleanNumber(string number)
|
||||
{
|
||||
return number.Substring(0);
|
||||
}
|
||||
|
||||
}
|
||||
public SortOrder Order { get; set; }
|
||||
}
|
||||
|
||||
37
Donors.cs
@@ -1,22 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class Donors
|
||||
internal class Donors
|
||||
{
|
||||
public static int GameNameIndex = 0;
|
||||
public static int PackageNameIndex = 1;
|
||||
public static int VersionCodeIndex = 2;
|
||||
public static int UpdateOrNew = 3;
|
||||
/* Game Name
|
||||
* Package Name
|
||||
* Version Code
|
||||
* Update or New app
|
||||
*/
|
||||
/* Game Name
|
||||
* Package Name
|
||||
* Version Code
|
||||
* Update or New app
|
||||
*/
|
||||
public static List<string> newAppProperties = new List<string>();
|
||||
public static List<string> donorGameProperties = new List<string>();
|
||||
|
||||
@@ -26,38 +22,33 @@ namespace AndroidSideloader
|
||||
{
|
||||
donorGameProperties.Clear();
|
||||
donorGames.Clear();
|
||||
if (!MainForm.DonorApps.Equals(""))
|
||||
if (!string.IsNullOrEmpty(MainForm.donorApps))
|
||||
{
|
||||
string[] gameListSplited = MainForm.DonorApps.Split(new[] { '\n' });
|
||||
string[] gameListSplited = MainForm.donorApps.Split('\n');
|
||||
foreach (string game in gameListSplited)
|
||||
{
|
||||
if (game.Length > 1)
|
||||
{
|
||||
string[] splitGame = game.Split(';');
|
||||
donorGames.Add(splitGame);
|
||||
donorGames.Add(game.Split(';'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void initNewApps()
|
||||
{
|
||||
newApps.Clear();
|
||||
if (!DonorsListViewForm.newAppsForList.Equals(""))
|
||||
if (!string.IsNullOrEmpty(DonorsListViewForm.newAppsForList))
|
||||
{
|
||||
string[] newListSplited = DonorsListViewForm.newAppsForList.Split(new[] { '\n' });
|
||||
string[] newListSplited = DonorsListViewForm.newAppsForList.Split('\n');
|
||||
foreach (string game in newListSplited)
|
||||
{
|
||||
if (game.Length > 1)
|
||||
{
|
||||
string[] splitGame = game.Split(';');
|
||||
newApps.Add(splitGame);
|
||||
newApps.Add(game.Split(';'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
285
DonorsListView.Designer.cs
generated
@@ -30,30 +30,148 @@ namespace AndroidSideloader
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.DonationTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.skip_forever = new AndroidSideloader.RoundButton();
|
||||
this.SkipButton = new AndroidSideloader.RoundButton();
|
||||
this.DonateButton = new AndroidSideloader.RoundButton();
|
||||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
this.DonorsListView = new System.Windows.Forms.ListView();
|
||||
this.GameNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.PackageNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.VersionCodeIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.UpdateOrNew = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.SkipButton = new System.Windows.Forms.Button();
|
||||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
this.bothdet = new System.Windows.Forms.Label();
|
||||
this.newdet = new System.Windows.Forms.Label();
|
||||
this.upddet = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.TimerDesc = new System.Windows.Forms.Label();
|
||||
this.DonateButton = new System.Windows.Forms.Button();
|
||||
this.DonationTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.panel1.SuspendLayout();
|
||||
this.panel2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
|
||||
this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
|
||||
this.panel1.Controls.Add(this.skip_forever);
|
||||
this.panel1.Controls.Add(this.SkipButton);
|
||||
this.panel1.Controls.Add(this.DonateButton);
|
||||
this.panel1.Controls.Add(this.panel2);
|
||||
this.panel1.Controls.Add(this.bothdet);
|
||||
this.panel1.Controls.Add(this.newdet);
|
||||
this.panel1.Controls.Add(this.upddet);
|
||||
this.panel1.Controls.Add(this.label2);
|
||||
this.panel1.Controls.Add(this.TimerDesc);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.panel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Padding = new System.Windows.Forms.Padding(16);
|
||||
this.panel1.Size = new System.Drawing.Size(460, 420);
|
||||
this.panel1.TabIndex = 1;
|
||||
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
|
||||
//
|
||||
// skip_forever
|
||||
//
|
||||
this.skip_forever.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
|
||||
this.skip_forever.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
|
||||
this.skip_forever.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.skip_forever.BackColor = System.Drawing.Color.Transparent;
|
||||
this.skip_forever.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.skip_forever.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.skip_forever.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.skip_forever.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
|
||||
this.skip_forever.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.skip_forever.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.skip_forever.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
|
||||
this.skip_forever.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
|
||||
this.skip_forever.Location = new System.Drawing.Point(20, 380);
|
||||
this.skip_forever.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.skip_forever.Name = "skip_forever";
|
||||
this.skip_forever.Radius = 4;
|
||||
this.skip_forever.Size = new System.Drawing.Size(420, 32);
|
||||
this.skip_forever.Stroke = true;
|
||||
this.skip_forever.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.skip_forever.TabIndex = 97;
|
||||
this.skip_forever.Text = "Add to blacklist / Never ask for the selected apps again";
|
||||
this.skip_forever.Transparency = false;
|
||||
this.skip_forever.Click += new System.EventHandler(this.skip_forever_Click);
|
||||
//
|
||||
// SkipButton
|
||||
//
|
||||
this.SkipButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
|
||||
this.SkipButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
|
||||
this.SkipButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.SkipButton.BackColor = System.Drawing.Color.Transparent;
|
||||
this.SkipButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.SkipButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.SkipButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.SkipButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
|
||||
this.SkipButton.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.SkipButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.SkipButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
|
||||
this.SkipButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
|
||||
this.SkipButton.Location = new System.Drawing.Point(20, 326);
|
||||
this.SkipButton.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.SkipButton.Name = "SkipButton";
|
||||
this.SkipButton.Radius = 4;
|
||||
this.SkipButton.Size = new System.Drawing.Size(100, 32);
|
||||
this.SkipButton.Stroke = true;
|
||||
this.SkipButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.SkipButton.TabIndex = 96;
|
||||
this.SkipButton.Text = "Skip";
|
||||
this.SkipButton.Transparency = false;
|
||||
this.SkipButton.Click += new System.EventHandler(this.SkipButton_Click);
|
||||
//
|
||||
// DonateButton
|
||||
//
|
||||
this.DonateButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(140)))), ((int)(((byte)(115)))));
|
||||
this.DonateButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(125)))), ((int)(((byte)(105)))));
|
||||
this.DonateButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.DonateButton.BackColor = System.Drawing.Color.Transparent;
|
||||
this.DonateButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.DonateButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.DonateButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
|
||||
this.DonateButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
|
||||
this.DonateButton.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold);
|
||||
this.DonateButton.ForeColor = System.Drawing.Color.White;
|
||||
this.DonateButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(120)))), ((int)(((byte)(100)))));
|
||||
this.DonateButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(35)))), ((int)(((byte)(100)))), ((int)(((byte)(85)))));
|
||||
this.DonateButton.Location = new System.Drawing.Point(128, 326);
|
||||
this.DonateButton.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.DonateButton.Name = "DonateButton";
|
||||
this.DonateButton.Radius = 4;
|
||||
this.DonateButton.Size = new System.Drawing.Size(312, 32);
|
||||
this.DonateButton.Stroke = true;
|
||||
this.DonateButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(150)))), ((int)(((byte)(125)))));
|
||||
this.DonateButton.TabIndex = 95;
|
||||
this.DonateButton.Text = "Share Selected Apps";
|
||||
this.DonateButton.Transparency = false;
|
||||
this.DonateButton.Click += new System.EventHandler(this.DonateButton_Click);
|
||||
//
|
||||
// panel2
|
||||
//
|
||||
this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
|
||||
this.panel2.Controls.Add(this.DonorsListView);
|
||||
this.panel2.Location = new System.Drawing.Point(20, 70);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Padding = new System.Windows.Forms.Padding(1);
|
||||
this.panel2.Size = new System.Drawing.Size(420, 250);
|
||||
this.panel2.TabIndex = 2;
|
||||
//
|
||||
// DonorsListView
|
||||
//
|
||||
this.DonorsListView.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
|
||||
this.DonorsListView.BackColor = global::AndroidSideloader.Properties.Settings.Default.ComboBoxColor;
|
||||
this.DonorsListView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.DonorsListView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
|
||||
this.DonorsListView.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.DonorsListView.CausesValidation = false;
|
||||
this.DonorsListView.CheckBoxes = true;
|
||||
this.DonorsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
@@ -61,22 +179,17 @@ namespace AndroidSideloader
|
||||
this.PackageNameIndex,
|
||||
this.VersionCodeIndex,
|
||||
this.UpdateOrNew});
|
||||
this.DonorsListView.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "ComboBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.DonorsListView.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.DonorsListView.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.DonorsListView.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
|
||||
this.DonorsListView.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
|
||||
this.DonorsListView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.DonorsListView.Font = new System.Drawing.Font("Segoe UI", 9.5F);
|
||||
this.DonorsListView.ForeColor = System.Drawing.Color.White;
|
||||
this.DonorsListView.FullRowSelect = true;
|
||||
this.DonorsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
|
||||
this.DonorsListView.HideSelection = false;
|
||||
this.DonorsListView.ImeMode = System.Windows.Forms.ImeMode.On;
|
||||
this.DonorsListView.Location = new System.Drawing.Point(6, 6);
|
||||
this.DonorsListView.Location = new System.Drawing.Point(1, 1);
|
||||
this.DonorsListView.MinimumSize = new System.Drawing.Size(100, 100);
|
||||
this.DonorsListView.Name = "DonorsListView";
|
||||
this.DonorsListView.RightToLeftLayout = true;
|
||||
this.DonorsListView.Size = new System.Drawing.Size(419, 219);
|
||||
this.DonorsListView.Size = new System.Drawing.Size(418, 248);
|
||||
this.DonorsListView.TabIndex = 0;
|
||||
this.DonorsListView.TileSize = new System.Drawing.Size(100, 100);
|
||||
this.DonorsListView.UseCompatibleStateImageBehavior = false;
|
||||
this.DonorsListView.View = System.Windows.Forms.View.Details;
|
||||
this.DonorsListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.DonorsListView_ItemChecked);
|
||||
@@ -86,86 +199,38 @@ namespace AndroidSideloader
|
||||
//
|
||||
// GameNameIndex
|
||||
//
|
||||
this.GameNameIndex.Text = "Game Name";
|
||||
this.GameNameIndex.Width = 219;
|
||||
this.GameNameIndex.Text = "App Name";
|
||||
this.GameNameIndex.Width = 220;
|
||||
//
|
||||
// PackageNameIndex
|
||||
//
|
||||
this.PackageNameIndex.DisplayIndex = 2;
|
||||
this.PackageNameIndex.Text = "Packagename";
|
||||
this.PackageNameIndex.Text = "Package";
|
||||
this.PackageNameIndex.Width = 0;
|
||||
//
|
||||
// VersionCodeIndex
|
||||
//
|
||||
this.VersionCodeIndex.DisplayIndex = 3;
|
||||
this.VersionCodeIndex.Text = "Version";
|
||||
this.VersionCodeIndex.Width = 113;
|
||||
this.VersionCodeIndex.Width = 100;
|
||||
//
|
||||
// UpdateOrNew
|
||||
//
|
||||
this.UpdateOrNew.DisplayIndex = 1;
|
||||
this.UpdateOrNew.Text = "Donation Type";
|
||||
this.UpdateOrNew.Width = 85;
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.panel1.BackgroundImage = global::AndroidSideloader.Properties.Resources.pattern_cubes_1_1_1_0_0_0_1__000000_212121;
|
||||
this.panel1.Controls.Add(this.SkipButton);
|
||||
this.panel1.Controls.Add(this.panel2);
|
||||
this.panel1.Controls.Add(this.bothdet);
|
||||
this.panel1.Controls.Add(this.newdet);
|
||||
this.panel1.Controls.Add(this.upddet);
|
||||
this.panel1.Controls.Add(this.label2);
|
||||
this.panel1.Controls.Add(this.TimerDesc);
|
||||
this.panel1.Controls.Add(this.DonateButton);
|
||||
this.panel1.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.panel1.Location = new System.Drawing.Point(-7, -7);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(463, 345);
|
||||
this.panel1.TabIndex = 1;
|
||||
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
|
||||
//
|
||||
// SkipButton
|
||||
//
|
||||
this.SkipButton.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
|
||||
this.SkipButton.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.SkipButton.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.SkipButton.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.SkipButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.SkipButton.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
|
||||
this.SkipButton.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
|
||||
this.SkipButton.Location = new System.Drawing.Point(22, 277);
|
||||
this.SkipButton.Name = "SkipButton";
|
||||
this.SkipButton.Size = new System.Drawing.Size(102, 36);
|
||||
this.SkipButton.TabIndex = 1;
|
||||
this.SkipButton.Text = "Skip";
|
||||
this.SkipButton.UseVisualStyleBackColor = true;
|
||||
this.SkipButton.Click += new System.EventHandler(this.SkipButton_Click);
|
||||
//
|
||||
// panel2
|
||||
//
|
||||
this.panel2.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
|
||||
this.panel2.Controls.Add(this.DonorsListView);
|
||||
this.panel2.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.panel2.Location = new System.Drawing.Point(16, 43);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Size = new System.Drawing.Size(430, 230);
|
||||
this.panel2.TabIndex = 2;
|
||||
this.UpdateOrNew.Text = "Type";
|
||||
this.UpdateOrNew.Width = 80;
|
||||
//
|
||||
// bothdet
|
||||
//
|
||||
this.bothdet.AutoSize = true;
|
||||
this.bothdet.BackColor = System.Drawing.Color.Transparent;
|
||||
this.bothdet.Font = new System.Drawing.Font("Microsoft Sans Serif", 10.25F, System.Drawing.FontStyle.Bold);
|
||||
this.bothdet.Location = new System.Drawing.Point(125, 7);
|
||||
this.bothdet.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.bothdet.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.bothdet.Location = new System.Drawing.Point(20, 15);
|
||||
this.bothdet.Name = "bothdet";
|
||||
this.bothdet.Size = new System.Drawing.Size(213, 17);
|
||||
this.bothdet.Size = new System.Drawing.Size(228, 20);
|
||||
this.bothdet.TabIndex = 3;
|
||||
this.bothdet.Text = "Updates/new apps detected!";
|
||||
this.bothdet.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.bothdet.Text = "Updates && New Apps Available";
|
||||
this.bothdet.Visible = false;
|
||||
this.bothdet.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.bothdet.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
@@ -175,13 +240,13 @@ namespace AndroidSideloader
|
||||
//
|
||||
this.newdet.AutoSize = true;
|
||||
this.newdet.BackColor = System.Drawing.Color.Transparent;
|
||||
this.newdet.Font = new System.Drawing.Font("Microsoft Sans Serif", 10.25F, System.Drawing.FontStyle.Bold);
|
||||
this.newdet.Location = new System.Drawing.Point(120, 7);
|
||||
this.newdet.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.newdet.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.newdet.Location = new System.Drawing.Point(20, 15);
|
||||
this.newdet.Name = "newdet";
|
||||
this.newdet.Size = new System.Drawing.Size(150, 17);
|
||||
this.newdet.Size = new System.Drawing.Size(149, 20);
|
||||
this.newdet.TabIndex = 3;
|
||||
this.newdet.Text = "New apps detected!";
|
||||
this.newdet.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.newdet.Text = "New Apps Available";
|
||||
this.newdet.Visible = false;
|
||||
this.newdet.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.newdet.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
@@ -191,13 +256,13 @@ namespace AndroidSideloader
|
||||
//
|
||||
this.upddet.AutoSize = true;
|
||||
this.upddet.BackColor = System.Drawing.Color.Transparent;
|
||||
this.upddet.Font = new System.Drawing.Font("Microsoft Sans Serif", 10.25F, System.Drawing.FontStyle.Bold);
|
||||
this.upddet.Location = new System.Drawing.Point(120, 7);
|
||||
this.upddet.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.upddet.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.upddet.Location = new System.Drawing.Point(20, 15);
|
||||
this.upddet.Name = "upddet";
|
||||
this.upddet.Size = new System.Drawing.Size(185, 17);
|
||||
this.upddet.Size = new System.Drawing.Size(135, 20);
|
||||
this.upddet.TabIndex = 3;
|
||||
this.upddet.Text = "Game Updates Detected";
|
||||
this.upddet.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.upddet.Text = "Updates Available";
|
||||
this.upddet.Visible = false;
|
||||
this.upddet.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.upddet.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
@@ -207,58 +272,43 @@ namespace AndroidSideloader
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.BackColor = System.Drawing.Color.Transparent;
|
||||
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label2.Location = new System.Drawing.Point(23, 23);
|
||||
this.label2.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||
this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.label2.Location = new System.Drawing.Point(20, 42);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(416, 15);
|
||||
this.label2.Size = new System.Drawing.Size(338, 15);
|
||||
this.label2.TabIndex = 3;
|
||||
this.label2.Text = "All Apps are donated by users! Without them none of this would be possible!";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.label2.Text = "All apps are donated by users! Help the community by sharing.";
|
||||
this.label2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.label2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
this.label2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
|
||||
//
|
||||
// TimerDesc
|
||||
//
|
||||
this.TimerDesc.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.TimerDesc.AutoSize = true;
|
||||
this.TimerDesc.BackColor = System.Drawing.Color.Transparent;
|
||||
this.TimerDesc.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.TimerDesc.Location = new System.Drawing.Point(28, 321);
|
||||
this.TimerDesc.Font = new System.Drawing.Font("Segoe UI", 8F);
|
||||
this.TimerDesc.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(125)))), ((int)(((byte)(135)))));
|
||||
this.TimerDesc.Location = new System.Drawing.Point(79, 362);
|
||||
this.TimerDesc.Name = "TimerDesc";
|
||||
this.TimerDesc.Size = new System.Drawing.Size(406, 13);
|
||||
this.TimerDesc.Size = new System.Drawing.Size(292, 13);
|
||||
this.TimerDesc.TabIndex = 3;
|
||||
this.TimerDesc.Text = "Don\'t share free apps. Rookie will extract/upload apps in background.";
|
||||
this.TimerDesc.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.TimerDesc.Text = "Don\'t share free apps. Upload happens in background.";
|
||||
this.TimerDesc.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
|
||||
this.TimerDesc.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
|
||||
this.TimerDesc.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
|
||||
//
|
||||
// DonateButton
|
||||
//
|
||||
this.DonateButton.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
|
||||
this.DonateButton.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.DonateButton.Enabled = false;
|
||||
this.DonateButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.DonateButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.DonateButton.ForeColor = System.Drawing.Color.White;
|
||||
this.DonateButton.Location = new System.Drawing.Point(130, 277);
|
||||
this.DonateButton.Name = "DonateButton";
|
||||
this.DonateButton.Size = new System.Drawing.Size(311, 36);
|
||||
this.DonateButton.TabIndex = 1;
|
||||
this.DonateButton.Text = "Automatically share selected apps";
|
||||
this.DonateButton.UseVisualStyleBackColor = true;
|
||||
this.DonateButton.Click += new System.EventHandler(this.DonateButton_Click);
|
||||
//
|
||||
// DonorsListViewForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.Gainsboro;
|
||||
this.ClientSize = new System.Drawing.Size(449, 336);
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
|
||||
this.ClientSize = new System.Drawing.Size(460, 420);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.panel1);
|
||||
this.ForeColor = System.Drawing.Color.White;
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.Name = "DonorsListViewForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Load += new System.EventHandler(this.DonorsListViewForm_Load);
|
||||
@@ -276,18 +326,19 @@ namespace AndroidSideloader
|
||||
|
||||
private System.Windows.Forms.ListView DonorsListView;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.Button DonateButton;
|
||||
private System.Windows.Forms.Label TimerDesc;
|
||||
private System.Windows.Forms.ColumnHeader GameNameIndex;
|
||||
private System.Windows.Forms.ColumnHeader PackageNameIndex;
|
||||
private System.Windows.Forms.ColumnHeader VersionCodeIndex;
|
||||
private System.Windows.Forms.ColumnHeader UpdateOrNew;
|
||||
public System.Windows.Forms.Timer DonationTimer;
|
||||
private System.Windows.Forms.Button SkipButton;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label bothdet;
|
||||
private System.Windows.Forms.Label newdet;
|
||||
private System.Windows.Forms.Label upddet;
|
||||
private System.Windows.Forms.Panel panel2;
|
||||
private RoundButton DonateButton;
|
||||
private RoundButton SkipButton;
|
||||
private RoundButton skip_forever;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,69 @@
|
||||
using AndroidSideloader.Utilities;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using Newtonsoft.Json;
|
||||
using SergeUtils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class DonorsListViewForm : Form
|
||||
{
|
||||
// Modern theme colors
|
||||
private static readonly Color BackgroundColor = Color.FromArgb(20, 24, 29);
|
||||
private static readonly Color BorderColor = Color.FromArgb(70, 80, 100);
|
||||
private static readonly Color UpdateHighlightColor = Color.FromArgb(0, 79, 97);
|
||||
|
||||
private bool mouseDown;
|
||||
private Point lastLocation;
|
||||
// Shadow and corner settings
|
||||
private const int CS_DROPSHADOW = 0x00020000;
|
||||
private const int WM_NCLBUTTONDOWN = 0xA1;
|
||||
private const int HT_CAPTION = 0x2;
|
||||
private const int SHADOW_SIZE = 2;
|
||||
private const int CONTENT_RADIUS = 10;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool ReleaseCapture();
|
||||
|
||||
protected override CreateParams CreateParams
|
||||
{
|
||||
get
|
||||
{
|
||||
CreateParams cp = base.CreateParams;
|
||||
cp.ClassStyle |= CS_DROPSHADOW;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
public DonorsListViewForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
|
||||
ApplyModernTheme();
|
||||
CenterToScreen();
|
||||
|
||||
Donors.initDonorGames();
|
||||
List<ListViewItem> DGameList = new List<ListViewItem>();
|
||||
|
||||
var seen = new HashSet<string>();
|
||||
var DGameList = new List<ListViewItem>();
|
||||
|
||||
foreach (string[] release in Donors.donorGames)
|
||||
{
|
||||
ListViewItem DGame = new ListViewItem(release);
|
||||
DGameList.Add(DGame);
|
||||
if (release.Length == 0) continue;
|
||||
string key = release[0];
|
||||
if (seen.Add(key))
|
||||
{
|
||||
DGameList.Add(new ListViewItem(release));
|
||||
}
|
||||
}
|
||||
|
||||
ListViewItem[] arr = DGameList.ToArray();
|
||||
DonorsListView.BeginUpdate();
|
||||
DonorsListView.Items.Clear();
|
||||
@@ -40,27 +71,145 @@ namespace AndroidSideloader
|
||||
DonorsListView.EndUpdate();
|
||||
}
|
||||
|
||||
public static string DonorsLocal = MainForm.DonorApps;
|
||||
private void ApplyModernTheme()
|
||||
{
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
this.BackColor = Color.FromArgb(25, 25, 30);
|
||||
this.Padding = new Padding(5);
|
||||
|
||||
panel1.BackColor = BackgroundColor;
|
||||
panel1.Location = new Point(6, 6);
|
||||
panel1.Size = new Size(this.ClientSize.Width - 12, this.ClientSize.Height - 12);
|
||||
panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
|
||||
this.Paint += Form_Paint;
|
||||
|
||||
// Close button
|
||||
var closeButton = new Button
|
||||
{
|
||||
Text = "✕",
|
||||
Font = new Font("Segoe UI", 9F),
|
||||
ForeColor = Color.White,
|
||||
BackColor = BackgroundColor,
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
Size = new Size(30, 28),
|
||||
Location = new Point(panel1.Width - 35, 5),
|
||||
Cursor = Cursors.Hand,
|
||||
TabStop = false
|
||||
};
|
||||
closeButton.FlatAppearance.BorderSize = 0;
|
||||
closeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(200, 60, 60);
|
||||
closeButton.Click += (s, e) => Close();
|
||||
panel1.Controls.Add(closeButton);
|
||||
closeButton.BringToFront();
|
||||
|
||||
// Enable dragging
|
||||
panel1.MouseDown += TitleArea_MouseDown;
|
||||
foreach (Control ctrl in panel1.Controls)
|
||||
{
|
||||
if (ctrl is Label)
|
||||
{
|
||||
ctrl.MouseDown += TitleArea_MouseDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TitleArea_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
ReleaseCapture();
|
||||
SendMessage(this.Handle, WM_NCLBUTTONDOWN, (IntPtr)HT_CAPTION, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
private void Form_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
int w = this.Width;
|
||||
int h = this.Height;
|
||||
|
||||
// Draw shadow layers
|
||||
for (int i = SHADOW_SIZE; i >= 1; i--)
|
||||
{
|
||||
int alpha = (SHADOW_SIZE - i + 1) * 12;
|
||||
Rectangle shadowRect = new Rectangle(
|
||||
SHADOW_SIZE - i,
|
||||
SHADOW_SIZE - i,
|
||||
w - (SHADOW_SIZE - i) * 2 - 1,
|
||||
h - (SHADOW_SIZE - i) * 2 - 1);
|
||||
|
||||
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 0, 0, 0), 1))
|
||||
using (GraphicsPath shadowPath = CreateRoundedRectPath(shadowRect, CONTENT_RADIUS + i))
|
||||
{
|
||||
e.Graphics.DrawPath(shadowPen, shadowPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw content background
|
||||
Rectangle contentRect = new Rectangle(SHADOW_SIZE, SHADOW_SIZE, w - SHADOW_SIZE * 2, h - SHADOW_SIZE * 2);
|
||||
using (GraphicsPath contentPath = CreateRoundedRectPath(contentRect, CONTENT_RADIUS))
|
||||
{
|
||||
using (SolidBrush bgBrush = new SolidBrush(BackgroundColor))
|
||||
{
|
||||
e.Graphics.FillPath(bgBrush, contentPath);
|
||||
}
|
||||
|
||||
using (Pen borderPen = new Pen(BorderColor, 1f))
|
||||
{
|
||||
e.Graphics.DrawPath(borderPen, contentPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply rounded region
|
||||
using (GraphicsPath regionPath = CreateRoundedRectPath(new Rectangle(0, 0, w, h), CONTENT_RADIUS + SHADOW_SIZE))
|
||||
{
|
||||
this.Region = new Region(regionPath);
|
||||
}
|
||||
}
|
||||
|
||||
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
if (radius <= 0)
|
||||
{
|
||||
path.AddRectangle(rect);
|
||||
return path;
|
||||
}
|
||||
|
||||
int diameter = Math.Min(radius * 2, Math.Min(rect.Width, rect.Height));
|
||||
radius = diameter / 2;
|
||||
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
|
||||
|
||||
path.AddArc(arcRect, 180, 90);
|
||||
arcRect.X = rect.Right - diameter;
|
||||
path.AddArc(arcRect, 270, 90);
|
||||
arcRect.Y = rect.Bottom - diameter;
|
||||
path.AddArc(arcRect, 0, 90);
|
||||
arcRect.X = rect.Left;
|
||||
path.AddArc(arcRect, 90, 90);
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string DonorsLocal = MainForm.donorApps;
|
||||
public static bool ifuploads = false;
|
||||
public static string newAppsForList = "";
|
||||
|
||||
|
||||
private void DonorsListViewForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
MainForm.updatesnotified = true;
|
||||
if (MainForm.updates && MainForm.newapps)
|
||||
bothdet.Visible = true;
|
||||
else if (MainForm.updates && !MainForm.newapps)
|
||||
upddet.Visible = true;
|
||||
else
|
||||
newdet.Visible = true;
|
||||
MainForm.updatesNotified = true;
|
||||
bothdet.Visible = MainForm.updates && MainForm.newapps;
|
||||
upddet.Visible = MainForm.updates && !MainForm.newapps;
|
||||
newdet.Visible = !MainForm.updates;
|
||||
|
||||
foreach (ListViewItem listItem in DonorsListView.Items)
|
||||
{
|
||||
{
|
||||
if (listItem.SubItems[Donors.UpdateOrNew].Text.Contains("Update"))
|
||||
listItem.BackColor = Color.FromArgb(0, 79, 97);
|
||||
listItem.BackColor = UpdateHighlightColor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async void DonateButton_Click(object sender, EventArgs e)
|
||||
@@ -70,102 +219,106 @@ namespace AndroidSideloader
|
||||
bool uncheckednewapps = false;
|
||||
foreach (ListViewItem listItem in DonorsListView.Items)
|
||||
{
|
||||
if (!listItem.Checked)
|
||||
{
|
||||
if (listItem.SubItems[Donors.UpdateOrNew].Text.Contains("New"))
|
||||
{
|
||||
uncheckednewapps = true;
|
||||
newAppsForList += listItem.SubItems[Donors.GameNameIndex].Text + ";" + listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uncheckednewapps)
|
||||
{
|
||||
|
||||
NewApps NewAppForm = new NewApps();
|
||||
NewAppForm.ShowDialog();
|
||||
this.Hide();
|
||||
}
|
||||
else
|
||||
this.Hide();
|
||||
int count = 0;
|
||||
count = DonorsListView.CheckedItems.Count;
|
||||
string[] gamesToUpload;
|
||||
gamesToUpload = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ulong vcode = Convert.ToUInt64(DonorsListView.CheckedItems[i].SubItems[Donors.VersionCodeIndex].Text);
|
||||
if (DonorsListView.CheckedItems[i].SubItems[Donors.UpdateOrNew].Text.Contains("Update"))
|
||||
await Program.form.extractAndPrepareGameToUploadAsync(DonorsListView.CheckedItems[i].SubItems[Donors.GameNameIndex].Text, DonorsListView.CheckedItems[i].SubItems[Donors.PackageNameIndex].Text, vcode, true);
|
||||
else
|
||||
await Program.form.extractAndPrepareGameToUploadAsync(DonorsListView.CheckedItems[i].SubItems[Donors.GameNameIndex].Text, DonorsListView.CheckedItems[i].SubItems[Donors.PackageNameIndex].Text, vcode, false);
|
||||
ifuploads = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifuploads)
|
||||
{
|
||||
MainForm.DoUpload();
|
||||
}
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void DonorsListView_ItemChecked(object sender, ItemCheckedEventArgs e)
|
||||
{
|
||||
if (DonorsListView.CheckedItems.Count == 0)
|
||||
{
|
||||
SkipButton.Enabled = true;
|
||||
DonateButton.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DonateButton.Enabled = true;
|
||||
SkipButton.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SkipButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool uncheckednewapps = false;
|
||||
foreach (ListViewItem listItem in DonorsListView.Items)
|
||||
{
|
||||
if (!listItem.Checked)
|
||||
{
|
||||
if (listItem.SubItems[Donors.UpdateOrNew].Text.Contains("New"))
|
||||
if (!listItem.Checked && listItem.SubItems[Donors.UpdateOrNew].Text.Contains("New"))
|
||||
{
|
||||
uncheckednewapps = true;
|
||||
newAppsForList += listItem.SubItems[Donors.GameNameIndex].Text + ";" + listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (uncheckednewapps)
|
||||
{
|
||||
new NewApps().ShowDialog();
|
||||
Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
for (int i = 0; i < DonorsListView.CheckedItems.Count; i++)
|
||||
{
|
||||
ulong vcode = Convert.ToUInt64(DonorsListView.CheckedItems[i].SubItems[Donors.VersionCodeIndex].Text);
|
||||
bool isUpdate = DonorsListView.CheckedItems[i].SubItems[Donors.UpdateOrNew].Text.Contains("Update");
|
||||
await Program.form.extractAndPrepareGameToUploadAsync(
|
||||
DonorsListView.CheckedItems[i].SubItems[Donors.GameNameIndex].Text,
|
||||
DonorsListView.CheckedItems[i].SubItems[Donors.PackageNameIndex].Text,
|
||||
vcode, isUpdate);
|
||||
ifuploads = true;
|
||||
}
|
||||
}
|
||||
if (uncheckednewapps)
|
||||
|
||||
if (ifuploads) MainForm.doUpload();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void DonorsListView_ItemChecked(object sender, ItemCheckedEventArgs e)
|
||||
{
|
||||
SkipButton.Enabled = DonorsListView.CheckedItems.Count == 0;
|
||||
DonateButton.Enabled = !SkipButton.Enabled;
|
||||
skip_forever.Enabled = DonorsListView.CheckedItems.Count > 0;
|
||||
}
|
||||
|
||||
private void SkipButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach (ListViewItem listItem in DonorsListView.Items)
|
||||
{
|
||||
NewApps NewAppForm = new NewApps();
|
||||
NewAppForm.ShowDialog();
|
||||
if (!listItem.Checked && listItem.SubItems[Donors.UpdateOrNew].Text.Contains("New"))
|
||||
newAppsForList += listItem.SubItems[Donors.GameNameIndex].Text + ";" + listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
|
||||
}
|
||||
this.Close();
|
||||
|
||||
if (!string.IsNullOrEmpty(newAppsForList))
|
||||
new NewApps().ShowDialog();
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private void DonorsListViewForm_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
mouseDown = true;
|
||||
lastLocation = e.Location;
|
||||
}
|
||||
private void DonorsListViewForm_MouseDown(object sender, MouseEventArgs e) => TitleArea_MouseDown(sender, e);
|
||||
private void DonorsListViewForm_MouseMove(object sender, MouseEventArgs e) { }
|
||||
private void DonorsListViewForm_MouseUp(object sender, MouseEventArgs e) { }
|
||||
|
||||
private void DonorsListViewForm_MouseMove(object sender, MouseEventArgs e)
|
||||
private void skip_forever_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (mouseDown)
|
||||
var appsToBlacklist = DonorsListView.CheckedItems.Cast<ListViewItem>()
|
||||
.Select(item => item.SubItems[Donors.PackageNameIndex].Text).ToList();
|
||||
|
||||
if (appsToBlacklist.Count == 0)
|
||||
{
|
||||
this.Location = new Point(
|
||||
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
|
||||
this.Update();
|
||||
MessageBox.Show("No apps selected to blacklist.", "Info", MessageBoxButtons.OK);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void DonorsListViewForm_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
mouseDown = false;
|
||||
if (MessageBox.Show(
|
||||
$"Permanently skip donation requests for {appsToBlacklist.Count} app(s)?",
|
||||
"Confirm Blacklist", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
|
||||
return;
|
||||
|
||||
string blacklistPath = Path.Combine(Environment.CurrentDirectory, "blacklist.json");
|
||||
try
|
||||
{
|
||||
var existingBlacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
if (File.Exists(blacklistPath))
|
||||
{
|
||||
var jsonArray = Newtonsoft.Json.JsonConvert.DeserializeObject<string[]>(File.ReadAllText(blacklistPath));
|
||||
if (jsonArray != null)
|
||||
foreach (string entry in jsonArray.Where(ee => !string.IsNullOrWhiteSpace(ee)))
|
||||
existingBlacklist.Add(entry.Trim());
|
||||
}
|
||||
|
||||
foreach (string pkg in appsToBlacklist) existingBlacklist.Add(pkg);
|
||||
|
||||
File.WriteAllText(blacklistPath, Newtonsoft.Json.JsonConvert.SerializeObject(existingBlacklist.ToArray(), Newtonsoft.Json.Formatting.Indented));
|
||||
Logger.Log($"Added {appsToBlacklist.Count} apps to local blacklist");
|
||||
MessageBox.Show($"{appsToBlacklist.Count} {(appsToBlacklist.Count == 1 ? "app" : "apps")} added to blacklist.",
|
||||
"Success",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Error saving blacklist: {ex.Message}", LogLevel.ERROR);
|
||||
MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1773
GalleryView.cs
Normal file
3183
MainForm.Designer.cs
generated
9860
MainForm.cs
Normal file → Executable file
@@ -117,4 +117,73 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="speedLabel_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>1165, 17</value>
|
||||
</metadata>
|
||||
<metadata name="startsideloadbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>966, 17</value>
|
||||
</metadata>
|
||||
<metadata name="devicesbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>705, 91</value>
|
||||
</metadata>
|
||||
<metadata name="obbcopybutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>526, 91</value>
|
||||
</metadata>
|
||||
<metadata name="backupadbbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>390, 17</value>
|
||||
</metadata>
|
||||
<metadata name="backupbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>355, 91</value>
|
||||
</metadata>
|
||||
<metadata name="restorebutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>187, 91</value>
|
||||
</metadata>
|
||||
<metadata name="getApkButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 91</value>
|
||||
</metadata>
|
||||
<metadata name="uninstallAppButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>1157, 54</value>
|
||||
</metadata>
|
||||
<metadata name="pullAppToDesktopBtn_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>945, 54</value>
|
||||
</metadata>
|
||||
<metadata name="copyBulkObbButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>741, 54</value>
|
||||
</metadata>
|
||||
<metadata name="aboutBtn_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>876, 91</value>
|
||||
</metadata>
|
||||
<metadata name="settingsButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>568, 54</value>
|
||||
</metadata>
|
||||
<metadata name="QuestOptionsButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>223, 54</value>
|
||||
</metadata>
|
||||
<metadata name="btnOpenDownloads_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>764, 17</value>
|
||||
</metadata>
|
||||
<metadata name="btnRunAdbCmd_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>581, 17</value>
|
||||
</metadata>
|
||||
<metadata name="ADBWirelessToggle_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="UpdateGamesButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 54</value>
|
||||
</metadata>
|
||||
<metadata name="listApkButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>1320, 17</value>
|
||||
</metadata>
|
||||
<metadata name="etaLabel_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>428, 54</value>
|
||||
</metadata>
|
||||
<metadata name="favoriteGame.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>1021, 91</value>
|
||||
</metadata>
|
||||
<metadata name="btnViewToggle_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>215, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>113</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -16,10 +16,7 @@ namespace AndroidSideloader.Models
|
||||
public string Password
|
||||
{
|
||||
get => password;
|
||||
set
|
||||
{
|
||||
password = Encoding.UTF8.GetString(Convert.FromBase64String(value));
|
||||
}
|
||||
set => password = Encoding.UTF8.GetString(Convert.FromBase64String(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1308
ModernListView.cs
Normal file
439
ModernProgessBar.cs
Normal file
@@ -0,0 +1,439 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
// A modern progress bar with rounded corners, left-to-right gradient fill,
|
||||
// animated indeterminate mode, and optional status text overlay
|
||||
[Description("Modern Themed Progress Bar")]
|
||||
public class ModernProgressBar : Control
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private float _value;
|
||||
private float _minimum;
|
||||
private float _maximum = 100f;
|
||||
private int _radius = 8;
|
||||
private bool _isIndeterminate;
|
||||
private string _statusText = string.Empty;
|
||||
private string _operationType = string.Empty;
|
||||
|
||||
// Indeterminate animation
|
||||
private readonly Timer _animationTimer;
|
||||
private float _animationOffset;
|
||||
private const float AnimationSpeed = 4f;
|
||||
private const int IndeterminateBlockWidth = 80;
|
||||
|
||||
// Colors
|
||||
private Color _backgroundColor = Color.FromArgb(28, 32, 38);
|
||||
private Color _progressStartColor = Color.FromArgb(120, 220, 190); // lighter accent
|
||||
private Color _progressEndColor = Color.FromArgb(50, 160, 130); // darker accent
|
||||
private Color _indeterminateColor = Color.FromArgb(93, 203, 173); // accent
|
||||
private Color _textColor = Color.FromArgb(230, 230, 230);
|
||||
private Color _textShadowColor = Color.FromArgb(90, 0, 0, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public ModernProgressBar()
|
||||
{
|
||||
SetStyle(
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.ResizeRedraw |
|
||||
ControlStyles.UserPaint |
|
||||
ControlStyles.SupportsTransparentBackColor,
|
||||
true);
|
||||
|
||||
BackColor = Color.Transparent;
|
||||
|
||||
// Size + Font
|
||||
Height = 28;
|
||||
Width = 220;
|
||||
Font = new Font("Segoe UI", 9f, FontStyle.Bold);
|
||||
|
||||
_animationTimer = new Timer { Interval = 16 }; // ~60fps
|
||||
_animationTimer.Tick += AnimationTimer_Tick;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
[Category("Progress")]
|
||||
[Description("The current value of the progress bar.")]
|
||||
public float Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
_value = Math.Max(_minimum, Math.Min(_maximum, value));
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Progress")]
|
||||
[Description("The minimum value of the progress bar.")]
|
||||
public float Minimum
|
||||
{
|
||||
get => _minimum;
|
||||
set
|
||||
{
|
||||
_minimum = value;
|
||||
if (_value < _minimum) _value = _minimum;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Progress")]
|
||||
[Description("The maximum value of the progress bar.")]
|
||||
public float Maximum
|
||||
{
|
||||
get => _maximum;
|
||||
set
|
||||
{
|
||||
_maximum = value;
|
||||
if (_value > _maximum) _value = _maximum;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("The corner radius of the progress bar.")]
|
||||
public int Radius
|
||||
{
|
||||
get => _radius;
|
||||
set
|
||||
{
|
||||
_radius = Math.Max(0, value);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Progress")]
|
||||
[Description("Whether the progress bar shows indeterminate (marquee) progress.")]
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get => _isIndeterminate;
|
||||
set
|
||||
{
|
||||
// If there is no change, do nothing
|
||||
if (_isIndeterminate == value)
|
||||
return;
|
||||
|
||||
_isIndeterminate = value;
|
||||
if (_isIndeterminate)
|
||||
{
|
||||
_animationOffset = -IndeterminateBlockWidth;
|
||||
_animationTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
_animationTimer.Stop();
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Optional status text to display on the progress bar.")]
|
||||
public string StatusText
|
||||
{
|
||||
get => _statusText;
|
||||
set
|
||||
{
|
||||
_statusText = value ?? string.Empty;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Operation type label (e.g., 'Downloading', 'Installing').")]
|
||||
public string OperationType
|
||||
{
|
||||
get => _operationType;
|
||||
set
|
||||
{
|
||||
_operationType = value ?? string.Empty;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Background color of the progress bar track.")]
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get => _backgroundColor;
|
||||
set { _backgroundColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Start color of the progress gradient (left side).")]
|
||||
public Color ProgressStartColor
|
||||
{
|
||||
get => _progressStartColor;
|
||||
set { _progressStartColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("End color of the progress gradient (right side).")]
|
||||
public Color ProgressEndColor
|
||||
{
|
||||
get => _progressEndColor;
|
||||
set { _progressEndColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Color used for indeterminate animation.")]
|
||||
public Color IndeterminateColor
|
||||
{
|
||||
get => _indeterminateColor;
|
||||
set { _indeterminateColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Text color for status overlay.")]
|
||||
public Color TextColor
|
||||
{
|
||||
get => _textColor;
|
||||
set { _textColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
// Gets the progress as a percentage (0-100)
|
||||
public float ProgressPercent =>
|
||||
_maximum > _minimum ? (_value - _minimum) / (_maximum - _minimum) * 100f : 0f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Painting
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
g.Clear(BackColor);
|
||||
|
||||
int w = ClientSize.Width;
|
||||
int h = ClientSize.Height;
|
||||
if (w <= 0 || h <= 0) return;
|
||||
|
||||
var outerRect = new Rectangle(0, 0, w - 1, h - 1);
|
||||
|
||||
// Draw background track
|
||||
using (var path = CreateRoundedPath(outerRect, _radius))
|
||||
using (var bgBrush = new SolidBrush(_backgroundColor))
|
||||
{
|
||||
g.FillPath(bgBrush, path);
|
||||
}
|
||||
|
||||
// Draw progress or indeterminate animation
|
||||
if (_isIndeterminate)
|
||||
{
|
||||
DrawIndeterminate(g, outerRect);
|
||||
}
|
||||
else if (_value > _minimum)
|
||||
{
|
||||
DrawProgress(g, outerRect);
|
||||
}
|
||||
|
||||
// Draw text overlay
|
||||
DrawTextOverlay(g, outerRect);
|
||||
|
||||
base.OnPaint(e);
|
||||
}
|
||||
|
||||
private void DrawProgress(Graphics g, Rectangle outerRect)
|
||||
{
|
||||
float percent = (_maximum > _minimum)
|
||||
? (_value - _minimum) / (_maximum - _minimum)
|
||||
: 0f;
|
||||
|
||||
if (percent <= 0f) return;
|
||||
if (percent > 1f) percent = 1f;
|
||||
|
||||
int progressWidth = (int)Math.Round(outerRect.Width * percent);
|
||||
if (progressWidth <= 0) return;
|
||||
if (progressWidth > outerRect.Width) progressWidth = outerRect.Width;
|
||||
|
||||
using (var outerPath = CreateRoundedPath(outerRect, _radius))
|
||||
{
|
||||
// Clip to progress area inside rounded track
|
||||
Rectangle progressRect = new Rectangle(outerRect.X, outerRect.Y, progressWidth, outerRect.Height);
|
||||
using (var progressClip = new Region(progressRect))
|
||||
using (var trackRegion = new Region(outerPath))
|
||||
{
|
||||
trackRegion.Intersect(progressClip);
|
||||
|
||||
Region prevClip = g.Clip;
|
||||
try
|
||||
{
|
||||
g.SetClip(trackRegion, CombineMode.Replace);
|
||||
|
||||
// Left-to-right gradient, based on accent color
|
||||
using (var gradientBrush = new LinearGradientBrush(
|
||||
progressRect,
|
||||
_progressStartColor,
|
||||
_progressEndColor,
|
||||
LinearGradientMode.Horizontal))
|
||||
{
|
||||
g.FillPath(gradientBrush, outerPath);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.Clip = prevClip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawIndeterminate(Graphics g, Rectangle outerRect)
|
||||
{
|
||||
using (var outerPath = CreateRoundedPath(outerRect, _radius))
|
||||
{
|
||||
Region prevClip = g.Clip;
|
||||
try
|
||||
{
|
||||
g.SetClip(outerPath, CombineMode.Replace);
|
||||
|
||||
int blockWidth = Math.Min(IndeterminateBlockWidth, outerRect.Width);
|
||||
int blockX = (int)_animationOffset;
|
||||
var blockRect = new Rectangle(blockX, outerRect.Y, blockWidth, outerRect.Height);
|
||||
|
||||
// Solid bar with slight left-to-right gradient
|
||||
using (var brush = new LinearGradientBrush(
|
||||
blockRect,
|
||||
ControlPaint.Light(_indeterminateColor, 0.1f),
|
||||
ControlPaint.Dark(_indeterminateColor, 0.1f),
|
||||
LinearGradientMode.Horizontal))
|
||||
{
|
||||
g.FillRectangle(brush, blockRect);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.Clip = prevClip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTextOverlay(Graphics g, Rectangle outerRect)
|
||||
{
|
||||
string displayText = BuildDisplayText();
|
||||
if (string.IsNullOrEmpty(displayText)) return;
|
||||
|
||||
using (var sf = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Center,
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Trimming = StringTrimming.EllipsisCharacter
|
||||
})
|
||||
{
|
||||
// Slight shadow for legibility on accent background
|
||||
var shadowRect = new Rectangle(outerRect.X + 1, outerRect.Y + 1, outerRect.Width, outerRect.Height);
|
||||
using (var shadowBrush = new SolidBrush(_textShadowColor))
|
||||
{
|
||||
g.DrawString(displayText, Font, shadowBrush, shadowRect, sf);
|
||||
}
|
||||
|
||||
using (var textBrush = new SolidBrush(_textColor))
|
||||
{
|
||||
g.DrawString(displayText, Font, textBrush, outerRect, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildDisplayText()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_statusText))
|
||||
{
|
||||
return _statusText;
|
||||
}
|
||||
|
||||
if (_isIndeterminate && !string.IsNullOrEmpty(_operationType))
|
||||
{
|
||||
// E.g. "Downloading..."
|
||||
return _operationType + "...";
|
||||
}
|
||||
|
||||
if (!_isIndeterminate && _value > _minimum)
|
||||
{
|
||||
// Show one decimal place for sub-percent precision
|
||||
string percentText = $"{ProgressPercent:0.0}%";
|
||||
if (!string.IsNullOrEmpty(_operationType))
|
||||
{
|
||||
// E.g. "Downloading · 73.5%"
|
||||
return $"{_operationType} · {percentText}";
|
||||
}
|
||||
return percentText;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private GraphicsPath CreateRoundedPath(Rectangle rect, int radius)
|
||||
{
|
||||
var path = new GraphicsPath();
|
||||
|
||||
if (radius <= 0)
|
||||
{
|
||||
path.AddRectangle(rect);
|
||||
return path;
|
||||
}
|
||||
|
||||
int diameter = radius * 2;
|
||||
diameter = Math.Min(diameter, Math.Min(rect.Width, rect.Height));
|
||||
radius = diameter / 2;
|
||||
|
||||
var arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
|
||||
|
||||
path.AddArc(arcRect, 180, 90);
|
||||
arcRect.X = rect.Right - diameter;
|
||||
path.AddArc(arcRect, 270, 90);
|
||||
arcRect.Y = rect.Bottom - diameter;
|
||||
path.AddArc(arcRect, 0, 90);
|
||||
arcRect.X = rect.Left;
|
||||
path.AddArc(arcRect, 90, 90);
|
||||
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Animation
|
||||
|
||||
private void AnimationTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
_animationOffset += AnimationSpeed;
|
||||
|
||||
if (_animationOffset > ClientSize.Width + IndeterminateBlockWidth)
|
||||
{
|
||||
_animationOffset = -IndeterminateBlockWidth;
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cleanup
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_animationTimer?.Stop();
|
||||
_animationTimer?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
511
ModernQueuePanel.cs
Normal file
@@ -0,0 +1,511 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
// Modern download queue panel with drag-reorder, cancel buttons
|
||||
// and custom scrollbar with auto-scrolling during drag
|
||||
public sealed class ModernQueuePanel : Control
|
||||
{
|
||||
// Layout constants
|
||||
private const int ItemHeight = 28, ItemMargin = 4, ItemRadius = 5;
|
||||
private const int XButtonSize = 18, DragHandleWidth = 20, TextPadding = 6;
|
||||
private const int ScrollbarWidth = 6, ScrollbarWidthHover = 8, ScrollbarMargin = 2;
|
||||
private const int ScrollbarRadius = 3, MinThumbHeight = 20;
|
||||
private const int AutoScrollZoneHeight = 30, AutoScrollSpeed = 3;
|
||||
|
||||
// Color palette
|
||||
private static readonly Color BgColor = Color.FromArgb(24, 26, 30);
|
||||
private static readonly Color ItemBg = Color.FromArgb(32, 36, 44);
|
||||
private static readonly Color ItemHoverBg = Color.FromArgb(42, 46, 54);
|
||||
private static readonly Color ItemDragBg = Color.FromArgb(45, 55, 70);
|
||||
private static readonly Color TextColor = Color.FromArgb(210, 210, 210);
|
||||
private static readonly Color TextDimColor = Color.FromArgb(140, 140, 140);
|
||||
private static readonly Color AccentColor = Color.FromArgb(93, 203, 173);
|
||||
private static readonly Color XButtonBg = Color.FromArgb(55, 60, 70);
|
||||
private static readonly Color XButtonHoverBg = Color.FromArgb(200, 60, 60);
|
||||
private static readonly Color GripColor = Color.FromArgb(70, 75, 85);
|
||||
private static readonly Color ItemDragBorder = Color.FromArgb(55, 65, 80);
|
||||
private static readonly Color ScrollTrackColor = Color.FromArgb(35, 38, 45);
|
||||
private static readonly Color ScrollThumbColor = Color.FromArgb(70, 75, 85);
|
||||
private static readonly Color ScrollThumbHoverColor = Color.FromArgb(90, 95, 105);
|
||||
private static readonly Color ScrollThumbDragColor = Color.FromArgb(110, 115, 125);
|
||||
|
||||
private readonly List<string> _items = new List<string>();
|
||||
private readonly Timer _autoScrollTimer;
|
||||
|
||||
// State tracking
|
||||
private int _hoveredIndex = -1, _dragIndex = -1, _dropIndex = -1, _scrollOffset;
|
||||
private bool _hoveringX, _scrollbarHovered, _scrollbarDragging;
|
||||
private int _scrollDragStartY, _scrollDragStartOffset, _autoScrollDirection;
|
||||
private Rectangle _scrollThumbRect, _scrollTrackRect;
|
||||
|
||||
public event EventHandler<int> ItemRemoved;
|
||||
public event EventHandler<ReorderEventArgs> ItemReordered;
|
||||
|
||||
public ModernQueuePanel()
|
||||
{
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
|
||||
BackColor = BgColor;
|
||||
_autoScrollTimer = new Timer { Interval = 16 }; // ~60 FPS
|
||||
_autoScrollTimer.Tick += (s, e) => HandleAutoScroll();
|
||||
}
|
||||
|
||||
public bool IsDownloading { get; set; }
|
||||
public int Count => _items.Count;
|
||||
private int ContentHeight => _items.Count * (ItemHeight + ItemMargin) + ItemMargin;
|
||||
private int MaxScroll => Math.Max(0, ContentHeight - Height);
|
||||
private bool ScrollbarVisible => ContentHeight > Height;
|
||||
|
||||
public void SetItems(IEnumerable<string> items)
|
||||
{
|
||||
_items.Clear();
|
||||
_items.AddRange(items);
|
||||
ResetState();
|
||||
}
|
||||
|
||||
private void ResetState()
|
||||
{
|
||||
_hoveredIndex = _dragIndex = -1;
|
||||
ClampScroll();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private void ClampScroll() =>
|
||||
_scrollOffset = Math.Max(0, Math.Min(MaxScroll, _scrollOffset));
|
||||
|
||||
// Auto-scroll when dragging near edges
|
||||
private void HandleAutoScroll()
|
||||
{
|
||||
if (_dragIndex < 0 || _autoScrollDirection == 0)
|
||||
{
|
||||
_autoScrollTimer.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
int oldOffset = _scrollOffset;
|
||||
_scrollOffset += _autoScrollDirection * AutoScrollSpeed;
|
||||
ClampScroll();
|
||||
|
||||
if (_scrollOffset != oldOffset)
|
||||
{
|
||||
UpdateDropIndex(PointToClient(MousePosition).Y);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAutoScroll(int mouseY)
|
||||
{
|
||||
if (_dragIndex < 0 || MaxScroll <= 0)
|
||||
{
|
||||
StopAutoScroll();
|
||||
return;
|
||||
}
|
||||
|
||||
_autoScrollDirection = mouseY < AutoScrollZoneHeight && _scrollOffset > 0 ? -1 :
|
||||
mouseY > Height - AutoScrollZoneHeight && _scrollOffset < MaxScroll ? 1 : 0;
|
||||
|
||||
if (_autoScrollDirection != 0 && !_autoScrollTimer.Enabled)
|
||||
_autoScrollTimer.Start();
|
||||
else if (_autoScrollDirection == 0)
|
||||
_autoScrollTimer.Stop();
|
||||
}
|
||||
|
||||
private void StopAutoScroll()
|
||||
{
|
||||
_autoScrollDirection = 0;
|
||||
_autoScrollTimer.Stop();
|
||||
}
|
||||
|
||||
private void UpdateDropIndex(int mouseY) =>
|
||||
_dropIndex = Math.Max(1, Math.Min(_items.Count, (mouseY + _scrollOffset + ItemHeight / 2) / (ItemHeight + ItemMargin)));
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.Clear(BgColor);
|
||||
|
||||
if (_items.Count == 0)
|
||||
{
|
||||
DrawEmptyState(g);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw visible items
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
var rect = GetItemRect(i);
|
||||
if (rect.Bottom >= 0 && rect.Top <= Height)
|
||||
DrawItem(g, i, rect);
|
||||
}
|
||||
|
||||
// Draw drop indicator and scrollbar
|
||||
if (_dragIndex >= 0 && _dropIndex >= 0 && _dropIndex != _dragIndex)
|
||||
DrawDropIndicator(g);
|
||||
if (ScrollbarVisible)
|
||||
DrawScrollbar(g);
|
||||
}
|
||||
|
||||
private void DrawEmptyState(Graphics g)
|
||||
{
|
||||
using (var brush = new SolidBrush(TextDimColor))
|
||||
using (var font = new Font("Segoe UI", 8.5f, FontStyle.Italic))
|
||||
{
|
||||
var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
g.DrawString("Queue is empty", font, brush, ClientRectangle, sf);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawItem(Graphics g, int index, Rectangle rect)
|
||||
{
|
||||
bool isFirst = index == 0;
|
||||
bool isDragging = index == _dragIndex;
|
||||
bool isHovered = !isDragging && index == _hoveredIndex;
|
||||
Color bg = isDragging ? ItemDragBg : isHovered ? ItemHoverBg : ItemBg;
|
||||
|
||||
// Draw item background
|
||||
using (var path = CreateRoundedRect(rect, ItemRadius))
|
||||
using (var brush = new SolidBrush(bg))
|
||||
g.FillPath(brush, path);
|
||||
|
||||
// Active download (first item) gets gradient accent and border
|
||||
if (isFirst)
|
||||
DrawFirstItemAccent(g, rect);
|
||||
// Dragged items get subtle highlight border
|
||||
else if (isDragging)
|
||||
DrawBorder(g, rect, ItemDragBorder, 0.5f);
|
||||
|
||||
// Draw drag handle, text, and close button
|
||||
if (!isFirst)
|
||||
DrawDragHandle(g, rect);
|
||||
DrawItemText(g, index, rect, isFirst);
|
||||
DrawXButton(g, rect, isHovered && _hoveringX);
|
||||
}
|
||||
|
||||
// Draw gradient accent and border for active download (first item)
|
||||
private void DrawFirstItemAccent(Graphics g, Rectangle rect)
|
||||
{
|
||||
using (var path = CreateRoundedRect(rect, ItemRadius))
|
||||
using (var gradBrush = new LinearGradientBrush(rect,
|
||||
Color.FromArgb(60, AccentColor), Color.FromArgb(0, AccentColor), LinearGradientMode.Horizontal))
|
||||
{
|
||||
var oldClip = g.Clip;
|
||||
g.SetClip(path);
|
||||
g.FillRectangle(gradBrush, rect);
|
||||
g.Clip = oldClip;
|
||||
}
|
||||
DrawBorder(g, rect, AccentColor, 1.5f);
|
||||
}
|
||||
|
||||
private void DrawBorder(Graphics g, Rectangle rect, Color color, float width)
|
||||
{
|
||||
using (var path = CreateRoundedRect(rect, ItemRadius))
|
||||
using (var pen = new Pen(color, width))
|
||||
g.DrawPath(pen, path);
|
||||
}
|
||||
|
||||
private void DrawDragHandle(Graphics g, Rectangle rect)
|
||||
{
|
||||
int cx = rect.X + 8, cy = rect.Y + rect.Height / 2;
|
||||
using (var brush = new SolidBrush(GripColor))
|
||||
{
|
||||
for (int row = -1; row <= 1; row++)
|
||||
for (int col = 0; col < 2; col++)
|
||||
g.FillEllipse(brush, cx + col * 4, cy + row * 4 - 1, 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawItemText(Graphics g, int index, Rectangle rect, bool isFirst)
|
||||
{
|
||||
int textLeft = isFirst ? rect.X + TextPadding : rect.X + DragHandleWidth;
|
||||
int rightPad = ScrollbarVisible ? ScrollbarWidthHover + ScrollbarMargin * 2 : 0;
|
||||
var textRect = new Rectangle(textLeft, rect.Y, rect.Right - XButtonSize - 6 - textLeft - rightPad, rect.Height);
|
||||
|
||||
using (var brush = new SolidBrush(TextColor))
|
||||
using (var font = new Font("Segoe UI", isFirst ? 8.5f : 8f, isFirst ? FontStyle.Bold : FontStyle.Regular))
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Near,
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Trimming = StringTrimming.EllipsisCharacter,
|
||||
FormatFlags = StringFormatFlags.NoWrap
|
||||
};
|
||||
g.DrawString(_items[index], font, brush, textRect, sf);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawXButton(Graphics g, Rectangle itemRect, bool hovered)
|
||||
{
|
||||
var xRect = GetXButtonRect(itemRect);
|
||||
using (var path = CreateRoundedRect(xRect, 3))
|
||||
using (var brush = new SolidBrush(hovered ? XButtonHoverBg : XButtonBg))
|
||||
g.FillPath(brush, path);
|
||||
|
||||
using (var pen = new Pen(Color.White, 1.4f) { StartCap = LineCap.Round, EndCap = LineCap.Round })
|
||||
{
|
||||
int p = 4;
|
||||
g.DrawLine(pen, xRect.X + p, xRect.Y + p, xRect.Right - p, xRect.Bottom - p);
|
||||
g.DrawLine(pen, xRect.Right - p, xRect.Y + p, xRect.X + p, xRect.Bottom - p);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawDropIndicator(Graphics g)
|
||||
{
|
||||
int y = (_dropIndex >= _items.Count ? _items.Count : _dropIndex) * (ItemHeight + ItemMargin) + ItemMargin / 2 - _scrollOffset;
|
||||
int left = ItemMargin + 2;
|
||||
int right = Width - ItemMargin - 2 - (ScrollbarVisible ? ScrollbarWidthHover + ScrollbarMargin : 0);
|
||||
|
||||
using (var pen = new Pen(AccentColor, 2.5f) { StartCap = LineCap.Round, EndCap = LineCap.Round })
|
||||
g.DrawLine(pen, left, y, right, y);
|
||||
}
|
||||
|
||||
// Draw custom scrollbar with hover expansion
|
||||
private void DrawScrollbar(Graphics g)
|
||||
{
|
||||
if (MaxScroll <= 0) return;
|
||||
|
||||
bool expanded = _scrollbarHovered || _scrollbarDragging;
|
||||
int sbWidth = expanded ? ScrollbarWidthHover : ScrollbarWidth;
|
||||
int trackX = Width - ScrollbarWidth - ScrollbarMargin - (expanded ? (ScrollbarWidthHover - ScrollbarWidth) / 2 : 0);
|
||||
|
||||
_scrollTrackRect = new Rectangle(trackX, ScrollbarMargin, sbWidth, Height - ScrollbarMargin * 2);
|
||||
|
||||
using (var trackBrush = new SolidBrush(Color.FromArgb(40, ScrollTrackColor)))
|
||||
using (var trackPath = CreateRoundedRect(_scrollTrackRect, ScrollbarRadius))
|
||||
g.FillPath(trackBrush, trackPath);
|
||||
|
||||
// Calculate thumb position and size
|
||||
int trackHeight = _scrollTrackRect.Height;
|
||||
int thumbHeight = Math.Max(MinThumbHeight, (int)(trackHeight * ((float)Height / ContentHeight)));
|
||||
float scrollRatio = MaxScroll > 0 ? (float)_scrollOffset / MaxScroll : 0;
|
||||
int thumbY = ScrollbarMargin + (int)((trackHeight - thumbHeight) * scrollRatio);
|
||||
|
||||
_scrollThumbRect = new Rectangle(trackX, thumbY, sbWidth, thumbHeight);
|
||||
Color thumbColor = _scrollbarDragging ? ScrollThumbDragColor : _scrollbarHovered ? ScrollThumbHoverColor : ScrollThumbColor;
|
||||
|
||||
using (var thumbBrush = new SolidBrush(thumbColor))
|
||||
using (var thumbPath = CreateRoundedRect(_scrollThumbRect, ScrollbarRadius))
|
||||
g.FillPath(thumbBrush, thumbPath);
|
||||
}
|
||||
|
||||
private Rectangle GetItemRect(int index)
|
||||
{
|
||||
int y = index * (ItemHeight + ItemMargin) + ItemMargin - _scrollOffset;
|
||||
int w = Width - ItemMargin * 2 - (ScrollbarVisible ? ScrollbarWidthHover + ScrollbarMargin + 2 : 0);
|
||||
return new Rectangle(ItemMargin, y, w, ItemHeight);
|
||||
}
|
||||
|
||||
private Rectangle GetXButtonRect(Rectangle itemRect) =>
|
||||
new Rectangle(itemRect.Right - XButtonSize - 3, itemRect.Y + (itemRect.Height - XButtonSize) / 2, XButtonSize, XButtonSize);
|
||||
|
||||
private int HitTest(Point pt)
|
||||
{
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
if (GetItemRect(i).Contains(pt)) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private bool HitTestScrollbar(Point pt) =>
|
||||
ScrollbarVisible && new Rectangle(_scrollTrackRect.X - 4, _scrollTrackRect.Y, _scrollTrackRect.Width + 8, _scrollTrackRect.Height).Contains(pt);
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (_scrollbarDragging)
|
||||
{
|
||||
HandleScrollbarDrag(e.Y);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update scrollbar hover state
|
||||
bool wasHovered = _scrollbarHovered;
|
||||
_scrollbarHovered = HitTestScrollbar(e.Location);
|
||||
if (_scrollbarHovered != wasHovered) Invalidate();
|
||||
|
||||
if (_scrollbarHovered)
|
||||
{
|
||||
Cursor = Cursors.Default;
|
||||
_hoveredIndex = -1;
|
||||
_hoveringX = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle drag operation
|
||||
if (_dragIndex >= 0)
|
||||
{
|
||||
UpdateAutoScroll(e.Y);
|
||||
int newDrop = Math.Max(1, Math.Min(_items.Count, (e.Y + _scrollOffset + ItemHeight / 2) / (ItemHeight + ItemMargin)));
|
||||
if (newDrop != _dropIndex) { _dropIndex = newDrop; Invalidate(); }
|
||||
return;
|
||||
}
|
||||
|
||||
// Update hover state
|
||||
int hit = HitTest(e.Location);
|
||||
bool overX = hit >= 0 && GetXButtonRect(GetItemRect(hit)).Contains(e.Location);
|
||||
|
||||
if (hit != _hoveredIndex || overX != _hoveringX)
|
||||
{
|
||||
_hoveredIndex = hit;
|
||||
_hoveringX = overX;
|
||||
Cursor = overX ? Cursors.Hand : hit > 0 ? Cursors.SizeNS : Cursors.Default;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleScrollbarDrag(int mouseY)
|
||||
{
|
||||
int trackHeight = Height - ScrollbarMargin * 2;
|
||||
int thumbHeight = Math.Max(MinThumbHeight, (int)(trackHeight * ((float)Height / ContentHeight)));
|
||||
int scrollableHeight = trackHeight - thumbHeight;
|
||||
|
||||
if (scrollableHeight > 0)
|
||||
{
|
||||
float scrollRatio = (float)(mouseY - _scrollDragStartY) / scrollableHeight;
|
||||
_scrollOffset = _scrollDragStartOffset + (int)(scrollRatio * MaxScroll);
|
||||
ClampScroll();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
if (e.Button != MouseButtons.Left) return;
|
||||
|
||||
// Handle scrollbar thumb drag
|
||||
if (ScrollbarVisible && _scrollThumbRect.Contains(e.Location))
|
||||
{
|
||||
_scrollbarDragging = true;
|
||||
_scrollDragStartY = e.Y;
|
||||
_scrollDragStartOffset = _scrollOffset;
|
||||
Capture = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle scrollbar track click
|
||||
if (ScrollbarVisible && HitTestScrollbar(e.Location))
|
||||
{
|
||||
_scrollOffset += e.Y < _scrollThumbRect.Top ? -Height : Height;
|
||||
ClampScroll();
|
||||
Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
int hit = HitTest(e.Location);
|
||||
if (hit < 0) return;
|
||||
|
||||
// Handle close button click
|
||||
if (GetXButtonRect(GetItemRect(hit)).Contains(e.Location))
|
||||
{
|
||||
ItemRemoved?.Invoke(this, hit);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start drag operation (only for non-first items)
|
||||
if (hit > 0)
|
||||
{
|
||||
_dragIndex = _dropIndex = hit;
|
||||
Capture = true;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
StopAutoScroll();
|
||||
|
||||
if (_scrollbarDragging)
|
||||
{
|
||||
_scrollbarDragging = false;
|
||||
Capture = false;
|
||||
Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
// Complete drag reorder operation
|
||||
if (_dragIndex > 0 && _dropIndex > 0 && _dropIndex != _dragIndex)
|
||||
{
|
||||
int from = _dragIndex;
|
||||
int to = Math.Max(1, _dropIndex > _dragIndex ? _dropIndex - 1 : _dropIndex);
|
||||
var item = _items[from];
|
||||
_items.RemoveAt(from);
|
||||
_items.Insert(to, item);
|
||||
ItemReordered?.Invoke(this, new ReorderEventArgs(from, to));
|
||||
}
|
||||
|
||||
_dragIndex = _dropIndex = -1;
|
||||
Capture = false;
|
||||
Cursor = Cursors.Default;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
if (_dragIndex < 0 && !_scrollbarDragging)
|
||||
{
|
||||
_hoveredIndex = -1;
|
||||
_hoveringX = _scrollbarHovered = false;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
if (MaxScroll <= 0) return;
|
||||
_scrollOffset -= e.Delta / 4;
|
||||
ClampScroll();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
ClampScroll();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_autoScrollTimer?.Stop();
|
||||
_autoScrollTimer?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private static GraphicsPath CreateRoundedRect(Rectangle rect, int radius)
|
||||
{
|
||||
var path = new GraphicsPath();
|
||||
if (radius <= 0 || rect.Width <= 0 || rect.Height <= 0)
|
||||
{
|
||||
path.AddRectangle(rect);
|
||||
return path;
|
||||
}
|
||||
int d = Math.Min(radius * 2, Math.Min(rect.Width, rect.Height));
|
||||
path.AddArc(rect.X, rect.Y, d, d, 180, 90);
|
||||
path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);
|
||||
path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);
|
||||
path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public class ReorderEventArgs : EventArgs
|
||||
{
|
||||
public int FromIndex { get; }
|
||||
public int ToIndex { get; }
|
||||
public ReorderEventArgs(int from, int to) { FromIndex = from; ToIndex = to; }
|
||||
}
|
||||
}
|
||||
144
NewApps.Designer.cs
generated
@@ -32,31 +32,34 @@ namespace AndroidSideloader
|
||||
this.NewAppsListView = new System.Windows.Forms.ListView();
|
||||
this.GameNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.PackageNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.NewAppsButton = new AndroidSideloader.RoundButton();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.titleLabel = new System.Windows.Forms.Label();
|
||||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
this.panel1.SuspendLayout();
|
||||
this.panel2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// NewAppsListView
|
||||
//
|
||||
this.NewAppsListView.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
|
||||
this.NewAppsListView.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.NewAppsListView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
|
||||
this.NewAppsListView.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.NewAppsListView.CausesValidation = false;
|
||||
this.NewAppsListView.CheckBoxes = true;
|
||||
this.NewAppsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.GameNameIndex,
|
||||
this.PackageNameIndex});
|
||||
this.NewAppsListView.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.NewAppsListView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.NewAppsListView.Font = new System.Drawing.Font("Segoe UI", 9.5F);
|
||||
this.NewAppsListView.ForeColor = System.Drawing.Color.White;
|
||||
this.NewAppsListView.FullRowSelect = true;
|
||||
this.NewAppsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
|
||||
this.NewAppsListView.HideSelection = false;
|
||||
this.NewAppsListView.Location = new System.Drawing.Point(3, 5);
|
||||
this.NewAppsListView.Location = new System.Drawing.Point(1, 1);
|
||||
this.NewAppsListView.Name = "NewAppsListView";
|
||||
this.NewAppsListView.RightToLeftLayout = true;
|
||||
this.NewAppsListView.Size = new System.Drawing.Size(288, 167);
|
||||
this.NewAppsListView.Size = new System.Drawing.Size(298, 168);
|
||||
this.NewAppsListView.TabIndex = 1;
|
||||
this.NewAppsListView.UseCompatibleStateImageBehavior = false;
|
||||
this.NewAppsListView.View = System.Windows.Forms.View.Details;
|
||||
@@ -66,82 +69,119 @@ namespace AndroidSideloader
|
||||
//
|
||||
// GameNameIndex
|
||||
//
|
||||
this.GameNameIndex.Text = "Game Name";
|
||||
this.GameNameIndex.Width = 284;
|
||||
this.GameNameIndex.Text = "App Name";
|
||||
this.GameNameIndex.Width = 280;
|
||||
//
|
||||
// PackageNameIndex
|
||||
//
|
||||
this.PackageNameIndex.Width = 0;
|
||||
//
|
||||
// panel2
|
||||
// panel1
|
||||
//
|
||||
this.panel2.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
|
||||
this.panel2.Controls.Add(this.NewAppsListView);
|
||||
this.panel2.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.panel2.Location = new System.Drawing.Point(9, 31);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Size = new System.Drawing.Size(295, 175);
|
||||
this.panel2.TabIndex = 8;
|
||||
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
|
||||
this.panel1.Controls.Add(this.NewAppsButton);
|
||||
this.panel1.Controls.Add(this.label2);
|
||||
this.panel1.Controls.Add(this.titleLabel);
|
||||
this.panel1.Controls.Add(this.panel2);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Padding = new System.Windows.Forms.Padding(16);
|
||||
this.panel1.Size = new System.Drawing.Size(340, 300);
|
||||
this.panel1.TabIndex = 10;
|
||||
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
|
||||
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
|
||||
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
|
||||
//
|
||||
// NewAppsButton
|
||||
//
|
||||
this.NewAppsButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(140)))), ((int)(((byte)(115)))));
|
||||
this.NewAppsButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(125)))), ((int)(((byte)(105)))));
|
||||
this.NewAppsButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.NewAppsButton.BackColor = System.Drawing.Color.Transparent;
|
||||
this.NewAppsButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.NewAppsButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.NewAppsButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
|
||||
this.NewAppsButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
|
||||
this.NewAppsButton.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold);
|
||||
this.NewAppsButton.ForeColor = System.Drawing.Color.White;
|
||||
this.NewAppsButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(120)))), ((int)(((byte)(100)))));
|
||||
this.NewAppsButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(35)))), ((int)(((byte)(100)))), ((int)(((byte)(85)))));
|
||||
this.NewAppsButton.Location = new System.Drawing.Point(20, 252);
|
||||
this.NewAppsButton.Name = "NewAppsButton";
|
||||
this.NewAppsButton.Radius = 4;
|
||||
this.NewAppsButton.Size = new System.Drawing.Size(300, 36);
|
||||
this.NewAppsButton.Stroke = true;
|
||||
this.NewAppsButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(150)))), ((int)(((byte)(125)))));
|
||||
this.NewAppsButton.TabIndex = 2;
|
||||
this.NewAppsButton.Text = "Continue";
|
||||
this.NewAppsButton.Transparency = false;
|
||||
this.NewAppsButton.Click += new System.EventHandler(this.DonateButton_Click);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.BackColor = System.Drawing.Color.Transparent;
|
||||
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 10.25F, System.Drawing.FontStyle.Bold);
|
||||
this.label2.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.label2.Location = new System.Drawing.Point(28, 7);
|
||||
this.label2.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||
this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.label2.Location = new System.Drawing.Point(20, 42);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(256, 17);
|
||||
this.label2.Size = new System.Drawing.Size(223, 15);
|
||||
this.label2.TabIndex = 9;
|
||||
this.label2.Text = "Check box of all free/non-VR apps";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.label2.Text = "Check the box for all free or non-VR apps";
|
||||
this.label2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
|
||||
this.label2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
|
||||
this.label2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
|
||||
//
|
||||
// NewAppsButton
|
||||
// titleLabel
|
||||
//
|
||||
this.NewAppsButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.NewAppsButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.NewAppsButton.BackColor = System.Drawing.Color.Transparent;
|
||||
this.NewAppsButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.NewAppsButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.NewAppsButton.ForeColor = System.Drawing.Color.White;
|
||||
this.NewAppsButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.NewAppsButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.NewAppsButton.Location = new System.Drawing.Point(12, 212);
|
||||
this.NewAppsButton.Name = "NewAppsButton";
|
||||
this.NewAppsButton.Radius = 5;
|
||||
this.NewAppsButton.Size = new System.Drawing.Size(288, 29);
|
||||
this.NewAppsButton.Stroke = true;
|
||||
this.NewAppsButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.NewAppsButton.TabIndex = 2;
|
||||
this.NewAppsButton.Text = "Accept";
|
||||
this.NewAppsButton.Transparency = false;
|
||||
this.NewAppsButton.Click += new System.EventHandler(this.DonateButton_Click);
|
||||
this.titleLabel.AutoSize = true;
|
||||
this.titleLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.titleLabel.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.titleLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.titleLabel.Location = new System.Drawing.Point(20, 15);
|
||||
this.titleLabel.Name = "titleLabel";
|
||||
this.titleLabel.Size = new System.Drawing.Size(129, 20);
|
||||
this.titleLabel.TabIndex = 11;
|
||||
this.titleLabel.Text = "New Apps Found";
|
||||
this.titleLabel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
|
||||
this.titleLabel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
|
||||
this.titleLabel.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
|
||||
//
|
||||
// panel2
|
||||
//
|
||||
this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
|
||||
this.panel2.Controls.Add(this.NewAppsListView);
|
||||
this.panel2.Location = new System.Drawing.Point(20, 70);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Padding = new System.Windows.Forms.Padding(1);
|
||||
this.panel2.Size = new System.Drawing.Size(300, 170);
|
||||
this.panel2.TabIndex = 8;
|
||||
//
|
||||
// NewApps
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.BackgroundImage = global::AndroidSideloader.Properties.Resources.pattern_cubes_1_1_1_0_0_0_1__000000_212121;
|
||||
this.ClientSize = new System.Drawing.Size(313, 248);
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
|
||||
this.ClientSize = new System.Drawing.Size(340, 300);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.NewAppsButton);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.panel2);
|
||||
this.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
|
||||
this.Controls.Add(this.panel1);
|
||||
this.ForeColor = System.Drawing.Color.White;
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.Name = "NewApps";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Load += new System.EventHandler(this.NewApps_Load);
|
||||
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
|
||||
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
|
||||
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.panel2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
@@ -149,8 +189,10 @@ namespace AndroidSideloader
|
||||
|
||||
private System.Windows.Forms.ListView NewAppsListView;
|
||||
private System.Windows.Forms.ColumnHeader GameNameIndex;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.Panel panel2;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label titleLabel;
|
||||
private System.Windows.Forms.ColumnHeader PackageNameIndex;
|
||||
private RoundButton NewAppsButton;
|
||||
}
|
||||
|
||||
186
NewApps.cs
@@ -1,83 +1,203 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class NewApps : Form
|
||||
{
|
||||
private bool mouseDown;
|
||||
private Point lastLocation;
|
||||
// Modern theme colors
|
||||
private static readonly Color BackgroundColor = Color.FromArgb(20, 24, 29);
|
||||
private static readonly Color BorderColor = Color.FromArgb(70, 80, 100);
|
||||
|
||||
// Shadow and corner settings
|
||||
private const int CS_DROPSHADOW = 0x00020000;
|
||||
private const int WM_NCLBUTTONDOWN = 0xA1;
|
||||
private const int HT_CAPTION = 0x2;
|
||||
private const int SHADOW_SIZE = 2;
|
||||
private const int CONTENT_RADIUS = 10;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool ReleaseCapture();
|
||||
|
||||
protected override CreateParams CreateParams
|
||||
{
|
||||
get
|
||||
{
|
||||
CreateParams cp = base.CreateParams;
|
||||
cp.ClassStyle |= CS_DROPSHADOW;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
public NewApps()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
|
||||
ApplyModernTheme();
|
||||
CenterToScreen();
|
||||
}
|
||||
|
||||
private void label2_MouseDown(object sender, MouseEventArgs e)
|
||||
private void ApplyModernTheme()
|
||||
{
|
||||
mouseDown = true;
|
||||
lastLocation = e.Location;
|
||||
}
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
this.BackColor = Color.FromArgb(25, 25, 30);
|
||||
this.Padding = new Padding(5);
|
||||
|
||||
private void label2_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (mouseDown)
|
||||
panel1.BackColor = BackgroundColor;
|
||||
panel1.Location = new Point(6, 6);
|
||||
panel1.Size = new Size(this.ClientSize.Width - 12, this.ClientSize.Height - 12);
|
||||
panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
|
||||
this.Paint += Form_Paint;
|
||||
|
||||
// Close button
|
||||
var closeButton = new Button
|
||||
{
|
||||
this.Location = new Point(
|
||||
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
|
||||
Text = "✕",
|
||||
Font = new Font("Segoe UI", 9F),
|
||||
ForeColor = Color.White,
|
||||
BackColor = BackgroundColor,
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
Size = new Size(30, 28),
|
||||
Location = new Point(panel1.Width - 35, 5),
|
||||
Cursor = Cursors.Hand,
|
||||
TabStop = false
|
||||
};
|
||||
closeButton.FlatAppearance.BorderSize = 0;
|
||||
closeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(200, 60, 60);
|
||||
closeButton.Click += (s, e) => Close();
|
||||
panel1.Controls.Add(closeButton);
|
||||
closeButton.BringToFront();
|
||||
|
||||
this.Update();
|
||||
// Enable dragging
|
||||
panel1.MouseDown += TitleArea_MouseDown;
|
||||
label2.MouseDown += TitleArea_MouseDown;
|
||||
titleLabel.MouseDown += TitleArea_MouseDown;
|
||||
}
|
||||
|
||||
private void TitleArea_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
ReleaseCapture();
|
||||
SendMessage(this.Handle, WM_NCLBUTTONDOWN, (IntPtr)HT_CAPTION, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
private void label2_MouseUp(object sender, MouseEventArgs e)
|
||||
private void Form_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
mouseDown = false;
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
int w = this.Width;
|
||||
int h = this.Height;
|
||||
|
||||
// Draw shadow layers
|
||||
for (int i = SHADOW_SIZE; i >= 1; i--)
|
||||
{
|
||||
int alpha = (SHADOW_SIZE - i + 1) * 12;
|
||||
Rectangle shadowRect = new Rectangle(
|
||||
SHADOW_SIZE - i,
|
||||
SHADOW_SIZE - i,
|
||||
w - (SHADOW_SIZE - i) * 2 - 1,
|
||||
h - (SHADOW_SIZE - i) * 2 - 1);
|
||||
|
||||
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 0, 0, 0), 1))
|
||||
using (GraphicsPath shadowPath = CreateRoundedRectPath(shadowRect, CONTENT_RADIUS + i))
|
||||
{
|
||||
e.Graphics.DrawPath(shadowPen, shadowPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw content background
|
||||
Rectangle contentRect = new Rectangle(SHADOW_SIZE, SHADOW_SIZE, w - SHADOW_SIZE * 2, h - SHADOW_SIZE * 2);
|
||||
using (GraphicsPath contentPath = CreateRoundedRectPath(contentRect, CONTENT_RADIUS))
|
||||
{
|
||||
using (SolidBrush bgBrush = new SolidBrush(BackgroundColor))
|
||||
{
|
||||
e.Graphics.FillPath(bgBrush, contentPath);
|
||||
}
|
||||
|
||||
using (Pen borderPen = new Pen(BorderColor, 1f))
|
||||
{
|
||||
e.Graphics.DrawPath(borderPen, contentPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply rounded region
|
||||
using (GraphicsPath regionPath = CreateRoundedRectPath(new Rectangle(0, 0, w, h), CONTENT_RADIUS + SHADOW_SIZE))
|
||||
{
|
||||
this.Region = new Region(regionPath);
|
||||
}
|
||||
}
|
||||
|
||||
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
if (radius <= 0)
|
||||
{
|
||||
path.AddRectangle(rect);
|
||||
return path;
|
||||
}
|
||||
|
||||
int diameter = Math.Min(radius * 2, Math.Min(rect.Width, rect.Height));
|
||||
radius = diameter / 2;
|
||||
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
|
||||
|
||||
path.AddArc(arcRect, 180, 90);
|
||||
arcRect.X = rect.Right - diameter;
|
||||
path.AddArc(arcRect, 270, 90);
|
||||
arcRect.Y = rect.Bottom - diameter;
|
||||
path.AddArc(arcRect, 0, 90);
|
||||
arcRect.X = rect.Left;
|
||||
path.AddArc(arcRect, 90, 90);
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
|
||||
private void label2_MouseDown(object sender, MouseEventArgs e) => TitleArea_MouseDown(sender, e);
|
||||
private void label2_MouseMove(object sender, MouseEventArgs e) { }
|
||||
private void label2_MouseUp(object sender, MouseEventArgs e) { }
|
||||
|
||||
private void DonateButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
string HWID = SideloaderUtilities.UUID();
|
||||
foreach (ListViewItem listItem in NewAppsListView.Items)
|
||||
{
|
||||
if (listItem.Checked)
|
||||
{
|
||||
Properties.Settings.Default.NonAppPackages += listItem.SubItems[Donors.PackageNameIndex].Text + ";" + HWID + "\n";
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
Properties.Settings.Default.AppPackages += listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
MainForm.newpackageupload();
|
||||
this.Close();
|
||||
MainForm.newPackageUpload();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void NewApps_Load(object sender, EventArgs e)
|
||||
{
|
||||
NewAppsListView.Items.Clear();
|
||||
Donors.initNewApps();
|
||||
List<ListViewItem> NewAppList = new List<ListViewItem>();
|
||||
var NewAppList = new List<ListViewItem>();
|
||||
foreach (string[] release in Donors.newApps)
|
||||
{
|
||||
ListViewItem NGame = new ListViewItem(release);
|
||||
if (!NewAppList.Contains(NGame))
|
||||
NewAppList.Add(NGame);
|
||||
NewAppList.Add(NGame);
|
||||
}
|
||||
ListViewItem[] arr = NewAppList.ToArray();
|
||||
NewAppsListView.BeginUpdate();
|
||||
NewAppsListView.Items.Clear();
|
||||
NewAppsListView.Items.AddRange(arr);
|
||||
NewAppsListView.Items.AddRange(NewAppList.ToArray());
|
||||
NewAppsListView.EndUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
144
Program.cs
@@ -1,36 +1,110 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Security.Permissions;
|
||||
using System.IO;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
|
||||
static void Main()
|
||||
{
|
||||
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
form = new MainForm();
|
||||
Application.Run(form);
|
||||
//form.Show();
|
||||
}
|
||||
public static MainForm form;
|
||||
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
Exception e = (Exception)args.ExceptionObject;
|
||||
string date_time = DateTime.Now.ToString("dddd, MMMM dd @ hh:mmtt (UTC)");
|
||||
File.WriteAllText(Sideloader.CrashLogPath, $"Date/Time of crash: {date_time}\nMessage: {e.Message}\nData: {e.Data}\nSource: {e.Source}\nTargetSite: {e.TargetSite}");
|
||||
}
|
||||
}
|
||||
using AndroidSideloader.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Permissions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static SettingsManager settings;
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
|
||||
private static void Main()
|
||||
{
|
||||
// Handle corrupted user.config files
|
||||
bool configFixed = false;
|
||||
Exception configException = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Force settings initialization to trigger any config errors early
|
||||
var test = AndroidSideloader.Properties.Settings.Default.FontStyle;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
configException = ex;
|
||||
// Delete the corrupted config file and retry
|
||||
try
|
||||
{
|
||||
string configPath = GetUserConfigPath();
|
||||
if (!string.IsNullOrEmpty(configPath) && File.Exists(configPath))
|
||||
{
|
||||
File.Delete(configPath);
|
||||
configFixed = true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If we can't delete it, try to continue anyway
|
||||
}
|
||||
}
|
||||
|
||||
if (configFixed)
|
||||
{
|
||||
// Restart the application after fixing config
|
||||
Application.Restart();
|
||||
return;
|
||||
}
|
||||
|
||||
if (configException != null)
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Settings file is corrupted and could not be repaired automatically.\n\n" +
|
||||
"Please delete this folder and restart the application:\n" +
|
||||
Path.GetDirectoryName(GetUserConfigPath()),
|
||||
"Configuration Error",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
settings = SettingsManager.Instance;
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
form = new MainForm();
|
||||
Application.Run(form);
|
||||
//form.Show();
|
||||
}
|
||||
|
||||
private static string GetUserConfigPath()
|
||||
{
|
||||
try
|
||||
{
|
||||
string appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
string companyName = "Rookie.AndroidSideloader";
|
||||
string exeName = "AndroidSideloader.exe_Url_dkp0unsd4fjaabhwwafgfxvvbrerf10b";
|
||||
string version = "2.0.0.0";
|
||||
return Path.Combine(appData, companyName, exeName, version, "user.config");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static MainForm form;
|
||||
|
||||
private static void CrashHandler(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
// Capture unhandled exceptions and write to file.
|
||||
Exception e = (Exception)args.ExceptionObject;
|
||||
string innerExceptionMessage = (e.InnerException != null)
|
||||
? e.InnerException.Message
|
||||
: "None";
|
||||
string date_time = DateTime.Now.ToString("dddd, MMMM dd @ hh:mmtt (UTC)");
|
||||
File.WriteAllText(Sideloader.CrashLogPath, $"Date/Time of crash: {date_time}\nMessage: {e.Message}\nInner Message: {innerExceptionMessage}\nData: {e.Data}\nSource: {e.Source}\nTargetSite: {e.TargetSite}\nStack Trace: \n{e.StackTrace}\n\n\nDebuglog: \n\n\n");
|
||||
// If a debuglog exists we append it to the crashlog.
|
||||
if (settings != null && File.Exists(settings.CurrentLogPath))
|
||||
{
|
||||
File.AppendAllText(Sideloader.CrashLogPath, File.ReadAllText($"{settings.CurrentLogPath}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
@@ -9,7 +8,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTitle("AndroidSideloader")]
|
||||
[assembly: AssemblyDescription("Rookie Sideloader")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Rookie.WTF")]
|
||||
[assembly: AssemblyCompany("Rookie.AndroidSideloader")]
|
||||
[assembly: AssemblyProduct("AndroidSideloader")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
62
Properties/Resources.Designer.cs
generated
@@ -19,7 +19,7 @@ namespace AndroidSideloader.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
@@ -80,56 +80,6 @@ namespace AndroidSideloader.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap battery1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("battery1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap battery11 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("battery11", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap Pattern {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Pattern", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap pattern_cubes_1_1_1_0_0_0_1__000000_212121 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("pattern_cubes-1_1_1_0-0_0_1__000000_212121", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap pattern_herringbone_2_1_3_0_0_90_1__000000_1c1c1c {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("pattern_herringbone_2_1_3_0_0_90_1__000000_1c1c1c", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
@@ -139,15 +89,5 @@ namespace AndroidSideloader.Properties {
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap splashimage {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("splashimage", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,28 +121,10 @@
|
||||
<data name="battery" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\battery.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="battery1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\battery11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="pattern_herringbone_2_1_3_0_0_90_1__000000_1c1c1c" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\pattern_herringbone-2_1_3_0-0_90_1__000000_1c1c1c.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="splashimage" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\splashimage.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="battery11" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\battery1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ajax-loader" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\ajax-loader.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="SearchGlass" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\SearchGlass.PNG;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Pattern" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Pattern.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="pattern_cubes-1_1_1_0-0_0_1__000000_212121" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\pattern_cubes-1_1_1_0-0_0_1__000000_212121.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
1490
Properties/Settings.Designer.cs
generated
@@ -24,7 +24,7 @@
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="FontStyle" Type="System.Drawing.Font" Scope="User">
|
||||
<Value Profile="(Default)">Microsoft Sans Serif, 11.25pt</Value>
|
||||
<Value Profile="(Default)">Microsoft Sans Serif, 10pt</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackPicturePath" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
@@ -32,9 +32,6 @@
|
||||
<Setting Name="SpoofGames" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="BandwithLimit" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="BigFontStyle" Type="System.Drawing.Font" Scope="User">
|
||||
<Value Profile="(Default)">Microsoft Sans Serif, 14pt</Value>
|
||||
</Setting>
|
||||
@@ -50,36 +47,9 @@
|
||||
<Setting Name="ADBPath" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="QUsett" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="QuChecked" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="QUhz" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="QUres" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="QUy" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="QUx" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="QUname" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Change Me</Value>
|
||||
</Setting>
|
||||
<Setting Name="QUString" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="MainDir" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="QUStringF" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="delsh" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
@@ -98,9 +68,6 @@
|
||||
<Setting Name="PackageNameToCB" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="EnterKeyInstall" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="DownUpHeld" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
@@ -116,9 +83,6 @@
|
||||
<Setting Name="CurrentCrashName" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="QUturnedon" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="adbdebugwarned" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
@@ -168,19 +132,67 @@
|
||||
<Value Profile="(Default)">25, 25, 25</Value>
|
||||
</Setting>
|
||||
<Setting Name="SubButtonColor" Type="System.Drawing.Color" Scope="User">
|
||||
<Value Profile="(Default)">25, 25, 25</Value>
|
||||
<Value Profile="(Default)">42, 45, 58</Value>
|
||||
</Setting>
|
||||
<Setting Name="TextBoxColor" Type="System.Drawing.Color" Scope="User">
|
||||
<Value Profile="(Default)">25, 25, 25</Value>
|
||||
</Setting>
|
||||
<Setting Name="ButtonColor" Type="System.Drawing.Color" Scope="User">
|
||||
<Value Profile="(Default)">Black</Value>
|
||||
<Value Profile="(Default)">32, 35, 45</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackColor" Type="System.Drawing.Color" Scope="User">
|
||||
<Value Profile="(Default)">1, 1, 1</Value>
|
||||
<Value Profile="(Default)">31, 34, 42</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppPackages" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="TrailersOn" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="downloadDir" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="customDownloadDir" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="customBackupDir" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="backupDir" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="singleThreadMode" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="virtualFilesystemCompatibility" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="UpdateSettings" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="UUID" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="createPubMirrorFile" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="useDownloadedFiles" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="bandwidthLimit" Type="System.Single" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="useProxy" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="proxyAddress" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="proxyPort" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="selectedMirror" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
1297
QuestForm.Designer.cs
generated
379
QuestForm.cs
@@ -1,374 +1,199 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AndroidSideloader.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class QuestForm : Form
|
||||
{
|
||||
private static readonly SettingsManager settings = SettingsManager.Instance;
|
||||
public static int length = 0;
|
||||
public static string[] result;
|
||||
public bool settingsexist = false;
|
||||
public static bool QUSon = false;
|
||||
public bool delsh = false;
|
||||
private bool delsh = false;
|
||||
|
||||
public QuestForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
}
|
||||
|
||||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
private void btnApplyTempSettings_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool ChangesMade = false;
|
||||
|
||||
//Quest 2 settings, might remove them in the future since some of them are broken
|
||||
if (RefreshRateComboBox.SelectedIndex != -1)
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
ADB.RunAdbCommandToString($"shell setprop debug.oculus.refreshRate {RefreshRateComboBox.SelectedItem.ToString()}");
|
||||
ADB.RunAdbCommandToString($"shell settings put global 90hz_global {RefreshRateComboBox.SelectedIndex}");
|
||||
ADB.RunAdbCommandToString($"shell settings put global 90hzglobal {RefreshRateComboBox.SelectedIndex}");
|
||||
string refreshRate = RefreshRateComboBox.SelectedItem.ToString().Replace(" Hz", "");
|
||||
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.refreshRate {refreshRate}");
|
||||
_ = ADB.RunAdbCommandToString($"shell settings put global 90hz_global {RefreshRateComboBox.SelectedIndex}");
|
||||
_ = ADB.RunAdbCommandToString($"shell settings put global 90hzglobal {RefreshRateComboBox.SelectedIndex}");
|
||||
ChangesMade = true;
|
||||
}
|
||||
|
||||
if (TextureResTextBox.Text.Length > 0)
|
||||
if (TextureResTextBox.Text.Length > 0 && TextureResTextBox.Text != "0")
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
int result;
|
||||
Int32.TryParse(TextureResTextBox.Text, out result);
|
||||
ADB.RunAdbCommandToString($"shell settings put global texture_size_Global {TextureResTextBox.Text}");
|
||||
ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureWidth {TextureResTextBox.Text}");
|
||||
ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureHeight {TextureResTextBox.Text}");
|
||||
ChangesMade = true;
|
||||
if (int.TryParse(TextureResTextBox.Text, out _))
|
||||
{
|
||||
_ = ADB.RunAdbCommandToString($"shell settings put global texture_size_Global {TextureResTextBox.Text}");
|
||||
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureWidth {TextureResTextBox.Text}");
|
||||
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureHeight {TextureResTextBox.Text}");
|
||||
ChangesMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (CPUComboBox.SelectedIndex != -1)
|
||||
{
|
||||
ADB.RunAdbCommandToString($"shell setprop debug.oculus.cpuLevel {CPUComboBox.SelectedItem.ToString()}");
|
||||
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.cpuLevel {CPUComboBox.SelectedIndex}");
|
||||
ChangesMade = true;
|
||||
}
|
||||
|
||||
if (GPUComboBox.SelectedIndex != -1)
|
||||
{
|
||||
ADB.RunAdbCommandToString($"shell setprop debug.oculus.gpuLevel {GPUComboBox.SelectedItem.ToString()}");
|
||||
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.gpuLevel {GPUComboBox.SelectedIndex}");
|
||||
ChangesMade = true;
|
||||
}
|
||||
|
||||
if (ChangesMade)
|
||||
MessageBox.Show("Settings applied!");
|
||||
{
|
||||
_ = MessageBox.Show("Settings applied!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void setLength(Int32 value)
|
||||
public static void setLength(int value)
|
||||
{
|
||||
result = new string[value];
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void ResetQU_click(object sender, EventArgs e)
|
||||
private void toggleDeleteAfterTransfer_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ResBox.Text = ("0");
|
||||
UsrBox.Text = ("Change Me");
|
||||
FOVx.Text = ("0");
|
||||
FOVy.Text = ("0");
|
||||
QURfrRt.SelectedIndex = 0;
|
||||
delsh = toggleDeleteAfterTransfer.Checked;
|
||||
}
|
||||
|
||||
private void DeleteShots_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (DeleteShots.Checked)
|
||||
delsh = true;
|
||||
else
|
||||
delsh = false;
|
||||
}
|
||||
private void QUon_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (QUon.Checked)
|
||||
{
|
||||
ResBox.Visible = true;
|
||||
UsrBox.Visible = true;
|
||||
FOVx.Visible = true;
|
||||
FOVy.Visible = true;
|
||||
QURfrRt.Visible = true;
|
||||
ResetQU.Visible = true;
|
||||
QUEnable.Visible = true;
|
||||
label5.Visible = true;
|
||||
label6.Visible = true;
|
||||
label7.Visible = true;
|
||||
label8.Visible = true;
|
||||
label9.Visible = true;
|
||||
label10.Visible = true;
|
||||
deleteButton.Visible = true;
|
||||
ResBox.Text = Properties.Settings.Default.QUres;
|
||||
UsrBox.Text = Properties.Settings.Default.QUname;
|
||||
FOVy.Text = Properties.Settings.Default.QUy;
|
||||
FOVx.Text = Properties.Settings.Default.QUx;
|
||||
QURfrRt.SelectedValue = Properties.Settings.Default.QUhz;
|
||||
Properties.Settings.Default.QUturnedon = true;
|
||||
}
|
||||
else if (!QUon.Checked)
|
||||
{
|
||||
ResBox.Visible = false;
|
||||
UsrBox.Visible = false;
|
||||
FOVx.Visible = false;
|
||||
FOVy.Visible = false;
|
||||
QURfrRt.Visible = false;
|
||||
ResetQU.Visible = false;
|
||||
QUEnable.Visible = false;
|
||||
label5.Visible = false;
|
||||
label6.Visible = false;
|
||||
label7.Visible = false;
|
||||
label8.Visible = false;
|
||||
label9.Visible = false;
|
||||
label10.Visible = false;
|
||||
deleteButton.Visible = false;
|
||||
Properties.Settings.Default.QUturnedon = false;
|
||||
MessageBox.Show("Ok, Deleted your custom settings file.\nIf you would like to re-enable return here and apply settings again");
|
||||
File.Delete($"{Environment.CurrentDirectory}\\Config.Json");
|
||||
File.Delete($"{Environment.CurrentDirectory}\\delete_settings");
|
||||
}
|
||||
|
||||
}
|
||||
private static readonly Random random = new Random();
|
||||
private static readonly object syncLock = new object();
|
||||
|
||||
public static int RandomNumber(int min, int max)
|
||||
{
|
||||
lock (syncLock)
|
||||
{ // synchronize
|
||||
{
|
||||
return random.Next(min, max);
|
||||
}
|
||||
}
|
||||
private void QUEnable_Click(object sender, EventArgs e)
|
||||
|
||||
private void QuestForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
|
||||
settingsexist = true;
|
||||
MessageBox.Show("OK, any -QU packages installed will have these settings applied!\nTo delete settings: goto main app window, select a game with top menu, and click \"Remove QU Setting\"");
|
||||
if (QUon.Checked)
|
||||
{
|
||||
Properties.Settings.Default.QUturnedon = true;
|
||||
Random r = new Random();
|
||||
|
||||
int x = r.Next(999999999);
|
||||
int y = r.Next(9999999);
|
||||
|
||||
var sum = ((long)y * (long)1000000000) + (long)x;
|
||||
|
||||
int x2 = r.Next(999999999);
|
||||
int y2 = r.Next(9999999);
|
||||
|
||||
var sum2 = ((long)y2 * (long)1000000000) + (long)x2;
|
||||
|
||||
QUSon = true;
|
||||
|
||||
string selected = this.QURfrRt.GetItemText(this.QURfrRt.SelectedItem);
|
||||
|
||||
Properties.Settings.Default.QUString = $"\"refresh_rate\":{selected},\"eye_texture_width\":{ResBox.Text},\"fov_x\":{FOVx.Text},\"fov_y\":{FOVy.Text},\"username\":\"{UsrBox.Text}\"}}";
|
||||
Properties.Settings.Default.QUStringF = $"{{\"user_id\":{sum},\"app_id\":\"{sum2}\",";
|
||||
Properties.Settings.Default.Save();
|
||||
File.WriteAllText($"{Properties.Settings.Default.MainDir}\\delete_settings", "");
|
||||
string boff = Properties.Settings.Default.QUStringF + Properties.Settings.Default.QUString;
|
||||
File.WriteAllText($"{Properties.Settings.Default.MainDir}\\config.json", boff);
|
||||
}
|
||||
else
|
||||
{
|
||||
Properties.Settings.Default.QUturnedon = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void QuestForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
if (QUon.Checked)
|
||||
{
|
||||
Properties.Settings.Default.QUsett = true;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
if (!QUon.Checked)
|
||||
{
|
||||
Properties.Settings.Default.QUsett = false;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
if (DeleteShots.Checked)
|
||||
{
|
||||
Properties.Settings.Default.delsh = true;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
if (!DeleteShots.Checked)
|
||||
{
|
||||
Properties.Settings.Default.delsh = false;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
settings.Delsh = toggleDeleteAfterTransfer.Checked;
|
||||
settings.Save();
|
||||
}
|
||||
|
||||
private void QuestForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (Properties.Settings.Default.delsh)
|
||||
DeleteShots.Checked = true;
|
||||
else
|
||||
DeleteShots.Checked = false;
|
||||
if (Properties.Settings.Default.QUsett)
|
||||
{
|
||||
ResBox.Text = Properties.Settings.Default.QUres;
|
||||
UsrBox.Text = Properties.Settings.Default.QUname;
|
||||
FOVy.Text = Properties.Settings.Default.QUy;
|
||||
FOVx.Text = Properties.Settings.Default.QUx;
|
||||
QURfrRt.Text = Properties.Settings.Default.QUhz;
|
||||
QUon.Checked = true;
|
||||
if (settingsexist)
|
||||
QUSon = true;
|
||||
}
|
||||
GlobalUsername.Text = Properties.Settings.Default.GlobalUsername;
|
||||
CenterToParent();
|
||||
toggleDeleteAfterTransfer.SetCheckedSilent(settings.Delsh);
|
||||
delsh = settings.Delsh;
|
||||
GlobalUsername.Text = settings.GlobalUsername;
|
||||
}
|
||||
|
||||
private void ResBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.QUres = ResBox.Text;
|
||||
Properties.Settings.Default.Save();
|
||||
|
||||
}
|
||||
|
||||
private void UsrBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.QUname = UsrBox.Text;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void FOVx_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.QUx = FOVx.Text;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void FOVy_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.QUy = FOVy.Text;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void QURfrRt_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
string selected = this.QURfrRt.GetItemText(this.QURfrRt.SelectedItem);
|
||||
Properties.Settings.Default.QUhz = selected;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
private void DeleteButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
MessageBox.Show("Ok, Deleted your custom settings file.\nIf you would like to re-enable return here and apply settings again");
|
||||
File.Delete($"{Properties.Settings.Default.MainDir}\\Config.Json");
|
||||
}
|
||||
private void questPics_Click(object sender, EventArgs e)
|
||||
{
|
||||
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
||||
if (!Directory.Exists($"{path}\\Quest ScreenShots"))
|
||||
Directory.CreateDirectory($"{path}\\Quest ScreenShots");
|
||||
MessageBox.Show("Please wait until you get the message that the transfer has finished.");
|
||||
ADB.WakeDevice();
|
||||
Program.form.ChangeTitle("Pulling files...");
|
||||
ADB.RunAdbCommandToString($"pull \"/sdcard/Oculus/Screenshots\" \"{path}\\Quest ScreenShots\"");
|
||||
if (!Directory.Exists($"{path}\\Quest Screenshots"))
|
||||
{
|
||||
_ = Directory.CreateDirectory($"{path}\\Quest Screenshots");
|
||||
}
|
||||
|
||||
_ = MessageBox.Show("Please wait until you get the message that the transfer has finished.",
|
||||
"Transfer Starting", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
Program.form.changeTitle("Pulling files...");
|
||||
_ = ADB.RunAdbCommandToString($"pull \"/sdcard/Oculus/Screenshots\" \"{path}\\Quest Screenshots\"");
|
||||
|
||||
if (delsh)
|
||||
{
|
||||
DialogResult dialogResult = MessageBox.Show("You have chosen to delete files from headset after transferring, so be sure to move them from your desktop to somewhere safe!", "Warning!", MessageBoxButtons.OKCancel);
|
||||
DialogResult dialogResult = MessageBox.Show(
|
||||
"You have chosen to delete files from headset after transferring.\n\nMake sure to move them from your desktop to somewhere safe!",
|
||||
"Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
|
||||
|
||||
if (dialogResult == DialogResult.OK)
|
||||
{
|
||||
ADB.RunAdbCommandToString("shell rm -r /sdcard/Oculus/Screenshots");
|
||||
ADB.RunAdbCommandToString("shell mkdir /sdcard/Oculus/Screenshots");
|
||||
{
|
||||
_ = ADB.RunAdbCommandToString("shell rm -r /sdcard/Oculus/Screenshots");
|
||||
_ = ADB.RunAdbCommandToString("shell mkdir /sdcard/Oculus/Screenshots");
|
||||
}
|
||||
}
|
||||
MessageBox.Show("Transfer finished! ScreenShots can be found in a folder named Quest Screenshots on your desktop!");
|
||||
Program.form.ChangeTitle("Done!");
|
||||
|
||||
_ = MessageBox.Show("Transfer finished!\n\nScreenshots can be found in:\nDesktop\\Quest Screenshots",
|
||||
"Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Program.form.changeTitle("Done!");
|
||||
}
|
||||
|
||||
private void questVids_Click(object sender, EventArgs e)
|
||||
{
|
||||
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
if (!Directory.Exists($"{path}\\Quest VideoShots"))
|
||||
Directory.CreateDirectory($"{path}\\Quest VideoShots");
|
||||
MessageBox.Show("Please wait until you get the message that the transfer has finished.");
|
||||
ADB.WakeDevice();
|
||||
Program.form.ChangeTitle("Pulling files...");
|
||||
ADB.RunAdbCommandToString($"pull \"/sdcard/Oculus/Videoshots\" \"{path}\\Quest VideoShots\"");
|
||||
|
||||
if (!Directory.Exists($"{path}\\Quest Recordings"))
|
||||
{
|
||||
_ = Directory.CreateDirectory($"{path}\\Quest Recordings");
|
||||
}
|
||||
|
||||
_ = MessageBox.Show("Please wait until you get the message that the transfer has finished.",
|
||||
"Transfer Starting", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
Program.form.changeTitle("Pulling files...");
|
||||
_ = ADB.RunAdbCommandToString($"pull \"/sdcard/Oculus/Videoshots\" \"{path}\\Quest Recordings\"");
|
||||
|
||||
if (delsh)
|
||||
{
|
||||
DialogResult dialogResult = MessageBox.Show("You have chosen to delete files from headset after transferring, so be sure to move them from your desktop to somewhere safe!", "Warning!", MessageBoxButtons.OKCancel);
|
||||
DialogResult dialogResult = MessageBox.Show(
|
||||
"You have chosen to delete files from headset after transferring.\n\nMake sure to move them from your desktop to somewhere safe!",
|
||||
"Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
|
||||
|
||||
if (dialogResult == DialogResult.OK)
|
||||
{
|
||||
ADB.RunAdbCommandToString("shell rm -r /sdcard/Oculus/Videoshots");
|
||||
ADB.RunAdbCommandToString("shell mkdir /sdcard/Oculus/Videoshots");
|
||||
_ = ADB.RunAdbCommandToString("shell rm -r /sdcard/Oculus/Videoshots");
|
||||
_ = ADB.RunAdbCommandToString("shell mkdir /sdcard/Oculus/Videoshots");
|
||||
}
|
||||
}
|
||||
MessageBox.Show("Transfer finished! VideoShots can be found in a folder named Quest VideoShots on your desktop!");
|
||||
Program.form.ChangeTitle("Done!");
|
||||
}
|
||||
private void button3_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (GlobalUsername.Text.Contains(" "))
|
||||
{
|
||||
MessageBox.Show("Usernames with a space are not permitted.", "Detected a space in username!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ADB.RunAdbCommandToString($"shell settings put global username {GlobalUsername.Text}");
|
||||
MessageBox.Show($"Username set as {GlobalUsername.Text}", "Success");
|
||||
}
|
||||
|
||||
_ = MessageBox.Show("Transfer finished!\n\nRecordings can be found in:\nDesktop\\Quest Recordings",
|
||||
"Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Program.form.changeTitle("Done!");
|
||||
}
|
||||
|
||||
|
||||
private void Form_KeyDown(object sender, KeyEventArgs e)
|
||||
private void btnApplyUsername_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
_ = ADB.RunAdbCommandToString($"shell settings put global username {GlobalUsername.Text}");
|
||||
_ = MessageBox.Show($"Username set to: {GlobalUsername.Text}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
private void btnClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override bool ProcessDialogKey(Keys keyData)
|
||||
{
|
||||
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessDialogKey(keyData);
|
||||
}
|
||||
|
||||
private void WifiWake_Click(object sender, EventArgs e)
|
||||
{
|
||||
ADB.RunAdbCommandToString("shell settings put global wifi_wakeup_available 1");
|
||||
ADB.RunAdbCommandToString("shell settings put global wifi_wakeup_enabled 1");
|
||||
MessageBox.Show("Wake on Wifi enabled!\n\nNOTE: This requires having wireless ADB enabled to work. (Obviously)");
|
||||
}
|
||||
|
||||
private void GlobalUsername_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (GlobalUsername.TextLength > 0)
|
||||
button3.Enabled = true;
|
||||
else
|
||||
button3.Enabled = false;
|
||||
Properties.Settings.Default.GlobalUsername = GlobalUsername.Text;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void RefreshRateComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void CPUComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void GPUComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
btnApplyUsername.Enabled = GlobalUsername.TextLength > 0;
|
||||
btnApplyUsername.ForeColor = System.Drawing.Color.FromArgb(
|
||||
((int)(((byte)(btnApplyUsername.Enabled ? 30 : 80)))),
|
||||
((int)(((byte)(btnApplyUsername.Enabled ? 24 : 80)))),
|
||||
((int)(((byte)(btnApplyUsername.Enabled ? 29 : 80)))));
|
||||
|
||||
settings.GlobalUsername = GlobalUsername.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
315
RCLONE.cs
@@ -1,22 +1,46 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using AndroidSideloader.Utilities;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class RCLONE
|
||||
internal class RCLONE
|
||||
{
|
||||
//Kill all rclone, using a static rclone variable doesn't work for some reason #tofix
|
||||
private static readonly SettingsManager settings = SettingsManager.Instance;
|
||||
// Kill RCLONE Processes that were started from Rookie by looking for child processes.
|
||||
public static void killRclone()
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName("rclone"))
|
||||
process.Kill();
|
||||
var parentProcessId = Process.GetCurrentProcess().Id;
|
||||
var processes = Process.GetProcessesByName("rclone");
|
||||
|
||||
foreach (var process in processes)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (ManagementObject obj = new ManagementObject($"win32_process.handle='{process.Id}'"))
|
||||
{
|
||||
obj.Get();
|
||||
var ppid = Convert.ToInt32(obj["ParentProcessId"]);
|
||||
|
||||
if (ppid == parentProcessId)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = Logger.Log($"Exception occured while attempting to shut down RCLONE with exception message: {ex.Message}", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//For custom configs that use a password
|
||||
// For custom configs that use a password
|
||||
public static void Init()
|
||||
{
|
||||
string PwTxtPath = Path.Combine(Environment.CurrentDirectory, "rclone\\pw.txt");
|
||||
@@ -26,83 +50,107 @@ namespace AndroidSideloader
|
||||
}
|
||||
}
|
||||
|
||||
//Change if you want to use a config
|
||||
// Change if you want to use a config
|
||||
public static string downloadConfigPath = "vrp.download.config";
|
||||
public static string uploadConfigPath = "vrp.upload.config";
|
||||
public static string rclonepw = "";
|
||||
|
||||
|
||||
private static Process rclone = new Process();
|
||||
|
||||
//Run rclone command
|
||||
public static ProcessOutput runRcloneCommand_DownloadConfig(string command, string bandwithLimit = "")
|
||||
private static readonly Process rclone = new Process();
|
||||
|
||||
// Run an RCLONE Command that accesses the Download Config.
|
||||
public static ProcessOutput runRcloneCommand_DownloadConfig(string command)
|
||||
{
|
||||
if (!MainForm.HasInternet || MainForm.isOffline)
|
||||
if (MainForm.isOffline)
|
||||
{
|
||||
return new ProcessOutput("", "No internet");
|
||||
}
|
||||
|
||||
ProcessOutput prcoutput = new ProcessOutput();
|
||||
//Rclone output is unicode, else it will show garbage instead of unicode characters
|
||||
// Rclone output is unicode, else it will show garbage instead of unicode characters
|
||||
rclone.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||
string originalCommand = command;
|
||||
|
||||
//set bandwidth limit
|
||||
if (bandwithLimit.Length > 0)
|
||||
{
|
||||
command += $" --bwlimit={bandwithLimit}";
|
||||
}
|
||||
|
||||
//set configpath if there is any
|
||||
// set configpath if there is any
|
||||
if (downloadConfigPath.Length > 0)
|
||||
{
|
||||
command += $" --config {downloadConfigPath}";
|
||||
}
|
||||
|
||||
//set rclonepw
|
||||
if (rclonepw.Length > 0)
|
||||
command += " --ask-password=false";
|
||||
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
|
||||
if (logcmd.Contains($"\"{Properties.Settings.Default.CurrentLogPath}\""))
|
||||
logcmd = logcmd.Replace($"\"{Properties.Settings.Default.CurrentLogPath}\"", $"\"{Properties.Settings.Default.CurrentLogName}\"");
|
||||
if (logcmd.Contains(Environment.CurrentDirectory))
|
||||
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
|
||||
Logger.Log($"Running Rclone command: {logcmd}");
|
||||
command += $" --inplace";
|
||||
|
||||
rclone.StartInfo.FileName = Environment.CurrentDirectory + "\\rclone\\rclone.exe";
|
||||
// set rclonepw
|
||||
if (rclonepw.Length > 0)
|
||||
{
|
||||
command += " --ask-password=false";
|
||||
}
|
||||
|
||||
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
|
||||
if (logcmd.Contains($"\"{settings.CurrentLogPath}\""))
|
||||
{
|
||||
logcmd = logcmd.Replace($"\"{settings.CurrentLogPath}\"", $"\"{settings.CurrentLogName}\"");
|
||||
}
|
||||
|
||||
if (logcmd.Contains(Environment.CurrentDirectory))
|
||||
{
|
||||
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
|
||||
}
|
||||
|
||||
_ = Logger.Log($"Running Rclone command: {logcmd}");
|
||||
|
||||
rclone.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "rclone", "rclone.exe");
|
||||
rclone.StartInfo.Arguments = command;
|
||||
rclone.StartInfo.RedirectStandardInput = true;
|
||||
rclone.StartInfo.RedirectStandardError = true;
|
||||
rclone.StartInfo.RedirectStandardOutput = true;
|
||||
rclone.StartInfo.WorkingDirectory = Environment.CurrentDirectory + "\\rclone";
|
||||
rclone.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "rclone");
|
||||
rclone.StartInfo.CreateNoWindow = true;
|
||||
//On debug we want to see when rclone is open
|
||||
if (MainForm.debugMode == true)
|
||||
|
||||
setRcloneProxy();
|
||||
|
||||
// Display RCLONE Window if the binary is being run in Debug Mode.
|
||||
if (MainForm.debugMode)
|
||||
{
|
||||
rclone.StartInfo.CreateNoWindow = false;
|
||||
}
|
||||
rclone.StartInfo.UseShellExecute = false;
|
||||
rclone.Start();
|
||||
_ = rclone.Start();
|
||||
rclone.StandardInput.WriteLine(command);
|
||||
rclone.StandardInput.Flush();
|
||||
rclone.StandardInput.Close();
|
||||
|
||||
string output = rclone.StandardOutput.ReadToEnd();
|
||||
string error = rclone.StandardError.ReadToEnd();
|
||||
rclone.WaitForExit();
|
||||
|
||||
//if there is one of these errors, we switch the mirrors
|
||||
if (error.Contains("There is not enough space"))
|
||||
{
|
||||
Program.form.Invoke(() =>
|
||||
{
|
||||
_ = FlexibleMessageBox.Show(Program.form, $"There isn't enough disk space to download this game.\r\nPlease ensure you have at least 200MB more the game size available in {settings.DownloadDir} and try again.",
|
||||
"NOT ENOUGH SPACE",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
});
|
||||
return new ProcessOutput("Download failed.", "");
|
||||
}
|
||||
|
||||
// Switch mirror upon matching error output.
|
||||
if (error.Contains("400 Bad Request") || error.Contains("cannot fetch token") || error.Contains("authError") || error.Contains("quota") || error.Contains("exceeded") || error.Contains("directory not found") || error.Contains("Failed to"))
|
||||
{
|
||||
string oldRemote = MainForm.currentRemote;
|
||||
bool retSM = false;
|
||||
try
|
||||
{
|
||||
Program.form.SwitchMirrors();
|
||||
|
||||
retSM = Program.form.SwitchMirrors();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ProcessOutput("All mirrors are on quota or down...", "All mirrors are on quota or down...");
|
||||
}
|
||||
prcoutput = runRcloneCommand_DownloadConfig(originalCommand.Replace(oldRemote, MainForm.currentRemote), bandwithLimit);
|
||||
if (retSM)
|
||||
{
|
||||
prcoutput = runRcloneCommand_DownloadConfig(originalCommand.Replace(oldRemote, MainForm.currentRemote));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -114,67 +162,61 @@ namespace AndroidSideloader
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
Logger.Log($"Rclone error: {error}\n");
|
||||
_ = Logger.Log($"Rclone error: {error}\n", LogLevel.ERROR);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
Logger.Log($"Rclone Output: {output}");
|
||||
_ = Logger.Log($"Rclone Output: {output}");
|
||||
}
|
||||
}
|
||||
|
||||
if (output.Contains("There is not enough space"))
|
||||
{
|
||||
FlexibleMessageBox.Show("There isn't enough space on your PC to properly install this game. Please have at least 2x the size of the game you are trying to download/install available on the drive where Rookie is installed.", "NOT ENOUGH SPACE");
|
||||
}
|
||||
return prcoutput;
|
||||
}
|
||||
|
||||
public static ProcessOutput runRcloneCommand_UploadConfig(string command, string bandwithLimit = "")
|
||||
public static ProcessOutput runRcloneCommand_UploadConfig(string command)
|
||||
{
|
||||
if (!MainForm.HasInternet || MainForm.isOffline)
|
||||
{
|
||||
return new ProcessOutput("", "No internet");
|
||||
}
|
||||
|
||||
ProcessOutput prcoutput = new ProcessOutput();
|
||||
//Rclone output is unicode, else it will show garbage instead of unicode characters
|
||||
// Rclone output is unicode, else it will show garbage instead of unicode characters
|
||||
rclone.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||
string originalCommand = command;
|
||||
|
||||
//set bandwidth limit
|
||||
if (bandwithLimit.Length > 0)
|
||||
{
|
||||
command += $" --bwlimit={bandwithLimit}";
|
||||
}
|
||||
|
||||
//set configpath if there is any
|
||||
// set configpath if there is any
|
||||
if (uploadConfigPath.Length > 0)
|
||||
{
|
||||
command += $" --config {uploadConfigPath}";
|
||||
}
|
||||
|
||||
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
|
||||
if (logcmd.Contains($"\"{Properties.Settings.Default.CurrentLogPath}\""))
|
||||
logcmd = logcmd.Replace($"\"{Properties.Settings.Default.CurrentLogPath}\"", $"\"{Properties.Settings.Default.CurrentLogName}\"");
|
||||
if (logcmd.Contains($"\"{settings.CurrentLogPath}\""))
|
||||
{
|
||||
logcmd = logcmd.Replace($"\"{settings.CurrentLogPath}\"", $"\"{settings.CurrentLogName}\"");
|
||||
}
|
||||
|
||||
if (logcmd.Contains(Environment.CurrentDirectory))
|
||||
{
|
||||
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
|
||||
Logger.Log($"Running Rclone command: {logcmd}");
|
||||
}
|
||||
|
||||
command += " --checkers 0 --no-check-dest --retries 1";
|
||||
_ = Logger.Log($"Running Rclone command: {logcmd}");
|
||||
|
||||
rclone.StartInfo.FileName = Environment.CurrentDirectory + "\\rclone\\rclone.exe";
|
||||
command += " --checkers 1 --retries 2 --inplace";
|
||||
|
||||
rclone.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "rclone", "rclone.exe");
|
||||
rclone.StartInfo.Arguments = command;
|
||||
rclone.StartInfo.RedirectStandardInput = true;
|
||||
rclone.StartInfo.RedirectStandardError = true;
|
||||
rclone.StartInfo.RedirectStandardOutput = true;
|
||||
rclone.StartInfo.WorkingDirectory = Environment.CurrentDirectory + "\\rclone";
|
||||
rclone.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "rclone");
|
||||
rclone.StartInfo.CreateNoWindow = true;
|
||||
//On debug we want to see when rclone is open
|
||||
if (MainForm.debugMode == true)
|
||||
|
||||
setRcloneProxy();
|
||||
|
||||
// Display RCLONE Window if the binary is being run in Debug Mode.
|
||||
if (MainForm.debugMode)
|
||||
{
|
||||
rclone.StartInfo.CreateNoWindow = false;
|
||||
}
|
||||
rclone.StartInfo.UseShellExecute = false;
|
||||
rclone.Start();
|
||||
_ = rclone.Start();
|
||||
rclone.StandardInput.WriteLine(command);
|
||||
rclone.StandardInput.Flush();
|
||||
rclone.StandardInput.Close();
|
||||
@@ -183,10 +225,10 @@ namespace AndroidSideloader
|
||||
string error = rclone.StandardError.ReadToEnd();
|
||||
rclone.WaitForExit();
|
||||
|
||||
//if there is one of these errors, we switch the mirrors
|
||||
// if there is one of these errors, we switch the mirrors
|
||||
if (error.Contains("400 Bad Request") || error.Contains("cannot fetch token") || error.Contains("authError") || error.Contains("quota") || error.Contains("exceeded") || error.Contains("directory not found") || error.Contains("Failed to"))
|
||||
{
|
||||
Logger.Log(error);
|
||||
_ = Logger.Log(error, LogLevel.ERROR);
|
||||
return new ProcessOutput("Upload Failed.", "Upload failed.");
|
||||
}
|
||||
else
|
||||
@@ -199,64 +241,62 @@ namespace AndroidSideloader
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
Logger.Log($"Rclone error: {error}\n");
|
||||
_ = Logger.Log($"Rclone error: {error}\n", LogLevel.ERROR);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
Logger.Log($"Rclone Output: {output}");
|
||||
_ = Logger.Log($"Rclone Output: {output}");
|
||||
}
|
||||
}
|
||||
|
||||
if (output.Contains("There is not enough space"))
|
||||
{
|
||||
FlexibleMessageBox.Show("There isn't enough space on your PC to properly install this game. Please have at least 2x the size of the game you are trying to download/install available on the drive where Rookie is installed.", "NOT ENOUGH SPACE");
|
||||
}
|
||||
return prcoutput;
|
||||
}
|
||||
|
||||
public static ProcessOutput runRcloneCommand_PublicConfig(string command, string bandwithLimit = "")
|
||||
public static ProcessOutput runRcloneCommand_PublicConfig(string command)
|
||||
{
|
||||
if (!MainForm.HasInternet || MainForm.isOffline)
|
||||
if (MainForm.isOffline)
|
||||
{
|
||||
return new ProcessOutput("", "No internet");
|
||||
}
|
||||
|
||||
ProcessOutput prcoutput = new ProcessOutput();
|
||||
//Rclone output is unicode, else it will show garbage instead of unicode characters
|
||||
// Rclone output is unicode, else it will show garbage instead of unicode characters
|
||||
rclone.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||
string originalCommand = command;
|
||||
|
||||
//set bandwidth limit
|
||||
if (bandwithLimit.Length > 0)
|
||||
{
|
||||
command += $" --bwlimit={bandwithLimit}";
|
||||
}
|
||||
|
||||
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
|
||||
if (logcmd.Contains($"\"{Properties.Settings.Default.CurrentLogPath}\""))
|
||||
logcmd = logcmd.Replace($"\"{Properties.Settings.Default.CurrentLogPath}\"", $"\"{Properties.Settings.Default.CurrentLogName}\"");
|
||||
if (logcmd.Contains($"\"{settings.CurrentLogPath}\""))
|
||||
{
|
||||
logcmd = logcmd.Replace($"\"{settings.CurrentLogPath}\"", $"\"{settings.CurrentLogName}\"");
|
||||
}
|
||||
|
||||
if (logcmd.Contains(Environment.CurrentDirectory))
|
||||
{
|
||||
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
|
||||
Logger.Log($"Running Rclone command: {logcmd}");
|
||||
}
|
||||
|
||||
command += $" --inplace";
|
||||
|
||||
_ = Logger.Log($"Running Rclone command: {logcmd}");
|
||||
|
||||
//set http source & args
|
||||
command += $" --http-url {MainForm.PublicConfigFile.BaseUri} {MainForm.PublicMirrorExtraArgs}";
|
||||
|
||||
rclone.StartInfo.FileName = Environment.CurrentDirectory + "\\rclone\\rclone.exe";
|
||||
rclone.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "rclone", "rclone.exe");
|
||||
rclone.StartInfo.Arguments = command;
|
||||
rclone.StartInfo.RedirectStandardInput = true;
|
||||
rclone.StartInfo.RedirectStandardError = true;
|
||||
rclone.StartInfo.RedirectStandardOutput = true;
|
||||
rclone.StartInfo.WorkingDirectory = Environment.CurrentDirectory + "\\rclone";
|
||||
rclone.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "rclone");
|
||||
rclone.StartInfo.CreateNoWindow = true;
|
||||
|
||||
//On debug we want to see when rclone is open
|
||||
if (MainForm.debugMode == true)
|
||||
rclone.StartInfo.CreateNoWindow = false;
|
||||
setRcloneProxy();
|
||||
|
||||
// Display RCLONE Window if the binary is being run in Debug Mode.
|
||||
if (MainForm.debugMode)
|
||||
{
|
||||
rclone.StartInfo.CreateNoWindow = false;
|
||||
}
|
||||
rclone.StartInfo.UseShellExecute = false;
|
||||
rclone.Start();
|
||||
_ = rclone.Start();
|
||||
rclone.StandardInput.WriteLine(command);
|
||||
rclone.StandardInput.Flush();
|
||||
rclone.StandardInput.Close();
|
||||
@@ -265,10 +305,32 @@ namespace AndroidSideloader
|
||||
string error = rclone.StandardError.ReadToEnd();
|
||||
rclone.WaitForExit();
|
||||
|
||||
//if there is one of these errors, we switch the mirrors
|
||||
if (error.Contains("400 Bad Request") || error.Contains("cannot fetch token") || error.Contains("authError") || error.Contains("quota") || error.Contains("exceeded") || error.Contains("directory not found") || error.Contains("Failed to"))
|
||||
if (error.Contains("There is not enough space"))
|
||||
{
|
||||
Logger.Log(error);
|
||||
Program.form.Invoke(() =>
|
||||
{
|
||||
_ = FlexibleMessageBox.Show(Program.form, $"There isn't enough disk space to download this game.\r\nPlease ensure you have at least 2x the game size available in {settings.DownloadDir} and try again.",
|
||||
"NOT ENOUGH SPACE",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
});
|
||||
return new ProcessOutput("Download failed.", string.Empty);
|
||||
}
|
||||
|
||||
if (error.Contains("Only one usage of each socket address (protocol/network address/port) is normally permitted"))
|
||||
{
|
||||
_ = Logger.Log(error, LogLevel.ERROR);
|
||||
return new ProcessOutput("Failed to fetch from public mirror.", "Failed to fetch from public mirror.\nYou may have a running RCLONE Task!\nCheck your Task Manager, Sort by Network Usage, and kill the process Rsync for Cloud Storage/Rclone");
|
||||
}
|
||||
else if (error.Contains("400 Bad Request")
|
||||
|| error.Contains("cannot fetch token")
|
||||
|| error.Contains("authError")
|
||||
|| error.Contains("quota")
|
||||
|| error.Contains("exceeded")
|
||||
|| error.Contains("directory not found")
|
||||
|| error.Contains("Failed to"))
|
||||
{
|
||||
_ = Logger.Log(error, LogLevel.ERROR);
|
||||
return new ProcessOutput("Failed to fetch from public mirror.", "Failed to fetch from public mirror.");
|
||||
}
|
||||
else
|
||||
@@ -281,20 +343,49 @@ namespace AndroidSideloader
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
Logger.Log($"Rclone error: {error}\n");
|
||||
_ = Logger.Log($"Rclone error: {error}\n", LogLevel.ERROR);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
Logger.Log($"Rclone Output: {output}");
|
||||
_ = Logger.Log($"Rclone Output: {output}");
|
||||
}
|
||||
}
|
||||
|
||||
if (output.Contains("There is not enough space"))
|
||||
{
|
||||
FlexibleMessageBox.Show("There isn't enough space on your PC to properly install this game. Please have at least 2x the size of the game you are trying to download/install available on the drive where Rookie is installed.", "NOT ENOUGH SPACE");
|
||||
}
|
||||
return prcoutput;
|
||||
}
|
||||
|
||||
private static void setRcloneProxy()
|
||||
{
|
||||
// Use the user's proxy settings if set, otherwise fallback to DNS fallback proxy if active
|
||||
string proxyUrl = DnsHelper.ProxyUrl;
|
||||
|
||||
if (settings.useProxy)
|
||||
{
|
||||
// Use user's configured proxy
|
||||
var url = $"http://{settings.ProxyAddress}:{settings.ProxyPort}";
|
||||
rclone.StartInfo.EnvironmentVariables["HTTP_PROXY"] = url;
|
||||
rclone.StartInfo.EnvironmentVariables["HTTPS_PROXY"] = url;
|
||||
rclone.StartInfo.EnvironmentVariables["http_proxy"] = url;
|
||||
rclone.StartInfo.EnvironmentVariables["https_proxy"] = url;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(proxyUrl))
|
||||
{
|
||||
// Use our DNS-resolving proxy
|
||||
rclone.StartInfo.EnvironmentVariables["HTTP_PROXY"] = proxyUrl;
|
||||
rclone.StartInfo.EnvironmentVariables["HTTPS_PROXY"] = proxyUrl;
|
||||
rclone.StartInfo.EnvironmentVariables["http_proxy"] = proxyUrl;
|
||||
rclone.StartInfo.EnvironmentVariables["https_proxy"] = proxyUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No proxy
|
||||
rclone.StartInfo.EnvironmentVariables.Remove("HTTP_PROXY");
|
||||
rclone.StartInfo.EnvironmentVariables.Remove("HTTPS_PROXY");
|
||||
rclone.StartInfo.EnvironmentVariables.Remove("http_proxy");
|
||||
rclone.StartInfo.EnvironmentVariables.Remove("https_proxy");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
README.md
@@ -1,15 +1,33 @@
|
||||
# androidsideloader
|
||||

|
||||

|
||||
[](https://github.com/nerdunit/androidsideloader/releases)
|
||||

|
||||
# AndroidSideloader
|
||||
|
||||
androidsideloader uses the GPL license, any forks of it must have their source code made public on the internet.
|
||||

|
||||

|
||||
[](https://github.com/VRPirates/rookie/releases)
|
||||

|
||||
|
||||
## !IMPORTANT!
|
||||
## Disclaimer
|
||||
This application might get flagged as malware by some antivirus software; however, both the Sideloader and the Sideloader Launcher are open source.
|
||||
|
||||
This app may be buggy and have problems.
|
||||
To run properly, Rookie must be extracted to a non-Protected folder on your drive. We recommend running Rookie from C:\RSL\Rookie
|
||||
Do Not use folders such as- C:\Users; C:\Users\Desktop; C:\Program Files; OneDrive; Google Drive; etc...
|
||||
Rookie will cleanup its own folder. We are not responsible if you run Rookie from a folder containing other files as Rookie may delete them.
|
||||
|
||||
### This app might get detected as malware, however both the sideloader and the sideloader launcher are open source. And obviously, it isn't.
|
||||
See:
|
||||
https://www.virustotal.com/gui/file/977105693610cf360fc29339b918e224180ba393ba05a64b6255af3845cbf376/relations
|
||||
|
||||
## Support
|
||||
For any assistance or questions, please utilize our support channels available at [Live Chats](https://vrpirates.wiki/en/general_information/live-chats).
|
||||
|
||||
## Build Instructions
|
||||
This project is developed using C# with WinForms targeting the .NET Framework 4.5.2. To build the project successfully in Visual Studio 2022, follow these steps:
|
||||
|
||||
1. Clone this repository to your local machine.
|
||||
2. Ensure you have the .NET Framework 4.5.2 installed on your machine.
|
||||
3. Open the solution file (`*.sln`) in Visual Studio 2022.
|
||||
4. Sometimes the building process can fail due to the packages.config, you should migrate it to PackageReference, do this by right clicking on References in the Solution Explorer, and pressing "Migrate packages.config to PackageReference"
|
||||
5. Build the solution by selecting "Build" > "Build Solution" from the Visual Studio menu or pressing `Ctrl + Shift + B`. (or right click the solution in the solution explorer, then press Build)
|
||||
6. Run the application.
|
||||
|
||||
## Contributing
|
||||
We welcome contributions from the community. If you would like to contribute, please fork the repository, branch from the newest beta branch from this repository, make your changes, and submit a pull request.
|
||||
|
||||
## License
|
||||
AndroidSideloader is distributed under the GPL license, meaning any forks of it must have their source code made public on the internet. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
6801
Resources/nouns.txt
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 476 B |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 15 KiB |
156
RoundButton.cs
@@ -10,19 +10,16 @@ namespace AndroidSideloader
|
||||
public class RoundButton : Control, IButtonControl
|
||||
{
|
||||
#region Variables
|
||||
int radius;
|
||||
bool transparency;
|
||||
MouseState state;
|
||||
RoundedRectangleF roundedRect;
|
||||
Color inactive1, inactive2, active1, active2;
|
||||
private int radius;
|
||||
private MouseState state;
|
||||
private RoundedRectangleF roundedRect;
|
||||
private Color inactive1, inactive2, active1, active2;
|
||||
private Color strokeColor;
|
||||
private bool stroke;
|
||||
internal bool UseVisualStyleBackColor;
|
||||
internal FlatStyle FlatStyle;
|
||||
|
||||
public bool Stroke
|
||||
{
|
||||
get { return stroke; }
|
||||
get => stroke;
|
||||
set
|
||||
{
|
||||
stroke = value;
|
||||
@@ -32,13 +29,46 @@ namespace AndroidSideloader
|
||||
|
||||
public Color StrokeColor
|
||||
{
|
||||
get { return strokeColor; }
|
||||
get => strokeColor;
|
||||
set
|
||||
{
|
||||
strokeColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private Color disabled1, disabled2;
|
||||
private Color disabledStrokeColor;
|
||||
|
||||
public Color Disabled1
|
||||
{
|
||||
get => disabled1;
|
||||
set
|
||||
{
|
||||
disabled1 = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public Color Disabled2
|
||||
{
|
||||
get => disabled2;
|
||||
set
|
||||
{
|
||||
disabled2 = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public Color DisabledStrokeColor
|
||||
{
|
||||
get => disabledStrokeColor;
|
||||
set
|
||||
{
|
||||
disabledStrokeColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region RoundButton
|
||||
public RoundButton()
|
||||
@@ -51,7 +81,9 @@ namespace AndroidSideloader
|
||||
inactive2 = Color.FromArgb(33, 167, 188);
|
||||
active1 = Color.FromArgb(64, 168, 183);
|
||||
active2 = Color.FromArgb(36, 164, 183);
|
||||
|
||||
disabled1 = Color.FromArgb(32, 35, 45);
|
||||
disabled2 = Color.FromArgb(25, 28, 35);
|
||||
disabledStrokeColor = Color.FromArgb(50, 55, 65);
|
||||
|
||||
radius = 10;
|
||||
roundedRect = new RoundedRectangleF(Width, Height, radius);
|
||||
@@ -63,21 +95,23 @@ namespace AndroidSideloader
|
||||
ForeColor = Color.Black;
|
||||
Font = new System.Drawing.Font("Comic Sans MS", 10, FontStyle.Bold);
|
||||
state = MouseState.Leave;
|
||||
transparency = false;
|
||||
Transparency = false;
|
||||
}
|
||||
#endregion
|
||||
#region Events
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
#region Transparency
|
||||
if (transparency)
|
||||
if (Transparency)
|
||||
{
|
||||
Transparenter.MakeTransparent(this, e.Graphics);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Drawing
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
roundedRect = new RoundedRectangleF(Width, Height, radius);
|
||||
e.Graphics.FillRectangle(Brushes.Transparent, this.ClientRectangle);
|
||||
e.Graphics.FillRectangle(Brushes.Transparent, ClientRectangle);
|
||||
|
||||
int R1 = (active1.R + inactive1.R) / 2;
|
||||
int G1 = (active1.G + inactive1.G) / 2;
|
||||
@@ -89,30 +123,53 @@ namespace AndroidSideloader
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, Width, Height);
|
||||
|
||||
if (this.Enabled)
|
||||
if (Enabled)
|
||||
{
|
||||
if (state == MouseState.Leave)
|
||||
{
|
||||
using (LinearGradientBrush inactiveGB = new LinearGradientBrush(rect, inactive1, inactive2, 90f))
|
||||
{
|
||||
e.Graphics.FillPath(inactiveGB, roundedRect.Path);
|
||||
}
|
||||
}
|
||||
else if (state == MouseState.Enter)
|
||||
{
|
||||
using (LinearGradientBrush activeGB = new LinearGradientBrush(rect, active1, active2, 90f))
|
||||
{
|
||||
e.Graphics.FillPath(activeGB, roundedRect.Path);
|
||||
}
|
||||
}
|
||||
else if (state == MouseState.Down)
|
||||
{
|
||||
using (LinearGradientBrush downGB = new LinearGradientBrush(rect, Color.FromArgb(R1, G1, B1), Color.FromArgb(R2, G2, B2), 90f))
|
||||
{
|
||||
e.Graphics.FillPath(downGB, roundedRect.Path);
|
||||
}
|
||||
}
|
||||
|
||||
if (stroke)
|
||||
{
|
||||
using (Pen pen = new Pen(strokeColor, 1))
|
||||
using (GraphicsPath path = new RoundedRectangleF(Width - (radius > 0 ? 0 : 1), Height - (radius > 0 ? 0 : 1), radius).Path)
|
||||
{
|
||||
e.Graphics.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Color linear1 = Color.FromArgb(190, 190, 190);
|
||||
Color linear2 = Color.FromArgb(210, 210, 210);
|
||||
using (LinearGradientBrush inactiveGB = new LinearGradientBrush(rect, linear1, linear2, 90f))
|
||||
using (LinearGradientBrush disabledGB = new LinearGradientBrush(rect, disabled1, disabled2, 90f))
|
||||
{
|
||||
e.Graphics.FillPath(inactiveGB, roundedRect.Path);
|
||||
e.Graphics.DrawPath(new Pen(inactiveGB), roundedRect.Path);
|
||||
e.Graphics.FillPath(disabledGB, roundedRect.Path);
|
||||
}
|
||||
|
||||
if (stroke)
|
||||
{
|
||||
using (Pen pen = new Pen(disabledStrokeColor, 1))
|
||||
using (GraphicsPath path = new RoundedRectangleF(Width - (radius > 0 ? 0 : 1), Height - (radius > 0 ? 0 : 1), radius).Path)
|
||||
{
|
||||
e.Graphics.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +183,9 @@ namespace AndroidSideloader
|
||||
Alignment = StringAlignment.Center,
|
||||
})
|
||||
using (Brush brush = new SolidBrush(ForeColor))
|
||||
e.Graphics.DrawString(Text, Font, brush, this.ClientRectangle, sf);
|
||||
{
|
||||
e.Graphics.DrawString(Text, Font, brush, ClientRectangle, sf);
|
||||
}
|
||||
#endregion
|
||||
base.OnPaint(e);
|
||||
}
|
||||
@@ -172,7 +231,10 @@ namespace AndroidSideloader
|
||||
protected override void OnMouseUp(MouseEventArgs e)
|
||||
{
|
||||
if (state != MouseState.Leave)
|
||||
{
|
||||
state = MouseState.Enter;
|
||||
}
|
||||
|
||||
base.OnMouseUp(e);
|
||||
Invalidate();
|
||||
}
|
||||
@@ -182,10 +244,7 @@ namespace AndroidSideloader
|
||||
|
||||
public int Radius
|
||||
{
|
||||
get
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
get => radius;
|
||||
set
|
||||
{
|
||||
radius = value;
|
||||
@@ -194,10 +253,7 @@ namespace AndroidSideloader
|
||||
}
|
||||
public Color Inactive1
|
||||
{
|
||||
get
|
||||
{
|
||||
return inactive1;
|
||||
}
|
||||
get => inactive1;
|
||||
set
|
||||
{
|
||||
inactive1 = value;
|
||||
@@ -206,10 +262,7 @@ namespace AndroidSideloader
|
||||
}
|
||||
public Color Inactive2
|
||||
{
|
||||
get
|
||||
{
|
||||
return inactive2;
|
||||
}
|
||||
get => inactive2;
|
||||
set
|
||||
{
|
||||
inactive2 = value;
|
||||
@@ -218,10 +271,7 @@ namespace AndroidSideloader
|
||||
}
|
||||
public Color Active1
|
||||
{
|
||||
get
|
||||
{
|
||||
return active1;
|
||||
}
|
||||
get => active1;
|
||||
set
|
||||
{
|
||||
active1 = value;
|
||||
@@ -230,33 +280,17 @@ namespace AndroidSideloader
|
||||
}
|
||||
public Color Active2
|
||||
{
|
||||
get
|
||||
{
|
||||
return active2;
|
||||
}
|
||||
get => active2;
|
||||
set
|
||||
{
|
||||
active2 = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
public bool Transparency
|
||||
{
|
||||
get
|
||||
{
|
||||
return transparency;
|
||||
}
|
||||
set
|
||||
{
|
||||
transparency = value;
|
||||
}
|
||||
}
|
||||
public bool Transparency { get; set; }
|
||||
public override string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Text;
|
||||
}
|
||||
get => base.Text;
|
||||
set
|
||||
{
|
||||
base.Text = value;
|
||||
@@ -265,10 +299,7 @@ namespace AndroidSideloader
|
||||
}
|
||||
public override Color ForeColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.ForeColor;
|
||||
}
|
||||
get => base.ForeColor;
|
||||
set
|
||||
{
|
||||
base.ForeColor = value;
|
||||
@@ -278,10 +309,7 @@ namespace AndroidSideloader
|
||||
|
||||
public DialogResult DialogResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.Windows.Forms.DialogResult.OK;
|
||||
}
|
||||
get => System.Windows.Forms.DialogResult.OK;
|
||||
set
|
||||
{
|
||||
}
|
||||
|
||||
@@ -5,69 +5,44 @@ namespace AndroidSideloader
|
||||
{
|
||||
public class RoundedRectangleF
|
||||
{
|
||||
|
||||
Point location;
|
||||
float radius;
|
||||
GraphicsPath grPath;
|
||||
float x, y;
|
||||
float width, height;
|
||||
private Point location;
|
||||
private readonly float x, y;
|
||||
private readonly float width, height;
|
||||
|
||||
|
||||
public RoundedRectangleF(float width, float height, float radius, float x = 0, float y = 0)
|
||||
{
|
||||
|
||||
location = new Point(0, 0);
|
||||
this.radius = radius;
|
||||
Radius = radius;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
grPath = new GraphicsPath();
|
||||
Path = new GraphicsPath();
|
||||
if (radius <= 0)
|
||||
{
|
||||
grPath.AddRectangle(new RectangleF(x, y, width, height));
|
||||
Path.AddRectangle(new RectangleF(x, y, width, height));
|
||||
return;
|
||||
}
|
||||
RectangleF upperLeftRect = new RectangleF(x, y, 2 * radius, 2 * radius);
|
||||
RectangleF upperRightRect = new RectangleF(width - 2 * radius - 1, x, 2 * radius, 2 * radius);
|
||||
RectangleF lowerLeftRect = new RectangleF(x, height - 2 * radius - 1, 2 * radius, 2 * radius);
|
||||
RectangleF lowerRightRect = new RectangleF(width - 2 * radius - 1, height - 2 * radius - 1, 2 * radius, 2 * radius);
|
||||
RectangleF upperRightRect = new RectangleF(width - (2 * radius) - 1, x, 2 * radius, 2 * radius);
|
||||
RectangleF lowerLeftRect = new RectangleF(x, height - (2 * radius) - 1, 2 * radius, 2 * radius);
|
||||
RectangleF lowerRightRect = new RectangleF(width - (2 * radius) - 1, height - (2 * radius) - 1, 2 * radius, 2 * radius);
|
||||
|
||||
grPath.AddArc(upperLeftRect, 180, 90);
|
||||
grPath.AddArc(upperRightRect, 270, 90);
|
||||
grPath.AddArc(lowerRightRect, 0, 90);
|
||||
grPath.AddArc(lowerLeftRect, 90, 90);
|
||||
grPath.CloseAllFigures();
|
||||
Path.AddArc(upperLeftRect, 180, 90);
|
||||
Path.AddArc(upperRightRect, 270, 90);
|
||||
Path.AddArc(lowerRightRect, 0, 90);
|
||||
Path.AddArc(lowerLeftRect, 90, 90);
|
||||
Path.CloseAllFigures();
|
||||
|
||||
}
|
||||
public RoundedRectangleF()
|
||||
{
|
||||
}
|
||||
public GraphicsPath Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return grPath;
|
||||
}
|
||||
}
|
||||
public RectangleF Rect
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RectangleF(x, y, width, height);
|
||||
}
|
||||
}
|
||||
public float Radius
|
||||
{
|
||||
get
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
set
|
||||
{
|
||||
radius = value;
|
||||
}
|
||||
}
|
||||
public GraphicsPath Path { get; }
|
||||
public RectangleF Rect => new RectangleF(x, y, width, height);
|
||||
public float Radius { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -14,19 +14,18 @@ namespace AndroidSideloader
|
||||
{
|
||||
private string _initialDirectory;
|
||||
private string _title;
|
||||
private string _fileName = "";
|
||||
|
||||
public string InitialDirectory
|
||||
{
|
||||
get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
|
||||
set { _initialDirectory = value; }
|
||||
get => string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory;
|
||||
set => _initialDirectory = value;
|
||||
}
|
||||
public string Title
|
||||
{
|
||||
get { return _title ?? "Select a folder"; }
|
||||
set { _title = value; }
|
||||
get => _title ?? "Select a folder";
|
||||
set => _title = value;
|
||||
}
|
||||
public string FileName { get { return _fileName; } }
|
||||
public string FileName { get; private set; } = "";
|
||||
|
||||
public bool Show() { return Show(IntPtr.Zero); }
|
||||
|
||||
@@ -34,10 +33,10 @@ namespace AndroidSideloader
|
||||
/// <returns>true if the user clicks OK</returns>
|
||||
public bool Show(IntPtr hWndOwner)
|
||||
{
|
||||
var result = Environment.OSVersion.Version.Major >= 6
|
||||
ShowDialogResult result = Environment.OSVersion.Version.Major >= 6
|
||||
? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
|
||||
: ShowXpDialog(hWndOwner, InitialDirectory, Title);
|
||||
_fileName = result.FileName;
|
||||
FileName = result.FileName;
|
||||
return result.Result;
|
||||
}
|
||||
|
||||
@@ -49,13 +48,13 @@ namespace AndroidSideloader
|
||||
|
||||
private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog
|
||||
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog
|
||||
{
|
||||
Description = title,
|
||||
SelectedPath = initialDirectory,
|
||||
ShowNewFolderButton = false
|
||||
};
|
||||
var dialogResult = new ShowDialogResult();
|
||||
ShowDialogResult dialogResult = new ShowDialogResult();
|
||||
if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK)
|
||||
{
|
||||
dialogResult.Result = true;
|
||||
@@ -69,26 +68,26 @@ namespace AndroidSideloader
|
||||
private const string c_foldersFilter = "Folders|\n";
|
||||
|
||||
private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
|
||||
private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
|
||||
private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
|
||||
private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
|
||||
private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
|
||||
private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
|
||||
private readonly static uint s_fosPickFoldersBitFlag = (uint)s_windowsFormsAssembly
|
||||
private static readonly Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
|
||||
private static readonly Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
|
||||
private static readonly MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
|
||||
private static readonly MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
|
||||
private static readonly MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
|
||||
private static readonly MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
|
||||
private static readonly uint s_fosPickFoldersBitFlag = (uint)s_windowsFormsAssembly
|
||||
.GetType("System.Windows.Forms.FileDialogNative+FOS")
|
||||
.GetField("FOS_PICKFOLDERS")
|
||||
.GetValue(null);
|
||||
private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
|
||||
private static readonly ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
|
||||
.GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
|
||||
.GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
|
||||
private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
|
||||
private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
|
||||
private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");
|
||||
private static readonly MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
|
||||
private static readonly MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
|
||||
private static readonly MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");
|
||||
|
||||
public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog
|
||||
OpenFileDialog openFileDialog = new OpenFileDialog
|
||||
{
|
||||
AddExtension = false,
|
||||
CheckFileExists = false,
|
||||
@@ -99,11 +98,11 @@ namespace AndroidSideloader
|
||||
Title = title
|
||||
};
|
||||
|
||||
var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
|
||||
s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
|
||||
s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint)s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
|
||||
var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
|
||||
s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);
|
||||
object iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
|
||||
_ = s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
|
||||
_ = s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint)s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
|
||||
object[] adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
|
||||
_ = s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -116,7 +115,7 @@ namespace AndroidSideloader
|
||||
}
|
||||
finally
|
||||
{
|
||||
s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
|
||||
_ = s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,9 +123,8 @@ namespace AndroidSideloader
|
||||
// Wrap an IWin32Window around an IntPtr
|
||||
private class WindowWrapper : IWin32Window
|
||||
{
|
||||
private readonly IntPtr _handle;
|
||||
public WindowWrapper(IntPtr handle) { _handle = handle; }
|
||||
public IntPtr Handle { get { return _handle; } }
|
||||
public WindowWrapper(IntPtr handle) { Handle = handle; }
|
||||
public IntPtr Handle { get; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
Settings.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace AndroidSideloader.Properties {
|
||||
|
||||
|
||||
// This class allows you to handle specific events on the settings class:
|
||||
// The SettingChanging event is raised before a setting's value is changed.
|
||||
// The PropertyChanged event is raised after a setting's value is changed.
|
||||
// The SettingsLoaded event is raised after the setting values are loaded.
|
||||
// The SettingsSaving event is raised before the setting values are saved.
|
||||
internal sealed partial class Settings {
|
||||
|
||||
public Settings() {
|
||||
// // To add event handlers for saving and changing settings, uncomment the lines below:
|
||||
//
|
||||
// this.SettingChanging += this.SettingChangingEventHandler;
|
||||
//
|
||||
// this.SettingsSaving += this.SettingsSavingEventHandler;
|
||||
//
|
||||
}
|
||||
|
||||
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
|
||||
// Add code to handle the SettingChangingEvent event here.
|
||||
}
|
||||
|
||||
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
|
||||
// Add code to handle the SettingsSaving event here.
|
||||
}
|
||||
}
|
||||
}
|
||||
1398
SettingsForm.Designer.cs
generated
635
SettingsForm.cs
@@ -1,235 +1,400 @@
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class SettingsForm : Form
|
||||
{
|
||||
public SettingsForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void SettingsForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
this.CenterToParent();
|
||||
if (!string.IsNullOrEmpty(Properties.Settings.Default.CurrentLogName))
|
||||
textBox1.Text = Properties.Settings.Default.CurrentCrashName;
|
||||
if (!string.IsNullOrEmpty(Properties.Settings.Default.CurrentLogPath))
|
||||
DebugID.Text = Properties.Settings.Default.CurrentLogName;
|
||||
debuglogID.Text = "This is your DebugLogID. Click on your DebugLogID to copy it to your clipboard.";
|
||||
intSettings();
|
||||
intToolTips();
|
||||
}
|
||||
|
||||
//Init form objects with values from settings
|
||||
private void intSettings()
|
||||
{
|
||||
checkForUpdatesCheckBox.Checked = Properties.Settings.Default.checkForUpdates;
|
||||
enableMessageBoxesCheckBox.Checked = Properties.Settings.Default.enableMessageBoxes;
|
||||
deleteAfterInstallCheckBox.Checked = Properties.Settings.Default.deleteAllAfterInstall;
|
||||
updateConfigCheckBox.Checked = Properties.Settings.Default.autoUpdateConfig;
|
||||
userJsonOnGameInstall.Checked = Properties.Settings.Default.userJsonOnGameInstall;
|
||||
nodevicemodeBox.Checked = Properties.Settings.Default.nodevicemode;
|
||||
bmbfBox.Checked = Properties.Settings.Default.BMBFchecked;
|
||||
AutoReinstBox.Checked = Properties.Settings.Default.AutoReinstall;
|
||||
|
||||
if (Properties.Settings.Default.BandwithLimit.Length > 1)
|
||||
{
|
||||
BandwithTextbox.Text = Properties.Settings.Default.BandwithLimit.Remove(Properties.Settings.Default.BandwithLimit.Length - 1);
|
||||
BandwithComboBox.Text = Properties.Settings.Default.BandwithLimit[Properties.Settings.Default.BandwithLimit.Length - 1].ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void intToolTips()
|
||||
{
|
||||
ToolTip checkForUpdatesToolTip = new ToolTip();
|
||||
checkForUpdatesToolTip.SetToolTip(this.checkForUpdatesCheckBox, "If this is checked, the software will check for available updates");
|
||||
ToolTip enableMessageBoxesToolTip = new ToolTip();
|
||||
enableMessageBoxesToolTip.SetToolTip(this.enableMessageBoxesCheckBox, "If this is checked, the software will display message boxes after every completed task");
|
||||
ToolTip deleteAfterInstallToolTip = new ToolTip();
|
||||
deleteAfterInstallToolTip.SetToolTip(this.deleteAfterInstallCheckBox, "If this is checked, the software will delete all game files after downloading and installing a game from a remote server");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void DebugLogCopy_click(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists($"{Properties.Settings.Default.CurrentLogPath}"))
|
||||
{
|
||||
RCLONE.runRcloneCommand_DownloadConfig($"copy \"{Properties.Settings.Default.CurrentLogPath}\" VRP-debuglogs:DebugLogs");
|
||||
Clipboard.SetText(DebugID.Text);
|
||||
MessageBox.Show($"Your debug log has been copied to the server. Please mention your DebugLog ID ({Properties.Settings.Default.CurrentLogName}) to the Mods (it has been automatically copied to your clipboard).");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void button1_click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
if (File.Exists($"{Properties.Settings.Default.CurrentLogPath}"))
|
||||
File.Delete($"{Properties.Settings.Default.CurrentLogPath}");
|
||||
if (File.Exists($"{Environment.CurrentDirectory}\\debuglog.txt"))
|
||||
File.Delete($"{Environment.CurrentDirectory}\\debuglog.txt");
|
||||
|
||||
|
||||
if (File.Exists($"{Environment.CurrentDirectory}\\nouns\\nouns.txt"))
|
||||
{
|
||||
string[] lines = File.ReadAllLines($"{Environment.CurrentDirectory}\\nouns\\nouns.txt");
|
||||
Random r = new Random();
|
||||
int x = r.Next(6806);
|
||||
int y = r.Next(6806);
|
||||
string randomnoun = lines[new Random(x).Next(lines.Length)];
|
||||
string randomnoun2 = lines[new Random(y).Next(lines.Length)];
|
||||
string combined = randomnoun + "-" + randomnoun2;
|
||||
Properties.Settings.Default.CurrentLogPath = Environment.CurrentDirectory + "\\" + combined + ".txt";
|
||||
Properties.Settings.Default.CurrentLogName = combined;
|
||||
Properties.Settings.Default.Save();
|
||||
DebugID.Text = combined;
|
||||
this.Close();
|
||||
SettingsForm Form = new SettingsForm();
|
||||
Form.Show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Apply settings
|
||||
private void applyButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (BandwithTextbox.Text.Length > 0 && BandwithTextbox.Text != "0")
|
||||
if (BandwithComboBox.SelectedIndex == -1)
|
||||
{
|
||||
FlexibleMessageBox.Show("You need to select something from the combobox");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Properties.Settings.Default.BandwithLimit = $"{BandwithTextbox.Text.Replace(" ", "")}{BandwithComboBox.Text}";
|
||||
}
|
||||
else
|
||||
Properties.Settings.Default.BandwithLimit = "";
|
||||
|
||||
Properties.Settings.Default.Save();
|
||||
FlexibleMessageBox.Show("Settings applied!");
|
||||
}
|
||||
|
||||
private void checkForUpdatesCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.checkForUpdates = checkForUpdatesCheckBox.Checked;
|
||||
}
|
||||
|
||||
private void enableMessageBoxesCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.enableMessageBoxes = enableMessageBoxesCheckBox.Checked;
|
||||
}
|
||||
|
||||
private void resetSettingsButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.Reset();
|
||||
intSettings();
|
||||
}
|
||||
|
||||
private void deleteAfterInstallCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.deleteAllAfterInstall = deleteAfterInstallCheckBox.Checked;
|
||||
}
|
||||
|
||||
private void updateConfigCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.autoUpdateConfig = updateConfigCheckBox.Checked;
|
||||
}
|
||||
|
||||
private void userJsonOnGameInstall_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.userJsonOnGameInstall = userJsonOnGameInstall.Checked;
|
||||
}
|
||||
|
||||
private void SettingsForm_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == (char)Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void SettingsForm_Leave(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
|
||||
private void Form_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
protected override bool ProcessDialogKey(Keys keyData)
|
||||
{
|
||||
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessDialogKey(keyData);
|
||||
}
|
||||
|
||||
private void DebugID_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists(Environment.CurrentDirectory + "\\" + Properties.Settings.Default.CurrentLogName + ".txt"))
|
||||
Clipboard.SetText(DebugID.Text);
|
||||
MessageBox.Show("DebugLogID copied to clipboard! Paste it to a moderator/helper for assistance!");
|
||||
}
|
||||
|
||||
private void textBox1_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Properties.Settings.Default.CurrentCrashName))
|
||||
{
|
||||
Clipboard.SetText(textBox1.Text);
|
||||
MessageBox.Show("CrashLogID copied to clipboard! Paste it to a moderator/helper for assistance!");
|
||||
}
|
||||
}
|
||||
|
||||
private void nodevicemodeBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.nodevicemode = nodevicemodeBox.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void bmbfBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.BMBFchecked = bmbfBox.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void AutoReinstBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.AutoReinstall = AutoReinstBox.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void AutoReinstBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (AutoReinstBox.Checked)
|
||||
{
|
||||
DialogResult dialogResult = FlexibleMessageBox.Show("WARNING: This box enables automatic reinstall when installs fail,\ndue to some games not allowing " +
|
||||
"access to their save data (less than 5%) this\noption can lead to losing your progress." +
|
||||
" However with this option\nchecked when installs fail you won't have to agree to a prompt to preform\nthe reinstall. " +
|
||||
"(ideal when installing from a queue).\n\nNOTE: If your usb/wireless adb connection is extremely slow this option can\ncause larger" +
|
||||
"apk file installations to fail. Enable anyway?", "WARNING", MessageBoxButtons.OKCancel);
|
||||
if (dialogResult == DialogResult.Cancel)
|
||||
AutoReinstBox.Checked = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using AndroidSideloader.Properties;
|
||||
using AndroidSideloader.Utilities;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class SettingsForm : Form
|
||||
{
|
||||
private static readonly SettingsManager _settings = SettingsManager.Instance;
|
||||
|
||||
public SettingsForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
}
|
||||
|
||||
private void SettingsForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
CenterToParent();
|
||||
initSettings();
|
||||
initToolTips();
|
||||
}
|
||||
|
||||
private void initSettings()
|
||||
{
|
||||
// Use SetCheckedSilent to avoid triggering events during initialization
|
||||
toggleCheckForUpdates.SetCheckedSilent(_settings.CheckForUpdates);
|
||||
toggleMessageBoxes.SetCheckedSilent(_settings.EnableMessageBoxes);
|
||||
toggleDeleteAfterInstall.SetCheckedSilent(_settings.DeleteAllAfterInstall);
|
||||
toggleUpdateConfig.SetCheckedSilent(_settings.AutoUpdateConfig);
|
||||
toggleUserJson.SetCheckedSilent(_settings.UserJsonOnGameInstall);
|
||||
toggleNoDeviceMode.SetCheckedSilent(_settings.NodeviceMode);
|
||||
toggleBMBF.SetCheckedSilent(_settings.BMBFChecked);
|
||||
toggleAutoReinstall.SetCheckedSilent(_settings.AutoReinstall);
|
||||
toggleSingleThread.SetCheckedSilent(_settings.SingleThreadMode);
|
||||
toggleVirtualFilesystem.SetCheckedSilent(_settings.VirtualFilesystemCompatibility);
|
||||
toggleUseDownloadedFiles.SetCheckedSilent(_settings.UseDownloadedFiles);
|
||||
toggleTrailers.SetCheckedSilent(_settings.TrailersEnabled);
|
||||
bandwidthLimitTextBox.Text = _settings.BandwidthLimit.ToString();
|
||||
|
||||
// Handle no device mode disabling delete after install
|
||||
if (toggleNoDeviceMode.Checked)
|
||||
{
|
||||
toggleDeleteAfterInstall.SetCheckedSilent(false);
|
||||
toggleDeleteAfterInstall.Enabled = false;
|
||||
lblDeleteAfterInstall.ForeColor = System.Drawing.Color.FromArgb(100, 100, 100);
|
||||
}
|
||||
|
||||
toggleProxy.Checked = _settings.useProxy;
|
||||
proxyAddressTextBox.Text = _settings.ProxyAddress;
|
||||
proxyPortTextBox.Text = _settings.ProxyPort;
|
||||
}
|
||||
|
||||
private void initToolTips()
|
||||
{
|
||||
ToolTip toolTip = new ToolTip();
|
||||
toolTip.SetToolTip(toggleCheckForUpdates, "Check for available application updates on startup");
|
||||
toolTip.SetToolTip(lblCheckForUpdates, "Check for available application updates on startup");
|
||||
toolTip.SetToolTip(toggleMessageBoxes, "Show message boxes after every completed task");
|
||||
toolTip.SetToolTip(lblMessageBoxes, "Show message boxes after every completed task");
|
||||
toolTip.SetToolTip(toggleDeleteAfterInstall, "Delete game files after downloading and installing");
|
||||
toolTip.SetToolTip(lblDeleteAfterInstall, "Delete game files after downloading and installing");
|
||||
toolTip.SetToolTip(toggleUseDownloadedFiles, "Always install downloaded files without prompting to re-download");
|
||||
toolTip.SetToolTip(lblUseDownloadedFiles, "Always install downloaded files without prompting to re-download");
|
||||
toolTip.SetToolTip(toggleTrailers, "Show game trailers when selecting a game");
|
||||
toolTip.SetToolTip(lblTrailers, "Show game trailers when selecting a game");
|
||||
}
|
||||
|
||||
private void SaveAllSettings()
|
||||
{
|
||||
string input = bandwidthLimitTextBox.Text;
|
||||
Regex regex = new Regex(@"^\d+(\.\d+)?$");
|
||||
|
||||
if (regex.IsMatch(input) && float.TryParse(input, out float bandwidthLimit))
|
||||
{
|
||||
_settings.BandwidthLimit = bandwidthLimit;
|
||||
}
|
||||
|
||||
_settings.CheckForUpdates = toggleCheckForUpdates.Checked;
|
||||
_settings.EnableMessageBoxes = toggleMessageBoxes.Checked;
|
||||
_settings.DeleteAllAfterInstall = toggleDeleteAfterInstall.Checked;
|
||||
_settings.AutoUpdateConfig = toggleUpdateConfig.Checked;
|
||||
_settings.UserJsonOnGameInstall = toggleUserJson.Checked;
|
||||
_settings.NodeviceMode = toggleNoDeviceMode.Checked;
|
||||
_settings.BMBFChecked = toggleBMBF.Checked;
|
||||
_settings.AutoReinstall = toggleAutoReinstall.Checked;
|
||||
_settings.SingleThreadMode = toggleSingleThread.Checked;
|
||||
_settings.VirtualFilesystemCompatibility = toggleVirtualFilesystem.Checked;
|
||||
_settings.UseDownloadedFiles = toggleUseDownloadedFiles.Checked;
|
||||
_settings.TrailersEnabled = toggleTrailers.Checked;
|
||||
_settings.useProxy = toggleProxy.Checked;
|
||||
|
||||
if (Program.form != null)
|
||||
{
|
||||
Program.form.SetTrailerVisibility(toggleTrailers.Checked);
|
||||
Program.form.UpdateSideloadingUI();
|
||||
}
|
||||
|
||||
if (_settings.AutoUpdateConfig)
|
||||
{
|
||||
_settings.CreatePubMirrorFile = true;
|
||||
}
|
||||
|
||||
_settings.Save();
|
||||
}
|
||||
|
||||
public void btnUploadDebug_click(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists($"{_settings.CurrentLogPath}"))
|
||||
{
|
||||
string UUID = SideloaderUtilities.UUID();
|
||||
string debugLogPath = $"{Environment.CurrentDirectory}\\{UUID}.log";
|
||||
System.IO.File.Copy("debuglog.txt", debugLogPath);
|
||||
|
||||
Clipboard.SetText(UUID);
|
||||
|
||||
_ = RCLONE.runRcloneCommand_UploadConfig($"copy \"{debugLogPath}\" RSL-gameuploads:DebugLogs");
|
||||
_ = MessageBox.Show($"Your debug log has been copied to the server. ID: {UUID}");
|
||||
}
|
||||
}
|
||||
|
||||
public void btnResetDebug_click(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists($"{_settings.CurrentLogPath}"))
|
||||
{
|
||||
File.Delete($"{_settings.CurrentLogPath}");
|
||||
}
|
||||
|
||||
if (File.Exists($"{Environment.CurrentDirectory}\\debuglog.txt"))
|
||||
{
|
||||
File.Delete($"{Environment.CurrentDirectory}\\debuglog.txt");
|
||||
}
|
||||
}
|
||||
|
||||
private void applyButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
// Parse bandwidth value
|
||||
var bandwidthInput = bandwidthLimitTextBox.Text;
|
||||
Regex regex = new Regex(@"^\d+(\.\d+)?$");
|
||||
|
||||
if (regex.IsMatch(bandwidthInput) && float.TryParse(bandwidthInput, out float bandwidthLimit))
|
||||
{
|
||||
_settings.BandwidthLimit = bandwidthLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Please enter a valid number for the bandwidth limit.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse proxy values if proxy is enabled
|
||||
if (toggleProxy.Checked)
|
||||
{
|
||||
// Parse proxy address
|
||||
var proxyAddressInput = proxyAddressTextBox.Text;
|
||||
|
||||
if (proxyAddressInput.StartsWith("http://"))
|
||||
{
|
||||
proxyAddressInput = proxyAddressInput.Substring("http://".Length);
|
||||
}
|
||||
else if (proxyAddressInput.StartsWith("https://"))
|
||||
{
|
||||
proxyAddressInput = proxyAddressInput.Substring("https://".Length);
|
||||
}
|
||||
|
||||
if (proxyAddressInput.Equals("localhost", StringComparison.OrdinalIgnoreCase) ||
|
||||
IPAddress.TryParse(proxyAddressInput, out _))
|
||||
{
|
||||
_settings.ProxyAddress = proxyAddressInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Please enter a valid address for the proxy.");
|
||||
}
|
||||
|
||||
// Parse proxy port
|
||||
var proxyPortInput = proxyPortTextBox.Text;
|
||||
|
||||
if (ushort.TryParse(proxyPortInput, out _))
|
||||
{
|
||||
_settings.ProxyPort = proxyPortInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Please enter a valid port for the proxy.");
|
||||
}
|
||||
}
|
||||
|
||||
SaveAllSettings();
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void toggleCheckForUpdates_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleUseDownloadedFiles_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleMessageBoxes_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleTrailers_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void resetSettingsButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void toggleDeleteAfterInstall_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleUpdateConfig_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleUserJson_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void SettingsForm_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == (char)Keys.Escape)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void SettingsForm_Leave(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Form_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ProcessDialogKey(Keys keyData)
|
||||
{
|
||||
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
|
||||
{
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessDialogKey(keyData);
|
||||
}
|
||||
|
||||
private void toggleNoDeviceMode_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Update UI state only - settings saved on form close
|
||||
if (!toggleNoDeviceMode.Checked)
|
||||
{
|
||||
toggleDeleteAfterInstall.Checked = true;
|
||||
toggleDeleteAfterInstall.Enabled = true;
|
||||
lblDeleteAfterInstall.ForeColor = System.Drawing.Color.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
toggleDeleteAfterInstall.SetCheckedSilent(false);
|
||||
toggleDeleteAfterInstall.Enabled = false;
|
||||
lblDeleteAfterInstall.ForeColor = System.Drawing.Color.FromArgb(100, 100, 100);
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleBMBF_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleAutoReinstall_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleAutoReinstall_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (toggleAutoReinstall.Checked)
|
||||
{
|
||||
DialogResult dialogResult = FlexibleMessageBox.Show(this,
|
||||
"WARNING: This enables automatic reinstall when installs fail.\n\n" +
|
||||
"Some games (less than 5%) don't allow access to their save data, " +
|
||||
"which can lead to losing your progress.\n\n" +
|
||||
"However, with this option enabled, you won't have to confirm reinstalls manually " +
|
||||
"(ideal for queue installations).\n\n" +
|
||||
"NOTE: If your USB/wireless ADB connection is slow, this may cause " +
|
||||
"larger APK installations to fail.\n\nEnable anyway?",
|
||||
"WARNING", MessageBoxButtons.OKCancel);
|
||||
|
||||
if (dialogResult == DialogResult.Cancel)
|
||||
{
|
||||
toggleAutoReinstall.SetCheckedSilent(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOpenDebug_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists($"{Environment.CurrentDirectory}\\debuglog.txt"))
|
||||
{
|
||||
_ = Process.Start($"{Environment.CurrentDirectory}\\debuglog.txt");
|
||||
}
|
||||
}
|
||||
|
||||
private void setDownloadDirectory_Click(object sender, EventArgs e)
|
||||
{
|
||||
var dialog = new FolderSelectDialog
|
||||
{
|
||||
Title = "Select Download Folder",
|
||||
InitialDirectory = _settings.CustomDownloadDir && Directory.Exists(_settings.DownloadDir)
|
||||
? _settings.DownloadDir
|
||||
: Environment.CurrentDirectory
|
||||
};
|
||||
|
||||
if (dialog.Show(this.Handle))
|
||||
{
|
||||
_settings.CustomDownloadDir = true;
|
||||
_settings.DownloadDir = dialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
private void setBackupDirectory_Click(object sender, EventArgs e)
|
||||
{
|
||||
var dialog = new FolderSelectDialog
|
||||
{
|
||||
Title = "Select Backup Folder",
|
||||
InitialDirectory = _settings.GetEffectiveBackupDir()
|
||||
};
|
||||
|
||||
if (dialog.Show(this.Handle))
|
||||
{
|
||||
_settings.CustomBackupDir = true;
|
||||
_settings.BackupDir = dialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleSingleThread_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void toggleVirtualFilesystem_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
|
||||
private void openDownloadDirectory_Click(object sender, EventArgs e)
|
||||
{
|
||||
string pathToOpen = _settings.CustomDownloadDir ? _settings.DownloadDir : Environment.CurrentDirectory;
|
||||
MainForm.OpenDirectory(pathToOpen);
|
||||
}
|
||||
|
||||
private void openBackupDirectory_Click(object sender, EventArgs e)
|
||||
{
|
||||
string pathToOpen = _settings.GetEffectiveBackupDir();
|
||||
MainForm.OpenDirectory(pathToOpen);
|
||||
}
|
||||
|
||||
private void bandwidthLimitTextBox_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.'))
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleProxy_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Settings saved on form close
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,4 +117,13 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="downloadDirectorySetter.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="backupDirectorySetter.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>186, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>25</value>
|
||||
</metadata>
|
||||
</root>
|
||||
574
Sideloader.cs
@@ -1,302 +1,272 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using JR.Utils.GUI.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class Sideloader
|
||||
{
|
||||
public static string TempFolder = Path.Combine(Environment.CurrentDirectory, "temp");
|
||||
public static string CrashLogPath = "crashlog.txt";
|
||||
|
||||
public static string SpooferWarning = @"Please make sure you have installed:
|
||||
- APKTool
|
||||
- Java JDK
|
||||
- aapt
|
||||
And all of them added to PATH, without ANY of them, the spoofer won't work!";
|
||||
|
||||
//push user.json to device (required for some devices like oculus quest)
|
||||
public static void PushUserJsons()
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
foreach (var userJson in UsernameForm.userJsons)
|
||||
{
|
||||
UsernameForm.createUserJsonByName(Utilities.GeneralUtilities.randomString(16), userJson);
|
||||
ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{userJson}\" " + " /sdcard/");
|
||||
File.Delete(userJson);
|
||||
}
|
||||
}
|
||||
|
||||
//List of all installed package names from connected device
|
||||
//public static List<string> InstalledPackageNames = new List<string>(); //Remove folder from device
|
||||
public static ProcessOutput RemoveFolder(string path)
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
return ADB.RunAdbCommandToString($"shell rm -r {path}");
|
||||
}
|
||||
public static ProcessOutput RemoveFile(string path)
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
return ADB.RunAdbCommandToString($"shell rm -f {path}");
|
||||
}
|
||||
|
||||
//For games that require manual install, like having another folder that isnt an obb
|
||||
public static ProcessOutput RunADBCommandsFromFile(string path)
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
ProcessOutput output = new ProcessOutput();
|
||||
var commands = File.ReadAllLines(path);
|
||||
string currfolder = Path.GetDirectoryName(path);
|
||||
string[] zipz = Directory.GetFiles(currfolder, "*.7z", SearchOption.AllDirectories);
|
||||
foreach (string zip in zipz)
|
||||
{
|
||||
Utilities.Zip.ExtractFile($"{zip}", currfolder);
|
||||
}
|
||||
foreach (string cmd in commands)
|
||||
{
|
||||
if (cmd.StartsWith("adb"))
|
||||
{
|
||||
string replacement = "";
|
||||
string pattern = "adb";
|
||||
if (ADB.DeviceID.Length > 1)
|
||||
replacement = $"{Properties.Settings.Default.ADBPath} -s {ADB.DeviceID}";
|
||||
else
|
||||
replacement = $"{Properties.Settings.Default.ADBPath}";
|
||||
Regex rgx = new Regex(pattern);
|
||||
string result = rgx.Replace(cmd, replacement);
|
||||
Program.form.ChangeTitle($"Running {result}");
|
||||
Logger.Log($"Logging command: {result} from file: {path}");
|
||||
output += ADB.RunAdbCommandToStringWOADB(result, path);
|
||||
if (output.Error.Contains("mkdir"))
|
||||
output.Error = "";
|
||||
if (output.Output.Contains("reserved"))
|
||||
output.Output = "";
|
||||
}
|
||||
}
|
||||
output.Output += "Custom install successful!";
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Recursive sideload any apk fileD
|
||||
public static ProcessOutput RecursiveOutput = new ProcessOutput();
|
||||
public static void RecursiveSideload(string FolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string f in Directory.GetFiles(FolderPath))
|
||||
{
|
||||
if (Path.GetExtension(f) == ".apk")
|
||||
|
||||
RecursiveOutput += ADB.Sideload(f);
|
||||
}
|
||||
|
||||
foreach (string d in Directory.GetDirectories(FolderPath))
|
||||
{
|
||||
RecursiveSideload(d);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { Logger.Log(ex.Message); }
|
||||
}
|
||||
|
||||
//Recursive copy any obb folder
|
||||
public static void RecursiveCopyOBB(string FolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string f in Directory.GetFiles(FolderPath))
|
||||
{
|
||||
RecursiveOutput += ADB.CopyOBB(f);
|
||||
}
|
||||
|
||||
foreach (string d in Directory.GetDirectories(FolderPath))
|
||||
{
|
||||
RecursiveCopyOBB(d);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { Logger.Log(ex.Message); }
|
||||
}
|
||||
public static string BackupFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), $"Rookie Backups");
|
||||
//uninstalls an app
|
||||
public static ProcessOutput UninstallGame(string packagename)
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
Program.form.ChangeTitle("Attempting to backup any savedata to Documents\\Rookie Backups...");
|
||||
ProcessOutput output = new ProcessOutput("", "");
|
||||
string date_str = DateTime.Today.ToString("yyyy.MM.dd");
|
||||
string CurrBackups = Path.Combine(BackupFolder, date_str);
|
||||
if (!Directory.Exists(CurrBackups))
|
||||
Directory.CreateDirectory(CurrBackups);
|
||||
ADB.RunAdbCommandToString($"pull \"/sdcard/Android/data/{packagename}\" \"{CurrBackups}\"");
|
||||
output = ADB.UninstallPackage(packagename);
|
||||
Program.form.ChangeTitle("");
|
||||
Sideloader.RemoveFolder("/sdcard/Android/obb/" + packagename);
|
||||
Sideloader.RemoveFolder("/sdcard/Android/data/" + packagename);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static ProcessOutput DeleteFile(string GameName)
|
||||
{
|
||||
ADB.WakeDevice();
|
||||
ProcessOutput output = new ProcessOutput("", "");
|
||||
|
||||
string packageName = Sideloader.gameNameToPackageName(GameName);
|
||||
|
||||
DialogResult dialogResult = FlexibleMessageBox.Show($"Are you sure you want to uninstall custom QU settings for {packageName}? this CANNOT be undone!", "WARNING!", MessageBoxButtons.YesNo);
|
||||
if (dialogResult != DialogResult.Yes)
|
||||
return output;
|
||||
|
||||
output = Sideloader.RemoveFile($"/sdcard/Android/data/{packageName}/private/Config.Json");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//Extracts apk from device, saves it by package name to sideloader folder
|
||||
public static ProcessOutput getApk(string GameName)
|
||||
{
|
||||
|
||||
ADB.WakeDevice();
|
||||
ProcessOutput output = new ProcessOutput("", "");
|
||||
|
||||
string packageName = Sideloader.gameNameToPackageName(GameName);
|
||||
|
||||
output = ADB.RunAdbCommandToString("shell pm path " + packageName);
|
||||
|
||||
string apkPath = output.Output; //Get apk
|
||||
|
||||
apkPath = apkPath.Remove(apkPath.Length - 1);
|
||||
apkPath = apkPath.Remove(0, 8); //remove package:
|
||||
apkPath = apkPath.Remove(apkPath.Length - 1);
|
||||
if (File.Exists($"{Properties.Settings.Default.ADBFolder}\\base.apk"))
|
||||
File.Delete($"{Properties.Settings.Default.ADBFolder}\\base.apk");
|
||||
if (File.Exists($"{Properties.Settings.Default.MainDir}\\{packageName}\\{packageName}.apk"))
|
||||
File.Delete($"{Properties.Settings.Default.MainDir}\\{packageName}\\{packageName}.apk");
|
||||
output += ADB.RunAdbCommandToString("pull " + apkPath); //pull apk
|
||||
|
||||
if (Directory.Exists($"{Properties.Settings.Default.MainDir}\\{packageName}"))
|
||||
Directory.Delete($"{Properties.Settings.Default.MainDir}\\{packageName}", true);
|
||||
|
||||
Directory.CreateDirectory($"{Properties.Settings.Default.MainDir}\\{packageName}");
|
||||
|
||||
File.Move($"{Properties.Settings.Default.ADBFolder}\\base.apk", $"{Properties.Settings.Default.MainDir}\\{packageName}\\{packageName}.apk");
|
||||
return output;
|
||||
}
|
||||
|
||||
public static string gameNameToPackageName(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]))
|
||||
return game[SideloaderRCLONE.PackageNameIndex];
|
||||
if (gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
|
||||
return game[SideloaderRCLONE.PackageNameIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
public static string PackageNametoGameName(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Equals(game[SideloaderRCLONE.PackageNameIndex]))
|
||||
return game[SideloaderRCLONE.ReleaseNameIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
public static string gameNameToSimpleName(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]))
|
||||
return game[SideloaderRCLONE.GameNameIndex];
|
||||
if (gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
|
||||
return game[SideloaderRCLONE.GameNameIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
public static string PackageNameToSimpleName(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Contains(game[SideloaderRCLONE.PackageNameIndex]))
|
||||
return game[SideloaderRCLONE.GameNameIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
|
||||
//Downloads the required files
|
||||
public static void downloadFiles()
|
||||
{
|
||||
var client = new WebClient();
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
try
|
||||
{
|
||||
if (!File.Exists("Sideloader Launcher.exe"))
|
||||
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/Sideloader%20Launcher.exe", "Sideloader Launcher.exe");
|
||||
|
||||
if (!File.Exists("Rookie Offline.cmd"))
|
||||
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/Rookie%20Offline.cmd", "Rookie Offline.cmd");
|
||||
|
||||
if (!File.Exists("C:\\RSL\\platform-tools\\aug2021.txt") || !File.Exists("C:\\RSL\\platform-tools\\adb.exe")) //if adb is not updated, download and auto extract
|
||||
{
|
||||
if (Directory.Exists($"C:\\RSL\\2.8.2"))
|
||||
Directory.Delete("C:\\RSL\\2.8.2", true);
|
||||
if (Directory.Exists($"{Properties.Settings.Default.MainDir}\\adb"))
|
||||
Directory.Delete($"{Properties.Settings.Default.MainDir}\\adb", true);
|
||||
if (!Directory.Exists("C:\\RSL\\platform-tools"))
|
||||
Directory.CreateDirectory("C:\\RSL\\platform-tools");
|
||||
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/adb2.zip", "Ad.7z");
|
||||
Utilities.Zip.ExtractFile(Environment.CurrentDirectory + "\\Ad.7z", "C:\\RSL\\platform-tools");
|
||||
File.Delete("Ad.7z");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(Environment.CurrentDirectory + "\\rclone"))
|
||||
{
|
||||
string url;
|
||||
if (Environment.Is64BitOperatingSystem)
|
||||
url = "https://downloads.rclone.org/v1.55.1/rclone-v1.55.1-windows-amd64.zip";
|
||||
else
|
||||
url = "https://downloads.rclone.org/v1.55.1/rclone-v1.55.1-windows-386.zip";
|
||||
//Since sideloader is build for x86, it should work on both x86 and x64 so we download the according rclone version
|
||||
|
||||
client.DownloadFile(url, "rclone.zip");
|
||||
|
||||
Utilities.Zip.ExtractFile(Environment.CurrentDirectory + "\\rclone.zip", Environment.CurrentDirectory);
|
||||
|
||||
File.Delete("rclone.zip");
|
||||
|
||||
string[] folders = Directory.GetDirectories(Environment.CurrentDirectory);
|
||||
foreach (string folder in folders)
|
||||
{
|
||||
if (folder.Contains("rclone"))
|
||||
{
|
||||
Directory.Move(folder, "rclone");
|
||||
break; //only 1 rclone folder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
FlexibleMessageBox.Show("Your internet is not working properly or rclone/github servers are down, some files may be missing (adb, rclone or launcher)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
using AndroidSideloader.Utilities;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
internal class Sideloader
|
||||
{
|
||||
private static readonly SettingsManager settings = SettingsManager.Instance;
|
||||
public static string TempFolder = Path.Combine(Environment.CurrentDirectory, "temp");
|
||||
public static string CrashLogPath = "crashlog.txt";
|
||||
|
||||
//push user.json to device (required for some devices like oculus quest)
|
||||
public static void PushUserJsons()
|
||||
{
|
||||
foreach (string userJson in UsernameForm.userJsons)
|
||||
{
|
||||
UsernameForm.createUserJsonByName(Utilities.GeneralUtilities.randomString(16), userJson);
|
||||
_ = ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{userJson}\" " + " /sdcard/");
|
||||
File.Delete(userJson);
|
||||
}
|
||||
}
|
||||
|
||||
//List of all installed package names from connected device
|
||||
//public static List<string> InstalledPackageNames = new List<string>(); //Remove folder from device
|
||||
public static ProcessOutput RemoveFolder(string path)
|
||||
{
|
||||
if (path == "/sdcard/Android/obb/" || path == "sdcard/Android/data/")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return ADB.RunAdbCommandToString($"shell rm -r \"{path}\"");
|
||||
}
|
||||
|
||||
public static ProcessOutput RemoveFile(string path)
|
||||
{
|
||||
return ADB.RunAdbCommandToString($"shell rm -f \"{path}\"");
|
||||
}
|
||||
|
||||
//For games that require manual install, like having another folder that isnt an obb
|
||||
public static ProcessOutput RunADBCommandsFromFile(string path)
|
||||
{
|
||||
ProcessOutput output = new ProcessOutput();
|
||||
string[] commands = File.ReadAllLines(path);
|
||||
string currfolder = Path.GetDirectoryName(path);
|
||||
string[] zipz = Directory.GetFiles(currfolder, "*.7z", SearchOption.AllDirectories);
|
||||
foreach (string zip in zipz)
|
||||
{
|
||||
Utilities.Zip.ExtractFile($"{zip}", currfolder);
|
||||
}
|
||||
foreach (string cmd in commands)
|
||||
{
|
||||
if (cmd.StartsWith("adb"))
|
||||
{
|
||||
string replacement = "";
|
||||
string pattern = "adb";
|
||||
replacement = ADB.DeviceID.Length > 1
|
||||
? $"{settings.ADBPath} -s {ADB.DeviceID}"
|
||||
: $"{settings.ADBPath}";
|
||||
Regex rgx = new Regex(pattern);
|
||||
string result = rgx.Replace(cmd, replacement);
|
||||
Program.form.changeTitle($"Running {result}");
|
||||
_ = Logger.Log($"Logging command: {result} from file: {path}");
|
||||
output += ADB.RunAdbCommandToStringWOADB(result, path);
|
||||
if (output.Error.Contains("mkdir"))
|
||||
{
|
||||
output.Error = "";
|
||||
}
|
||||
|
||||
if (output.Output.Contains("reserved"))
|
||||
{
|
||||
output.Output = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
output.Output += "Custom install successful!";
|
||||
return output;
|
||||
}
|
||||
|
||||
//Recursive sideload any apk file
|
||||
public static ProcessOutput RecursiveOutput = new ProcessOutput();
|
||||
public static async Task RecursiveSideloadAsync(
|
||||
string FolderPath,
|
||||
Action<float, TimeSpan?> progressCallback = null,
|
||||
Action<string> statusCallback = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string f in Directory.GetFiles(FolderPath))
|
||||
{
|
||||
if (Path.GetExtension(f) == ".apk")
|
||||
{
|
||||
string gameName = Path.GetFileNameWithoutExtension(f);
|
||||
statusCallback?.Invoke(gameName);
|
||||
RecursiveOutput += await ADB.SideloadWithProgressAsync(f, progressCallback, statusCallback, "", gameName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string d in Directory.GetDirectories(FolderPath))
|
||||
{
|
||||
await RecursiveSideloadAsync(d, progressCallback, statusCallback);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _ = Logger.Log(ex.Message, LogLevel.ERROR); }
|
||||
}
|
||||
|
||||
//Recursive copy any obb folder
|
||||
public static async Task RecursiveCopyOBBAsync(
|
||||
string FolderPath,
|
||||
Action<float, TimeSpan?> progressCallback = null,
|
||||
Action<string> statusCallback = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string d in Directory.GetDirectories(FolderPath))
|
||||
{
|
||||
string folderName = Path.GetFileName(d);
|
||||
if (folderName.Contains("."))
|
||||
{
|
||||
statusCallback?.Invoke(folderName);
|
||||
RecursiveOutput += await ADB.CopyOBBWithProgressAsync(d, progressCallback, statusCallback, folderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
await RecursiveCopyOBBAsync(d, progressCallback, statusCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _ = Logger.Log(ex.Message, LogLevel.ERROR); }
|
||||
}
|
||||
|
||||
// Removes the game package and its OBB + Data Folders.
|
||||
public static ProcessOutput UninstallGame(string packagename)
|
||||
{
|
||||
ProcessOutput output = ADB.UninstallPackage(packagename);
|
||||
Program.form.changeTitle("");
|
||||
_ = Sideloader.RemoveFolder("/sdcard/Android/obb/" + packagename);
|
||||
_ = Sideloader.RemoveFolder("/sdcard/Android/data/" + packagename);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void BackupGame(string packagename)
|
||||
{
|
||||
MainForm.backupFolder = settings.GetEffectiveBackupDir();
|
||||
if (!Directory.Exists(MainForm.backupFolder))
|
||||
{
|
||||
_ = Directory.CreateDirectory(MainForm.backupFolder);
|
||||
}
|
||||
Program.form.changeTitle($"Attempting to backup any savedata to {MainForm.backupFolder}\\Rookie Backups...");
|
||||
_ = new ProcessOutput("", "");
|
||||
string date_str = DateTime.Today.ToString("yyyy.MM.dd");
|
||||
string CurrBackups = Path.Combine(MainForm.backupFolder, date_str);
|
||||
if (!Directory.Exists(CurrBackups))
|
||||
{
|
||||
_ = Directory.CreateDirectory(CurrBackups);
|
||||
}
|
||||
_ = ADB.RunAdbCommandToString($"pull \"/sdcard/Android/data/{packagename}\" \"{CurrBackups}\"");
|
||||
}
|
||||
|
||||
public static ProcessOutput DeleteFile(string GameName)
|
||||
{
|
||||
ProcessOutput output = new ProcessOutput("", "");
|
||||
|
||||
string packageName = Sideloader.gameNameToPackageName(GameName);
|
||||
|
||||
DialogResult dialogResult = FlexibleMessageBox.Show(Program.form, $"Are you sure you want to uninstall custom QU settings for {packageName}? this CANNOT be undone!", "WARNING!", MessageBoxButtons.YesNo);
|
||||
if (dialogResult != DialogResult.Yes)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
output = Sideloader.RemoveFile($"/sdcard/Android/data/{packageName}/private/Config.Json");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//Extracts apk from device, saves it by package name to sideloader folder
|
||||
public static ProcessOutput getApk(string GameName)
|
||||
{
|
||||
_ = new ProcessOutput("", "");
|
||||
|
||||
string packageName = Sideloader.gameNameToPackageName(GameName);
|
||||
|
||||
ProcessOutput output = ADB.RunAdbCommandToString("shell pm path " + packageName);
|
||||
|
||||
string apkPath = output.Output; //Get apk
|
||||
|
||||
apkPath = apkPath.Remove(apkPath.Length - 1);
|
||||
apkPath = apkPath.Remove(0, 8); //remove package:
|
||||
apkPath = apkPath.Remove(apkPath.Length - 1);
|
||||
if (File.Exists($"{settings.ADBFolder}\\base.apk"))
|
||||
{
|
||||
File.Delete($"{settings.ADBFolder}\\base.apk");
|
||||
}
|
||||
|
||||
if (File.Exists($"{settings.MainDir}\\{packageName}\\{packageName}.apk"))
|
||||
{
|
||||
File.Delete($"{settings.MainDir}\\{packageName}\\{packageName}.apk");
|
||||
}
|
||||
|
||||
output += ADB.RunAdbCommandToString("pull " + apkPath); //pull apk
|
||||
|
||||
if (Directory.Exists($"{settings.MainDir}\\{packageName}"))
|
||||
{
|
||||
FileSystemUtilities.TryDeleteDirectory($"{settings.MainDir}\\{packageName}");
|
||||
}
|
||||
|
||||
_ = Directory.CreateDirectory($"{settings.MainDir}\\{packageName}");
|
||||
|
||||
File.Move($"{settings.ADBFolder}\\base.apk", $"{settings.MainDir}\\{packageName}\\{packageName}.apk");
|
||||
return output;
|
||||
}
|
||||
|
||||
public static string gameNameToPackageName(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]) || gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
|
||||
return game[SideloaderRCLONE.PackageNameIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
public static string gameNameToVersionCode(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]) || gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
|
||||
return game[SideloaderRCLONE.VersionCodeIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
public static string PackageNametoGameName(string packageName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (packageName.Equals(game[SideloaderRCLONE.PackageNameIndex]))
|
||||
return game[SideloaderRCLONE.ReleaseNameIndex];
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public static string gameNameToSimpleName(string gameName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]) || gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
|
||||
return game[SideloaderRCLONE.GameNameIndex];
|
||||
}
|
||||
return gameName;
|
||||
}
|
||||
|
||||
public static string PackageNameToSimpleName(string packageName)
|
||||
{
|
||||
foreach (string[] game in SideloaderRCLONE.games)
|
||||
{
|
||||
if (packageName.Contains(game[SideloaderRCLONE.PackageNameIndex]))
|
||||
return game[SideloaderRCLONE.GameNameIndex];
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
333
Sideloader/GetDependencies.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using AndroidSideloader.Utilities;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
internal class GetDependencies
|
||||
{
|
||||
public static void updatePublicConfig()
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
|
||||
| SecurityProtocolType.Tls11
|
||||
| SecurityProtocolType.Tls12
|
||||
| SecurityProtocolType.Ssl3;
|
||||
|
||||
_ = Logger.Log("Attempting to update public config from main.");
|
||||
|
||||
string configUrl = "https://raw.githubusercontent.com/vrpyou/quest/main/vrp-public.json";
|
||||
string fallbackUrl = "https://vrpirates.wiki/downloads/vrp-public.json";
|
||||
|
||||
try
|
||||
{
|
||||
string resultString;
|
||||
|
||||
// Try fetching raw JSON data from the provided link
|
||||
HttpWebRequest getUrl = DnsHelper.CreateWebRequest(configUrl);
|
||||
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
|
||||
{
|
||||
resultString = responseReader.ReadToEnd();
|
||||
_ = Logger.Log($"Retrieved updated config from main: {configUrl}.");
|
||||
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "vrp-public.json"), resultString);
|
||||
_ = Logger.Log("Public config updated successfully from main.");
|
||||
}
|
||||
}
|
||||
catch (Exception mainException)
|
||||
{
|
||||
_ = Logger.Log($"Failed to update public config from main: {mainException.Message}, trying fallback.", LogLevel.ERROR);
|
||||
try
|
||||
{
|
||||
HttpWebRequest getUrl = DnsHelper.CreateWebRequest(fallbackUrl);
|
||||
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
|
||||
{
|
||||
string resultString = responseReader.ReadToEnd();
|
||||
_ = Logger.Log($"Retrieved updated config from fallback: {fallbackUrl}.");
|
||||
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "vrp-public.json"), resultString);
|
||||
_ = Logger.Log("Public config updated successfully from fallback.");
|
||||
}
|
||||
}
|
||||
catch (Exception fallbackException)
|
||||
{
|
||||
_ = Logger.Log($"Failed to update public config from fallback: {fallbackException.Message}.", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Download required dependencies
|
||||
public static void downloadFiles()
|
||||
{
|
||||
// Initialize DNS helper early to detect and configure fallback if needed
|
||||
DnsHelper.Initialize();
|
||||
|
||||
WebClient client = new WebClient();
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
var currentAccessedWebsite = "";
|
||||
try
|
||||
{
|
||||
if (!File.Exists("Sideloader Launcher.exe"))
|
||||
{
|
||||
currentAccessedWebsite = "github";
|
||||
_ = Logger.Log($"Missing 'Sideloader Launcher.exe'. Attempting to download from {currentAccessedWebsite}");
|
||||
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/Sideloader%20Launcher.exe", "Sideloader Launcher.exe");
|
||||
_ = Logger.Log($"'Sideloader Launcher.exe' download successful");
|
||||
}
|
||||
|
||||
if (!File.Exists("Rookie Offline.cmd"))
|
||||
{
|
||||
currentAccessedWebsite = "github";
|
||||
_ = Logger.Log($"Missing 'Rookie Offline.cmd'. Attempting to download from {currentAccessedWebsite}");
|
||||
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/Rookie%20Offline.cmd", "Rookie Offline.cmd");
|
||||
_ = Logger.Log($"'Rookie Offline.cmd' download successful");
|
||||
}
|
||||
|
||||
if (!File.Exists("CleanupInstall.cmd"))
|
||||
{
|
||||
currentAccessedWebsite = "github";
|
||||
_ = Logger.Log($"Missing 'CleanupInstall.cmd'. Attempting to download from {currentAccessedWebsite}");
|
||||
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/CleanupInstall.cmd", "CleanupInstall.cmd");
|
||||
_ = Logger.Log($"'CleanupInstall.cmd' download successful");
|
||||
}
|
||||
|
||||
if (!File.Exists("AddDefenderExceptions.ps1"))
|
||||
{
|
||||
currentAccessedWebsite = "github";
|
||||
_ = Logger.Log($"Missing 'AddDefenderExceptions.ps1'. Attempting to download from {currentAccessedWebsite}");
|
||||
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/AddDefenderExceptions.ps1", "AddDefenderExceptions.ps1");
|
||||
_ = Logger.Log($"'AddDefenderExceptions.ps1' download successful");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = FlexibleMessageBox.Show(Program.form, $"You are unable to access raw.githubusercontent.com with the Exception:\n{ex.Message}\n\nSome files may be missing (Offline/Cleanup Script, Launcher)");
|
||||
}
|
||||
|
||||
string adbPath = Path.Combine(Environment.CurrentDirectory, "platform-tools", "adb.exe");
|
||||
string platformToolsDir = Path.Combine(Environment.CurrentDirectory, "platform-tools");
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(adbPath)) //if adb is not updated, download and auto extract
|
||||
{
|
||||
if (!Directory.Exists(platformToolsDir))
|
||||
{
|
||||
_ = Directory.CreateDirectory(platformToolsDir);
|
||||
}
|
||||
|
||||
currentAccessedWebsite = "github";
|
||||
_ = Logger.Log($"Missing adb within {platformToolsDir}. Attempting to download from {currentAccessedWebsite}");
|
||||
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/dependencies.7z", "dependencies.7z");
|
||||
Utilities.Zip.ExtractFile(Path.Combine(Environment.CurrentDirectory, "dependencies.7z"), platformToolsDir);
|
||||
File.Delete("dependencies.7z");
|
||||
_ = Logger.Log($"adb download successful");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = FlexibleMessageBox.Show(Program.form, $"You are unable to access raw.githubusercontent.com page with the Exception:\n{ex.Message}\n\nSome files may be missing (ADB)");
|
||||
_ = FlexibleMessageBox.Show(Program.form, "ADB was unable to be downloaded\nRookie will now close.");
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
string wantedRcloneVersion = "1.72.1";
|
||||
bool rcloneSuccess = false;
|
||||
|
||||
rcloneSuccess = downloadRclone(wantedRcloneVersion, false);
|
||||
if (!rcloneSuccess)
|
||||
{
|
||||
rcloneSuccess = downloadRclone(wantedRcloneVersion, true);
|
||||
}
|
||||
if (!rcloneSuccess)
|
||||
{
|
||||
_ = Logger.Log($"Unable to download rclone", LogLevel.ERROR);
|
||||
_ = FlexibleMessageBox.Show(Program.form, "Rclone was unable to be downloaded\nRookie will now close, please use Offline Mode for manual sideloading if needed");
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
// Download WebView2 runtime if needed
|
||||
downloadWebView2Runtime();
|
||||
}
|
||||
|
||||
// Downloads a file using the DNS fallback proxy if active
|
||||
public static void DownloadFileWithDnsFallback(WebClient client, string url, string localPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use DNS fallback proxy if active
|
||||
if (DnsHelper.UseFallbackDns && !string.IsNullOrEmpty(DnsHelper.ProxyUrl))
|
||||
{
|
||||
client.Proxy = new WebProxy(DnsHelper.ProxyUrl);
|
||||
}
|
||||
|
||||
client.DownloadFile(url, localPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = Logger.Log($"Download failed for {url}: {ex.Message}", LogLevel.ERROR);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Reset proxy to avoid affecting other operations
|
||||
client.Proxy = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Overload that creates its own WebClient for convenience
|
||||
public static void DownloadFileWithDnsFallback(string url, string localPath)
|
||||
{
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
DownloadFileWithDnsFallback(client, url, localPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Downloads WebView2 runtime if not present
|
||||
private static void downloadWebView2Runtime()
|
||||
{
|
||||
string runtimesPath = Path.Combine(Environment.CurrentDirectory, "runtimes");
|
||||
string webView2LoaderArm64 = Path.Combine(runtimesPath, "win-arm64", "native", "WebView2Loader.dll");
|
||||
string webView2LoaderX86 = Path.Combine(runtimesPath, "win-x86", "native", "WebView2Loader.dll");
|
||||
string webView2LoaderX64 = Path.Combine(runtimesPath, "win-x64", "native", "WebView2Loader.dll");
|
||||
|
||||
bool runtimeExists = File.Exists(webView2LoaderX86) || File.Exists(webView2LoaderX64) || File.Exists(webView2LoaderArm64);
|
||||
|
||||
if (!runtimeExists)
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Logger.Log("Missing WebView2 runtime. Attempting to download...");
|
||||
string archivePath = Path.Combine(Environment.CurrentDirectory, "runtimes.7z");
|
||||
|
||||
DownloadFileWithDnsFallback("https://vrpirates.wiki/downloads/runtimes.7z", archivePath);
|
||||
|
||||
_ = Logger.Log("Extracting WebView2 runtime...");
|
||||
Utilities.Zip.ExtractFile(archivePath, Environment.CurrentDirectory);
|
||||
File.Delete(archivePath);
|
||||
_ = Logger.Log("WebView2 runtime download successful");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = Logger.Log($"Failed to download WebView2 runtime: {ex.Message}", LogLevel.ERROR);
|
||||
// Don't show message box here - let CreateEnvironment handle the UI feedback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool downloadRclone(string wantedRcloneVersion, bool useFallback = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool updateRclone = false;
|
||||
string currentRcloneVersion = "0.0.0";
|
||||
|
||||
WebClient client = new WebClient();
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
|
||||
_ = Logger.Log($"Checking for Local rclone...");
|
||||
string dirRclone = Path.Combine(Environment.CurrentDirectory, "rclone");
|
||||
string pathToRclone = Path.Combine(dirRclone, "rclone.exe");
|
||||
if (File.Exists(pathToRclone))
|
||||
{
|
||||
var versionInfo = FileVersionInfo.GetVersionInfo(pathToRclone);
|
||||
currentRcloneVersion = versionInfo.ProductVersion;
|
||||
Logger.Log($"Current RCLONE Version {currentRcloneVersion}");
|
||||
if (!MainForm.noRcloneUpdating)
|
||||
{
|
||||
if (currentRcloneVersion != wantedRcloneVersion)
|
||||
{
|
||||
updateRclone = true;
|
||||
_ = Logger.Log($"RCLONE Version does not match ({currentRcloneVersion})! Downloading required version ({wantedRcloneVersion})");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
updateRclone = true;
|
||||
_ = Logger.Log($"RCLONE exe does not exist, attempting to download");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(dirRclone))
|
||||
{
|
||||
updateRclone = true;
|
||||
_ = Logger.Log($"Missing RCLONE Folder, attempting to download");
|
||||
|
||||
Directory.CreateDirectory(dirRclone);
|
||||
}
|
||||
|
||||
if (updateRclone == true)
|
||||
{
|
||||
// Preserve vrp.download.config if it exists
|
||||
string configPath = Path.Combine(dirRclone, "vrp.download.config");
|
||||
string tempConfigPath = Path.Combine(Environment.CurrentDirectory, "vrp.download.config.bak");
|
||||
bool hasConfig = false;
|
||||
|
||||
if (File.Exists(configPath))
|
||||
{
|
||||
_ = Logger.Log("Preserving vrp.download.config before update");
|
||||
File.Copy(configPath, tempConfigPath, true);
|
||||
hasConfig = true;
|
||||
}
|
||||
|
||||
string architecture = Environment.Is64BitOperatingSystem ? "amd64" : "386";
|
||||
string url = $"https://downloads.rclone.org/v{wantedRcloneVersion}/rclone-v{wantedRcloneVersion}-windows-{architecture}.zip";
|
||||
if (useFallback == true)
|
||||
{
|
||||
_ = Logger.Log($"Using git fallback for rclone download");
|
||||
url = $"https://raw.githubusercontent.com/VRPirates/rookie/master/dep/rclone-v{wantedRcloneVersion}-windows-{architecture}.zip";
|
||||
}
|
||||
_ = Logger.Log($"Downloading rclone from {url}");
|
||||
|
||||
_ = Logger.Log("Begin download rclone");
|
||||
DownloadFileWithDnsFallback(client, url, "rclone.zip");
|
||||
_ = Logger.Log("Complete download rclone");
|
||||
|
||||
_ = Logger.Log($"Extract {Environment.CurrentDirectory}\\rclone.zip");
|
||||
Utilities.Zip.ExtractFile(Path.Combine(Environment.CurrentDirectory, "rclone.zip"), Environment.CurrentDirectory);
|
||||
string dirExtractedRclone = Path.Combine(Environment.CurrentDirectory, $"rclone-v{wantedRcloneVersion}-windows-{architecture}");
|
||||
File.Delete("rclone.zip");
|
||||
_ = Logger.Log("rclone extracted. Moving files");
|
||||
|
||||
foreach (string file in Directory.GetFiles(dirExtractedRclone))
|
||||
{
|
||||
string fileName = Path.GetFileName(file);
|
||||
string destFile = Path.Combine(dirRclone, fileName);
|
||||
if (File.Exists(destFile))
|
||||
{
|
||||
File.Delete(destFile);
|
||||
}
|
||||
File.Move(file, destFile);
|
||||
}
|
||||
FileSystemUtilities.TryDeleteDirectory(dirExtractedRclone);
|
||||
|
||||
// Restore vrp.download.config if it was backed up
|
||||
if (hasConfig && File.Exists(tempConfigPath))
|
||||
{
|
||||
_ = Logger.Log("Restoring vrp.download.config after update");
|
||||
File.Move(tempConfigPath, configPath);
|
||||
}
|
||||
|
||||
_ = Logger.Log($"rclone download successful");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = Logger.Log($"Unable to download rclone: {ex}", LogLevel.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AndroidSideloader
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public class ProcessOutput
|
||||
{
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
using System;
|
||||
using AndroidSideloader.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using AndroidSideloader.Utilities;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class rcloneFolder
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Size { get; set; }
|
||||
public string ModTime { get; set; }
|
||||
}
|
||||
|
||||
class SideloaderRCLONE
|
||||
internal class SideloaderRCLONE
|
||||
{
|
||||
public static List<string> RemotesList = new List<string>();
|
||||
|
||||
public static string RcloneGamesFolder = "Quest Games";
|
||||
|
||||
//This shit sucks but i'll switch to programatically adding indexes from the gamelist txt sometimes maybe
|
||||
|
||||
public static int GameNameIndex = 0;
|
||||
public static int ReleaseNameIndex = 1;
|
||||
public static int PackageNameIndex = 2;
|
||||
public static int VersionCodeIndex = 3;
|
||||
public static int ReleaseAPKPathIndex = 4;
|
||||
public static int VersionNameIndex = 5;
|
||||
public static int DownloadsIndex = 6;
|
||||
public static int InstalledVersion = 7;
|
||||
|
||||
public static List<string> gameProperties = new List<string>();
|
||||
/* Game Name
|
||||
@@ -41,247 +33,298 @@ namespace AndroidSideloader
|
||||
*/
|
||||
public static List<string[]> games = new List<string[]>();
|
||||
|
||||
public static string Nouns = Environment.CurrentDirectory + "\\nouns";
|
||||
public static string ThumbnailsFolder = Environment.CurrentDirectory + "\\thumbnails";
|
||||
public static string NotesFolder = Environment.CurrentDirectory + "\\notes";
|
||||
public static string Nouns = Path.Combine(Environment.CurrentDirectory, "nouns");
|
||||
public static string ThumbnailsFolder = Path.Combine(Environment.CurrentDirectory, "thumbnails");
|
||||
public static string NotesFolder = Path.Combine(Environment.CurrentDirectory, "notes");
|
||||
|
||||
public static void UpdateNouns(string remote)
|
||||
{
|
||||
Logger.Log($"Updating Nouns");
|
||||
RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/nouns\" \"{Nouns}\"");
|
||||
_ = Logger.Log($"Updating Nouns");
|
||||
_ = RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/nouns\" \"{Nouns}\"");
|
||||
}
|
||||
|
||||
public static void UpdateGamePhotos(string remote)
|
||||
{
|
||||
Logger.Log($"Updating Thumbnails");
|
||||
RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/thumbnails\" \"{ThumbnailsFolder}\"");
|
||||
_ = Logger.Log($"Updating Thumbnails");
|
||||
_ = RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/thumbnails\" \"{ThumbnailsFolder}\" --transfers 10");
|
||||
}
|
||||
|
||||
public static void UpdateGameNotes(string remote)
|
||||
{
|
||||
Logger.Log($"Updating Game Notes");
|
||||
RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/notes\" \"{NotesFolder}\"");
|
||||
_ = Logger.Log($"Updating Game Notes");
|
||||
_ = RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/notes\" \"{NotesFolder}\"");
|
||||
}
|
||||
|
||||
public static void UpdateMetadataFromPublic()
|
||||
{
|
||||
Logger.Log($"Downloading Metadata");
|
||||
var rclonecommand =
|
||||
_ = Logger.Log($"Downloading Metadata");
|
||||
string rclonecommand =
|
||||
$"sync \":http:/meta.7z\" \"{Environment.CurrentDirectory}\"";
|
||||
RCLONE.runRcloneCommand_PublicConfig(rclonecommand);
|
||||
_ = RCLONE.runRcloneCommand_PublicConfig(rclonecommand);
|
||||
}
|
||||
|
||||
public static void ProcessMetadataFromPublic()
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Log($"Extracting Metadata");
|
||||
Zip.ExtractFile($"{Environment.CurrentDirectory}\\meta.7z", $"{Environment.CurrentDirectory}\\meta",
|
||||
MainForm.PublicConfigFile.Password);
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
Logger.Log($"Updating Metadata");
|
||||
string currentDir = Environment.CurrentDirectory;
|
||||
string metaRoot = Path.Combine(currentDir, "meta");
|
||||
string metaArchive = Path.Combine(currentDir, "meta.7z");
|
||||
string metaDotMeta = Path.Combine(metaRoot, ".meta");
|
||||
|
||||
if (Directory.Exists(Nouns)) Directory.Delete(Nouns, true);
|
||||
if (Directory.Exists(ThumbnailsFolder)) Directory.Delete(ThumbnailsFolder, true);
|
||||
if (Directory.Exists(NotesFolder)) Directory.Delete(NotesFolder, true);
|
||||
|
||||
Directory.Move($"{Environment.CurrentDirectory}\\meta\\.meta\\nouns", Nouns);
|
||||
Directory.Move($"{Environment.CurrentDirectory}\\meta\\.meta\\thumbnails", ThumbnailsFolder);
|
||||
Directory.Move($"{Environment.CurrentDirectory}\\meta\\.meta\\notes", NotesFolder);
|
||||
|
||||
Logger.Log($"Initializing Games List");
|
||||
var gameList = File.ReadAllText($"{Environment.CurrentDirectory}\\meta\\VRP-GameList.txt");
|
||||
|
||||
string[] splitList = gameList.Split('\n');
|
||||
splitList = splitList.Skip(1).ToArray();
|
||||
foreach (string game in splitList)
|
||||
// Check if archive exists and is newer than existing metadata
|
||||
if (!File.Exists(metaArchive))
|
||||
{
|
||||
if (game.Length > 1)
|
||||
Logger.Log("meta.7z not found, skipping extraction", LogLevel.WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip extraction if metadata is already up-to-date (based on file timestamps)
|
||||
string gameListPath = Path.Combine(metaRoot, "VRP-GameList.txt");
|
||||
if (File.Exists(gameListPath))
|
||||
{
|
||||
var archiveTime = File.GetLastWriteTimeUtc(metaArchive);
|
||||
var gameListTime = File.GetLastWriteTimeUtc(gameListPath);
|
||||
|
||||
// If game list is newer than archive, skip extraction
|
||||
if (gameListTime > archiveTime && games.Count > 0)
|
||||
{
|
||||
string[] splitGame = game.Split(';');
|
||||
games.Add(splitGame);
|
||||
Logger.Log($"Metadata already up-to-date, skipping extraction");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Directory.Delete($"{Environment.CurrentDirectory}\\meta", true);
|
||||
_ = Logger.Log($"Extracting Metadata");
|
||||
Zip.ExtractFile(metaArchive, metaRoot, MainForm.PublicConfigFile.Password);
|
||||
Logger.Log($"Extraction completed in {sw.ElapsedMilliseconds}ms");
|
||||
sw.Restart();
|
||||
|
||||
_ = Logger.Log($"Updating Metadata");
|
||||
|
||||
// Use Parallel.Invoke for independent directory operations
|
||||
System.Threading.Tasks.Parallel.Invoke(
|
||||
() => SafeDeleteDirectory(Nouns),
|
||||
() => SafeDeleteDirectory(ThumbnailsFolder),
|
||||
() => SafeDeleteDirectory(NotesFolder)
|
||||
);
|
||||
Logger.Log($"Directory cleanup in {sw.ElapsedMilliseconds}ms");
|
||||
sw.Restart();
|
||||
|
||||
// Move directories
|
||||
MoveIfExists(Path.Combine(metaDotMeta, "nouns"), Nouns);
|
||||
MoveIfExists(Path.Combine(metaDotMeta, "thumbnails"), ThumbnailsFolder);
|
||||
MoveIfExists(Path.Combine(metaDotMeta, "notes"), NotesFolder);
|
||||
Logger.Log($"Directory moves in {sw.ElapsedMilliseconds}ms");
|
||||
sw.Restart();
|
||||
|
||||
_ = Logger.Log($"Initializing Games List");
|
||||
|
||||
gameListPath = Path.Combine(metaRoot, "VRP-GameList.txt");
|
||||
if (File.Exists(gameListPath))
|
||||
{
|
||||
// Read all lines at once - faster for files that fit in memory
|
||||
var lines = File.ReadAllLines(gameListPath);
|
||||
var newGames = new List<string[]>(lines.Length);
|
||||
|
||||
for (int i = 1; i < lines.Length; i++) // Skip header
|
||||
{
|
||||
var line = lines[i];
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
var splitGame = line.Split(';');
|
||||
if (splitGame.Length > 1)
|
||||
{
|
||||
newGames.Add(splitGame);
|
||||
}
|
||||
}
|
||||
|
||||
// Atomic swap
|
||||
games.Clear();
|
||||
games.AddRange(newGames);
|
||||
Logger.Log($"Parsed {games.Count} games in {sw.ElapsedMilliseconds}ms");
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Logger.Log("VRP-GameList.txt not found in extracted metadata.", LogLevel.WARNING);
|
||||
}
|
||||
|
||||
SafeDeleteDirectory(metaRoot);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log(e.Message);
|
||||
Logger.Log(e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RefreshRemotes()
|
||||
{
|
||||
Logger.Log($"Refresh / List Remotes");
|
||||
RemotesList.Clear();
|
||||
var remotes = RCLONE.runRcloneCommand_DownloadConfig("listremotes").Output.Split('\n');
|
||||
|
||||
Logger.Log("Loaded following remotes: ");
|
||||
foreach (string r in remotes)
|
||||
{
|
||||
if (r.Length > 1)
|
||||
{
|
||||
var remote = r.Remove(r.Length - 1);
|
||||
if (remote.Contains("mirror"))
|
||||
{
|
||||
Logger.Log(remote);
|
||||
RemotesList.Add(remote);
|
||||
}
|
||||
}
|
||||
_ = Logger.Log(e.Message);
|
||||
_ = Logger.Log(e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initGames(string remote)
|
||||
{
|
||||
Logger.Log($"Initializing Games List");
|
||||
|
||||
_ = Logger.Log($"Initializing Games List");
|
||||
|
||||
gameProperties.Clear();
|
||||
games.Clear();
|
||||
|
||||
// Fetch once, then process as lines
|
||||
string tempGameList = RCLONE.runRcloneCommand_DownloadConfig($"cat \"{remote}:{RcloneGamesFolder}/VRP-GameList.txt\"").Output;
|
||||
if (MainForm.debugMode)
|
||||
{
|
||||
File.WriteAllText("VRP-GamesList.txt", tempGameList);
|
||||
}
|
||||
if (!tempGameList.Equals(""))
|
||||
{
|
||||
string[] gameListSplited = tempGameList.Split(new[] { '\n' });
|
||||
gameListSplited = gameListSplited.Skip(1).ToArray();
|
||||
foreach (string game in gameListSplited)
|
||||
// Avoid redundant disk I/O: write only if non-empty
|
||||
if (!string.IsNullOrEmpty(tempGameList))
|
||||
{
|
||||
if (game.Length > 1)
|
||||
File.WriteAllText("VRP-GamesList.txt", tempGameList);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tempGameList))
|
||||
{
|
||||
bool isFirstLine = true;
|
||||
foreach (var line in SplitLines(tempGameList))
|
||||
{
|
||||
if (isFirstLine)
|
||||
{
|
||||
isFirstLine = false; // skip header
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var splitGame = line.Split(new[] { ';' }, StringSplitOptions.None);
|
||||
if (splitGame.Length > 1)
|
||||
{
|
||||
string[] splitGame = game.Split(';');
|
||||
games.Add(splitGame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateDownloadConfig()
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
|
||||
| SecurityProtocolType.Tls11
|
||||
| SecurityProtocolType.Tls12
|
||||
| SecurityProtocolType.Ssl3;
|
||||
Logger.Log($"Attempting to Update Download Config");
|
||||
try
|
||||
{
|
||||
string configUrl = "https://wiki.vrpirates.club/downloads/vrp.download.config";
|
||||
|
||||
HttpWebRequest getUrl = (HttpWebRequest)WebRequest.Create(configUrl);
|
||||
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
|
||||
{
|
||||
string resultString = responseReader.ReadToEnd();
|
||||
|
||||
Logger.Log($"Retrived updated config from: {configUrl}");
|
||||
|
||||
if (File.Exists(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new"))
|
||||
File.Delete(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new");
|
||||
File.Create(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new").Close();
|
||||
File.WriteAllText(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new", resultString);
|
||||
|
||||
if (!File.Exists(Environment.CurrentDirectory + "\\rclone\\hash.txt"))
|
||||
File.Create(Environment.CurrentDirectory + "\\rclone\\hash.txt").Close();
|
||||
|
||||
string newConfig = CalculateMD5(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new");
|
||||
string oldConfig = File.ReadAllText(Environment.CurrentDirectory + "\\rclone\\hash.txt");
|
||||
|
||||
if (!File.Exists(Environment.CurrentDirectory + "\\rclone\\vrp.download.config"))
|
||||
oldConfig = "Config Doesnt Exist!";
|
||||
|
||||
Logger.Log($"Online Config Hash: {newConfig}; Local Config Hash: {oldConfig}");
|
||||
|
||||
if (newConfig != oldConfig)
|
||||
{
|
||||
Logger.Log($"Updated Config Hash is different than the current Config. Updating Configuration File.");
|
||||
|
||||
if (File.Exists(Environment.CurrentDirectory + "\\rclone\\vrp.download.config"))
|
||||
File.Delete(Environment.CurrentDirectory + "\\rclone\\vrp.download.config");
|
||||
File.Move(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new", Environment.CurrentDirectory + "\\rclone\\vrp.download.config");
|
||||
|
||||
File.WriteAllText(Environment.CurrentDirectory + "\\rclone\\hash.txt", string.Empty);
|
||||
File.WriteAllText(Environment.CurrentDirectory + "\\rclone\\hash.txt", newConfig);
|
||||
} else
|
||||
{
|
||||
Logger.Log($"Updated Config Hash matches last download. Not updating.");
|
||||
|
||||
if (File.Exists(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new"))
|
||||
File.Delete(Environment.CurrentDirectory + "\\rclone\\vrp.download.config_new");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void updateUploadConfig()
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
|
||||
| SecurityProtocolType.Tls11
|
||||
| SecurityProtocolType.Tls12
|
||||
| SecurityProtocolType.Ssl3;
|
||||
Logger.Log($"Attempting to Update Upload Config");
|
||||
_ = Logger.Log($"Attempting to Update Upload Config");
|
||||
try
|
||||
{
|
||||
string configUrl = "https://wiki.vrpirates.club/downloads/vrp.upload.config";
|
||||
string configUrl = "https://vrpirates.wiki/downloads/vrp.upload.config";
|
||||
|
||||
HttpWebRequest getUrl = (HttpWebRequest)WebRequest.Create(configUrl);
|
||||
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
|
||||
// Use DnsHelper for fallback DNS support
|
||||
var getUrl = DnsHelper.CreateWebRequest(configUrl);
|
||||
using (var response = getUrl.GetResponse())
|
||||
using (var stream = response.GetResponseStream())
|
||||
using (var responseReader = new StreamReader(stream))
|
||||
{
|
||||
string resultString = responseReader.ReadToEnd();
|
||||
|
||||
Logger.Log($"Retrived updated config from: {configUrl}");
|
||||
_ = Logger.Log($"Retrieved updated config from: {configUrl}");
|
||||
|
||||
File.WriteAllText(Environment.CurrentDirectory + "\\rclone\\vrp.upload.config", resultString);
|
||||
// Avoid multiple combines; write once
|
||||
string uploadConfigPath = Path.Combine(Environment.CurrentDirectory, "rclone", "vrp.upload.config");
|
||||
File.WriteAllText(uploadConfigPath, resultString);
|
||||
|
||||
Logger.Log("Upload config updated successfully.");
|
||||
_ = Logger.Log("Upload config updated successfully.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"Failed to update Upload config: {e.Message}");
|
||||
_ = Logger.Log($"Failed to update Upload config: {e.Message}", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updatePublicConfig()
|
||||
// Fast directory delete using Windows cmd - faster than .NET's Directory.Delete
|
||||
// for large directories with many files (e.g., thumbnails folder with 1000+ images)
|
||||
private static void SafeDeleteDirectory(string path)
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
|
||||
| SecurityProtocolType.Tls11
|
||||
| SecurityProtocolType.Tls12
|
||||
| SecurityProtocolType.Ssl3;
|
||||
Logger.Log($"Attempting to Update Public Config");
|
||||
// Avoid exceptions when directory is missing
|
||||
if (!Directory.Exists(path))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
string configUrl = "https://wiki.vrpirates.club/downloads/vrp-public.json";
|
||||
|
||||
HttpWebRequest getUrl = (HttpWebRequest)WebRequest.Create(configUrl);
|
||||
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
|
||||
// Use Windows rd command which is ~10x faster than .NET's recursive delete
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
string resultString = responseReader.ReadToEnd();
|
||||
FileName = "cmd.exe",
|
||||
Arguments = $"/c rd /s /q \"{path}\"",
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
|
||||
Logger.Log($"Retrived updated config from: {configUrl}");
|
||||
|
||||
File.WriteAllText(Environment.CurrentDirectory + "\\vrp-public.json", resultString);
|
||||
|
||||
Logger.Log("Public config updated successfully.");
|
||||
using (var process = Process.Start(psi))
|
||||
{
|
||||
// Wait with timeout to prevent hanging
|
||||
if (!process.WaitForExit(30000)) // 30 second timeout
|
||||
{
|
||||
try { process.Kill(); } catch { }
|
||||
Logger.Log($"Directory delete timed out for: {path}", LogLevel.WARNING);
|
||||
// Fallback to .NET delete
|
||||
FallbackDelete(path);
|
||||
}
|
||||
else if (process.ExitCode != 0 && Directory.Exists(path))
|
||||
{
|
||||
// Command failed, try fallback
|
||||
FallbackDelete(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to update Public config: {e.Message}");
|
||||
Logger.Log($"Fast delete failed for {path}: {ex.Message}", LogLevel.WARNING);
|
||||
// Fallback to standard .NET delete
|
||||
FallbackDelete(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static string CalculateMD5(string filename)
|
||||
// Fallback delete method using standard .NET
|
||||
private static void FallbackDelete(string path)
|
||||
{
|
||||
using (var md5 = MD5.Create())
|
||||
try
|
||||
{
|
||||
using (var stream = File.OpenRead(filename))
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
var hash = md5.ComputeHash(stream);
|
||||
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||
FileSystemUtilities.TryDeleteDirectory(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Fallback delete also failed for {path}: {ex.Message}", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// Move directory only if source exists
|
||||
private static void MoveIfExists(string sourceDir, string destDir)
|
||||
{
|
||||
if (Directory.Exists(sourceDir))
|
||||
{
|
||||
// Ensure destination does not exist to prevent IOException
|
||||
// Use fast delete method
|
||||
SafeDeleteDirectory(destDir);
|
||||
Directory.Move(sourceDir, destDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Logger.Log($"Source directory not found: {sourceDir}", LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
// Efficient, cross-platform line splitting for string buffers
|
||||
private static IEnumerable<string> SplitLines(string s)
|
||||
{
|
||||
// Handle both \r\n and \n without allocating intermediate arrays
|
||||
using (var reader = new StringReader(s))
|
||||
{
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using AndroidSideloader.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Security.Cryptography;
|
||||
@@ -6,61 +7,44 @@ using System.Text;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class SideloaderUtilities
|
||||
internal class SideloaderUtilities
|
||||
{
|
||||
private static readonly SettingsManager settings = SettingsManager.Instance;
|
||||
public static bool CheckFolderIsObb(string path)
|
||||
{
|
||||
string[] files = Directory.GetFiles(path);
|
||||
|
||||
foreach (string file in files)
|
||||
if (file.EndsWith(".obb") || Path.GetDirectoryName(file).Contains(".") && !Path.GetDirectoryName(file).Contains("_data"))
|
||||
{
|
||||
if (file.EndsWith(".obb") || (Path.GetDirectoryName(file).Contains(".") && !Path.GetDirectoryName(file).Contains("_data")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string uuid = null;
|
||||
public static string UUID()
|
||||
{
|
||||
if (uuid != null) return uuid;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_Processor");
|
||||
|
||||
foreach (ManagementObject queryObj in searcher.Get())
|
||||
uuid = settings.UUID;
|
||||
if (string.IsNullOrEmpty(uuid) != true)
|
||||
{
|
||||
sb.Append(queryObj["NumberOfCores"]);
|
||||
sb.Append(queryObj["ProcessorId"]);
|
||||
sb.Append(queryObj["Name"]);
|
||||
sb.Append(queryObj["SocketDesignation"]);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
searcher = new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_BIOS");
|
||||
|
||||
foreach (ManagementObject queryObj in searcher.Get())
|
||||
var bytes = new byte[16];
|
||||
using (var rng = new RNGCryptoServiceProvider())
|
||||
{
|
||||
sb.Append(queryObj["Manufacturer"]);
|
||||
sb.Append(queryObj["Name"]);
|
||||
sb.Append(queryObj["Version"]);
|
||||
|
||||
rng.GetBytes(bytes);
|
||||
}
|
||||
|
||||
searcher = new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_BaseBoard");
|
||||
uuid = BitConverter.ToString(bytes).Replace("-", "");
|
||||
|
||||
foreach (ManagementObject queryObj in searcher.Get())
|
||||
{
|
||||
sb.Append(queryObj["Product"]);
|
||||
}
|
||||
settings.UUID = uuid;
|
||||
settings.Save();
|
||||
|
||||
var bytes = Encoding.ASCII.GetBytes(sb.ToString());
|
||||
SHA256Managed sha = new SHA256Managed();
|
||||
|
||||
byte[] hash = sha.ComputeHash(bytes);
|
||||
|
||||
uuid = BitConverter.ToString(hash).Replace("-", "");
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
58
Splash.Designer.cs
generated
@@ -1,58 +0,0 @@
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
partial class Splash
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Splash));
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// Splash
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
|
||||
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
|
||||
this.CausesValidation = false;
|
||||
this.ClientSize = new System.Drawing.Size(427, 250);
|
||||
this.ControlBox = false;
|
||||
this.DoubleBuffered = true;
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.Name = "Splash";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Splash";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
20
Splash.cs
@@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class Splash : Form
|
||||
{
|
||||
public Splash()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
413
Splash.resx
@@ -1,413 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
127
SpoofForm.Designer.cs
generated
@@ -1,127 +0,0 @@
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
partial class SpoofForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.PackageNameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.SpoofButton = new AndroidSideloader.RoundButton();
|
||||
this.RandomizeButton = new AndroidSideloader.RoundButton();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// PackageNameTextBox
|
||||
//
|
||||
this.PackageNameTextBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
|
||||
this.PackageNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.PackageNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "TextBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.PackageNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.PackageNameTextBox.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
|
||||
this.PackageNameTextBox.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
|
||||
this.PackageNameTextBox.Location = new System.Drawing.Point(13, 13);
|
||||
this.PackageNameTextBox.Name = "PackageNameTextBox";
|
||||
this.PackageNameTextBox.Size = new System.Drawing.Size(273, 24);
|
||||
this.PackageNameTextBox.TabIndex = 1;
|
||||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Location = new System.Drawing.Point(13, 43);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(273, 23);
|
||||
this.progressBar1.TabIndex = 3;
|
||||
//
|
||||
// SpoofButton
|
||||
//
|
||||
this.SpoofButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.SpoofButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.SpoofButton.BackColor = System.Drawing.Color.Transparent;
|
||||
this.SpoofButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.SpoofButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.SpoofButton.ForeColor = System.Drawing.Color.White;
|
||||
this.SpoofButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.SpoofButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.SpoofButton.Location = new System.Drawing.Point(176, 72);
|
||||
this.SpoofButton.Name = "SpoofButton";
|
||||
this.SpoofButton.Radius = 5;
|
||||
this.SpoofButton.Size = new System.Drawing.Size(110, 42);
|
||||
this.SpoofButton.Stroke = true;
|
||||
this.SpoofButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.SpoofButton.TabIndex = 5;
|
||||
this.SpoofButton.Text = "Spoof!";
|
||||
this.SpoofButton.Transparency = false;
|
||||
this.SpoofButton.Click += new System.EventHandler(this.SpoofButton_Click);
|
||||
//
|
||||
// RandomizeButton
|
||||
//
|
||||
this.RandomizeButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.RandomizeButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.RandomizeButton.BackColor = System.Drawing.Color.Transparent;
|
||||
this.RandomizeButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.RandomizeButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.RandomizeButton.ForeColor = System.Drawing.Color.White;
|
||||
this.RandomizeButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.RandomizeButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.RandomizeButton.Location = new System.Drawing.Point(12, 72);
|
||||
this.RandomizeButton.Name = "RandomizeButton";
|
||||
this.RandomizeButton.Radius = 5;
|
||||
this.RandomizeButton.Size = new System.Drawing.Size(110, 42);
|
||||
this.RandomizeButton.Stroke = true;
|
||||
this.RandomizeButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.RandomizeButton.TabIndex = 6;
|
||||
this.RandomizeButton.Text = "Randomize";
|
||||
this.RandomizeButton.Transparency = false;
|
||||
this.RandomizeButton.Click += new System.EventHandler(this.RandomizeButton_Click);
|
||||
//
|
||||
// SpoofForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.BackgroundImage = global::AndroidSideloader.Properties.Resources.pattern_cubes_1_1_1_0_0_0_1__000000_212121;
|
||||
this.ClientSize = new System.Drawing.Size(300, 131);
|
||||
this.Controls.Add(this.RandomizeButton);
|
||||
this.Controls.Add(this.SpoofButton);
|
||||
this.Controls.Add(this.progressBar1);
|
||||
this.Controls.Add(this.PackageNameTextBox);
|
||||
this.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.MaximumSize = new System.Drawing.Size(316, 170);
|
||||
this.MinimumSize = new System.Drawing.Size(316, 170);
|
||||
this.Name = "SpoofForm";
|
||||
this.Text = "SpoofForm";
|
||||
this.Load += new System.EventHandler(this.SpoofForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.TextBox PackageNameTextBox;
|
||||
private System.Windows.Forms.ProgressBar progressBar1;
|
||||
private RoundButton SpoofButton;
|
||||
private RoundButton RandomizeButton;
|
||||
}
|
||||
}
|
||||
74
SpoofForm.cs
@@ -1,74 +0,0 @@
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Spoofer;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public partial class SpoofForm : Form
|
||||
{
|
||||
public SpoofForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SpoofButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!spoofer.HasDependencies())
|
||||
{
|
||||
MessageBox.Show("You are missing the dependencies... Cannot spoof games");
|
||||
return;
|
||||
}
|
||||
string NewPackageName = PackageNameTextBox.Text;
|
||||
string path;
|
||||
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
openFileDialog.Filter = "Android apps (*.apk)|*.apk";
|
||||
openFileDialog.FilterIndex = 2;
|
||||
openFileDialog.RestoreDirectory = true;
|
||||
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
path = openFileDialog.FileName;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar1.Style = ProgressBarStyle.Marquee;
|
||||
|
||||
string output = "";
|
||||
//Spawn spoofer in a new thread so the ui isn't blocked
|
||||
Thread t1 = new Thread(() =>
|
||||
{
|
||||
spoofer.Init();
|
||||
output += spoofer.SpoofApk(path, NewPackageName);
|
||||
});
|
||||
t1.IsBackground = true;
|
||||
t1.Start();
|
||||
|
||||
while (t1.IsAlive)
|
||||
await Task.Delay(100);
|
||||
|
||||
|
||||
|
||||
progressBar1.Style = ProgressBarStyle.Continuous;
|
||||
|
||||
if (output.Contains("is not recognized as an internal or external command"))
|
||||
FlexibleMessageBox.Show(Sideloader.SpooferWarning);
|
||||
else
|
||||
FlexibleMessageBox.Show($"App spoofed from {spoofer.originalPackageName} to {NewPackageName}");
|
||||
}
|
||||
|
||||
private void SpoofForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
PackageNameTextBox.Text = Utilities.GeneralUtilities.RandomPackageName();
|
||||
}
|
||||
|
||||
private void RandomizeButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
PackageNameTextBox.Text = Utilities.GeneralUtilities.RandomPackageName();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
SpoofForm.resx
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
264
ToggleSwitch.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
/// <summary>
|
||||
/// An iOS-style toggle switch control with smooth animation.
|
||||
/// </summary>
|
||||
public class ToggleSwitch : Control
|
||||
{
|
||||
private bool _checked;
|
||||
private bool _isHovered;
|
||||
private float _animationProgress; // 0 = off, 1 = on
|
||||
private Timer _animationTimer;
|
||||
private const int AnimationDuration = 80; // ms
|
||||
private const int AnimationInterval = 8; // ~120fps
|
||||
private float _animationStep;
|
||||
|
||||
// Colors
|
||||
private Color _onColor = Color.FromArgb(93, 203, 173);
|
||||
private Color _offColor = Color.FromArgb(60, 65, 75);
|
||||
private Color _thumbColor = Color.White;
|
||||
private Color _onHoverColor = Color.FromArgb(110, 215, 190);
|
||||
private Color _offHoverColor = Color.FromArgb(75, 80, 90);
|
||||
|
||||
public event EventHandler CheckedChanged;
|
||||
|
||||
public ToggleSwitch()
|
||||
{
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.UserPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.ResizeRedraw |
|
||||
ControlStyles.SupportsTransparentBackColor |
|
||||
ControlStyles.StandardClick |
|
||||
ControlStyles.StandardDoubleClick, true);
|
||||
|
||||
// Disable double-click so rapid clicks are treated as separate clicks
|
||||
SetStyle(ControlStyles.StandardDoubleClick, false);
|
||||
|
||||
Size = new Size(44, 24);
|
||||
Cursor = Cursors.Hand;
|
||||
BackColor = Color.Transparent;
|
||||
|
||||
_animationTimer = new Timer { Interval = AnimationInterval };
|
||||
_animationTimer.Tick += AnimationTimer_Tick;
|
||||
_animationStep = (float)AnimationInterval / AnimationDuration;
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("Gets or sets whether the toggle is in the 'on' state.")]
|
||||
[DefaultValue(false)]
|
||||
public bool Checked
|
||||
{
|
||||
get => _checked;
|
||||
set
|
||||
{
|
||||
if (_checked != value)
|
||||
{
|
||||
_checked = value;
|
||||
StartAnimation();
|
||||
OnCheckedChanged(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the checked state without triggering animation or events.
|
||||
/// Using this for initial state setup.
|
||||
/// </summary>
|
||||
public void SetCheckedSilent(bool value)
|
||||
{
|
||||
_checked = value;
|
||||
_animationProgress = value ? 1f : 0f;
|
||||
_animationTimer.Stop();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("The color of the toggle when it is on.")]
|
||||
public Color OnColor
|
||||
{
|
||||
get => _onColor;
|
||||
set { _onColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("The color of the toggle when it is off.")]
|
||||
public Color OffColor
|
||||
{
|
||||
get => _offColor;
|
||||
set { _offColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
[Category("Appearance")]
|
||||
[Description("The color of the thumb (circle).")]
|
||||
public Color ThumbColor
|
||||
{
|
||||
get => _thumbColor;
|
||||
set { _thumbColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
protected virtual void OnCheckedChanged(EventArgs e)
|
||||
{
|
||||
CheckedChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void StartAnimation()
|
||||
{
|
||||
if (!_animationTimer.Enabled)
|
||||
{
|
||||
_animationTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void AnimationTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
float target = _checked ? 1f : 0f;
|
||||
|
||||
if (_animationProgress < target)
|
||||
{
|
||||
_animationProgress += _animationStep;
|
||||
if (_animationProgress >= target)
|
||||
{
|
||||
_animationProgress = target;
|
||||
_animationTimer.Stop();
|
||||
}
|
||||
}
|
||||
else if (_animationProgress > target)
|
||||
{
|
||||
_animationProgress -= _animationStep;
|
||||
if (_animationProgress <= target)
|
||||
{
|
||||
_animationProgress = target;
|
||||
_animationTimer.Stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_animationTimer.Stop();
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
|
||||
Graphics g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
int width = Width;
|
||||
int height = Height;
|
||||
int padding = 2;
|
||||
int thumbDiameter = height - (padding * 2);
|
||||
int trackRadius = height / 2;
|
||||
|
||||
Color trackColor;
|
||||
if (_isHovered)
|
||||
{
|
||||
trackColor = InterpolateColor(_offHoverColor, _onHoverColor, _animationProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
trackColor = InterpolateColor(_offColor, _onColor, _animationProgress);
|
||||
}
|
||||
|
||||
Rectangle trackRect = new Rectangle(0, 0, width, height);
|
||||
using (GraphicsPath trackPath = CreateRoundedRectPath(trackRect, trackRadius))
|
||||
using (SolidBrush trackBrush = new SolidBrush(trackColor))
|
||||
{
|
||||
g.FillPath(trackBrush, trackPath);
|
||||
}
|
||||
|
||||
int thumbMinX = padding;
|
||||
int thumbMaxX = width - thumbDiameter - padding;
|
||||
float easedProgress = EaseOutQuad(_animationProgress);
|
||||
int thumbX = (int)(thumbMinX + (thumbMaxX - thumbMinX) * easedProgress);
|
||||
int thumbY = padding;
|
||||
|
||||
Rectangle shadowRect = new Rectangle(thumbX + 1, thumbY + 1, thumbDiameter, thumbDiameter);
|
||||
using (SolidBrush shadowBrush = new SolidBrush(Color.FromArgb(40, 0, 0, 0)))
|
||||
{
|
||||
g.FillEllipse(shadowBrush, shadowRect);
|
||||
}
|
||||
|
||||
Rectangle thumbRect = new Rectangle(thumbX, thumbY, thumbDiameter, thumbDiameter);
|
||||
using (SolidBrush thumbBrush = new SolidBrush(_thumbColor))
|
||||
{
|
||||
g.FillEllipse(thumbBrush, thumbRect);
|
||||
}
|
||||
}
|
||||
|
||||
private float EaseOutQuad(float t)
|
||||
{
|
||||
return t * (2 - t);
|
||||
}
|
||||
|
||||
private Color InterpolateColor(Color from, Color to, float progress)
|
||||
{
|
||||
int r = (int)(from.R + (to.R - from.R) * progress);
|
||||
int g = (int)(from.G + (to.G - from.G) * progress);
|
||||
int b = (int)(from.B + (to.B - from.B) * progress);
|
||||
int a = (int)(from.A + (to.A - from.A) * progress);
|
||||
return Color.FromArgb(a, r, g, b);
|
||||
}
|
||||
|
||||
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
int diameter = radius * 2;
|
||||
|
||||
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90);
|
||||
path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90);
|
||||
path.CloseFigure();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(EventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
_isHovered = true;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
_isHovered = false;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
// Toggle immediately on mouse down for responsive feel
|
||||
_checked = !_checked;
|
||||
StartAnimation();
|
||||
OnCheckedChanged(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_animationTimer?.Stop();
|
||||
_animationTimer?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,21 +7,36 @@ namespace AndroidSideloader
|
||||
{
|
||||
public static void MakeTransparent(Control control, Graphics g)
|
||||
{
|
||||
var parent = control.Parent;
|
||||
if (parent == null) return;
|
||||
var bounds = control.Bounds;
|
||||
var siblings = parent.Controls;
|
||||
Control parent = control.Parent;
|
||||
if (parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rectangle bounds = control.Bounds;
|
||||
Control.ControlCollection siblings = parent.Controls;
|
||||
int index = siblings.IndexOf(control);
|
||||
Bitmap behind = null;
|
||||
for (int i = siblings.Count - 1; i > index; i--)
|
||||
{
|
||||
var c = siblings[i];
|
||||
if (!c.Bounds.IntersectsWith(bounds)) continue;
|
||||
Control c = siblings[i];
|
||||
if (!c.Bounds.IntersectsWith(bounds))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (behind == null)
|
||||
{
|
||||
behind = new Bitmap(control.Parent.ClientSize.Width, control.Parent.ClientSize.Height);
|
||||
}
|
||||
|
||||
c.DrawToBitmap(behind, c.Bounds);
|
||||
}
|
||||
if (behind == null) return;
|
||||
if (behind == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g.DrawImage(behind, control.ClientRectangle, bounds, GraphicsUnit.Pixel);
|
||||
behind.Dispose();
|
||||
}
|
||||
|
||||
120
UpdateForm.Designer.cs
generated
@@ -1,5 +1,4 @@
|
||||
|
||||
namespace AndroidSideloader
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
partial class UpdateForm
|
||||
{
|
||||
@@ -30,57 +29,85 @@ namespace AndroidSideloader
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.YesUpdate = new AndroidSideloader.RoundButton();
|
||||
this.panel3 = new System.Windows.Forms.Panel();
|
||||
this.UpdateTextBox = new System.Windows.Forms.RichTextBox();
|
||||
this.UpdateVerLabel = new System.Windows.Forms.Label();
|
||||
this.CurVerLabel = new System.Windows.Forms.Label();
|
||||
this.SkipUpdate = new System.Windows.Forms.Label();
|
||||
this.YesUpdate = new AndroidSideloader.RoundButton();
|
||||
this.panel1.SuspendLayout();
|
||||
this.panel3.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.panel1.BackgroundImage = global::AndroidSideloader.Properties.Resources.pattern_cubes_1_1_1_0_0_0_1__000000_212121;
|
||||
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
|
||||
this.panel1.Controls.Add(this.YesUpdate);
|
||||
this.panel1.Controls.Add(this.panel3);
|
||||
this.panel1.Controls.Add(this.UpdateVerLabel);
|
||||
this.panel1.Controls.Add(this.CurVerLabel);
|
||||
this.panel1.Controls.Add(this.SkipUpdate);
|
||||
this.panel1.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.panel1.Location = new System.Drawing.Point(-6, -6);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(474, 305);
|
||||
this.panel1.Padding = new System.Windows.Forms.Padding(20, 50, 20, 20);
|
||||
this.panel1.Size = new System.Drawing.Size(480, 320);
|
||||
this.panel1.TabIndex = 5;
|
||||
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseDown);
|
||||
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseMove);
|
||||
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseUp);
|
||||
//
|
||||
// YesUpdate
|
||||
//
|
||||
this.YesUpdate.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(113)))), ((int)(((byte)(223)))), ((int)(((byte)(193)))));
|
||||
this.YesUpdate.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.YesUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.YesUpdate.BackColor = System.Drawing.Color.Transparent;
|
||||
this.YesUpdate.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.YesUpdate.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.YesUpdate.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
|
||||
this.YesUpdate.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
|
||||
this.YesUpdate.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold);
|
||||
this.YesUpdate.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
|
||||
this.YesUpdate.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.YesUpdate.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(73)))), ((int)(((byte)(183)))), ((int)(((byte)(153)))));
|
||||
this.YesUpdate.Location = new System.Drawing.Point(340, 259);
|
||||
this.YesUpdate.Name = "YesUpdate";
|
||||
this.YesUpdate.Radius = 6;
|
||||
this.YesUpdate.Size = new System.Drawing.Size(120, 36);
|
||||
this.YesUpdate.Stroke = false;
|
||||
this.YesUpdate.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.YesUpdate.TabIndex = 2;
|
||||
this.YesUpdate.Text = "Update Now";
|
||||
this.YesUpdate.Transparency = false;
|
||||
this.YesUpdate.Click += new System.EventHandler(this.YesUpdate_Click);
|
||||
//
|
||||
// panel3
|
||||
//
|
||||
this.panel3.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
|
||||
this.panel3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
|
||||
this.panel3.Controls.Add(this.UpdateTextBox);
|
||||
this.panel3.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.panel3.Location = new System.Drawing.Point(21, 19);
|
||||
this.panel3.Location = new System.Drawing.Point(20, 50);
|
||||
this.panel3.Name = "panel3";
|
||||
this.panel3.Size = new System.Drawing.Size(432, 218);
|
||||
this.panel3.Padding = new System.Windows.Forms.Padding(12, 10, 12, 10);
|
||||
this.panel3.Size = new System.Drawing.Size(440, 200);
|
||||
this.panel3.TabIndex = 0;
|
||||
//
|
||||
// UpdateTextBox
|
||||
//
|
||||
this.UpdateTextBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.ComboBoxColor;
|
||||
this.UpdateTextBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
|
||||
this.UpdateTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.UpdateTextBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "ComboBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.UpdateTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.25F);
|
||||
this.UpdateTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.UpdateTextBox.Font = new System.Drawing.Font("Segoe UI", 9.5F);
|
||||
this.UpdateTextBox.ForeColor = System.Drawing.Color.White;
|
||||
this.UpdateTextBox.Location = new System.Drawing.Point(12, 8);
|
||||
this.UpdateTextBox.Location = new System.Drawing.Point(12, 10);
|
||||
this.UpdateTextBox.Margin = new System.Windows.Forms.Padding(6);
|
||||
this.UpdateTextBox.Name = "UpdateTextBox";
|
||||
this.UpdateTextBox.ReadOnly = true;
|
||||
this.UpdateTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
|
||||
this.UpdateTextBox.Size = new System.Drawing.Size(408, 200);
|
||||
this.UpdateTextBox.Size = new System.Drawing.Size(416, 180);
|
||||
this.UpdateTextBox.TabIndex = 1;
|
||||
this.UpdateTextBox.Text = "";
|
||||
this.UpdateTextBox.TextChanged += new System.EventHandler(this.UpdateTextBox_TextChanged);
|
||||
@@ -90,73 +117,54 @@ namespace AndroidSideloader
|
||||
//
|
||||
// UpdateVerLabel
|
||||
//
|
||||
this.UpdateVerLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.UpdateVerLabel.AutoSize = true;
|
||||
this.UpdateVerLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.UpdateVerLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F);
|
||||
this.UpdateVerLabel.ForeColor = System.Drawing.SystemColors.Control;
|
||||
this.UpdateVerLabel.Location = new System.Drawing.Point(21, 261);
|
||||
this.UpdateVerLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
||||
this.UpdateVerLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
|
||||
this.UpdateVerLabel.Location = new System.Drawing.Point(20, 285);
|
||||
this.UpdateVerLabel.Name = "UpdateVerLabel";
|
||||
this.UpdateVerLabel.Size = new System.Drawing.Size(94, 15);
|
||||
this.UpdateVerLabel.Size = new System.Drawing.Size(95, 15);
|
||||
this.UpdateVerLabel.TabIndex = 3;
|
||||
this.UpdateVerLabel.Text = "Update Version:";
|
||||
//
|
||||
// CurVerLabel
|
||||
//
|
||||
this.CurVerLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.CurVerLabel.AutoSize = true;
|
||||
this.CurVerLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.CurVerLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F);
|
||||
this.CurVerLabel.ForeColor = System.Drawing.SystemColors.Control;
|
||||
this.CurVerLabel.Location = new System.Drawing.Point(21, 245);
|
||||
this.CurVerLabel.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||
this.CurVerLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.CurVerLabel.Location = new System.Drawing.Point(20, 266);
|
||||
this.CurVerLabel.Name = "CurVerLabel";
|
||||
this.CurVerLabel.Size = new System.Drawing.Size(94, 15);
|
||||
this.CurVerLabel.Size = new System.Drawing.Size(91, 15);
|
||||
this.CurVerLabel.TabIndex = 2;
|
||||
this.CurVerLabel.Text = "Current Version:";
|
||||
//
|
||||
// SkipUpdate
|
||||
//
|
||||
this.SkipUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.SkipUpdate.AutoSize = true;
|
||||
this.SkipUpdate.BackColor = System.Drawing.Color.Transparent;
|
||||
this.SkipUpdate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.SkipUpdate.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F);
|
||||
this.SkipUpdate.ForeColor = System.Drawing.Color.Silver;
|
||||
this.SkipUpdate.Location = new System.Drawing.Point(374, 279);
|
||||
this.SkipUpdate.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.SkipUpdate.Font = new System.Drawing.Font("Segoe UI", 8.5F);
|
||||
this.SkipUpdate.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
|
||||
this.SkipUpdate.Location = new System.Drawing.Point(380, 297);
|
||||
this.SkipUpdate.Name = "SkipUpdate";
|
||||
this.SkipUpdate.Size = new System.Drawing.Size(76, 13);
|
||||
this.SkipUpdate.Size = new System.Drawing.Size(73, 15);
|
||||
this.SkipUpdate.TabIndex = 4;
|
||||
this.SkipUpdate.Text = "𝖲𝖪𝖨𝖯 𝖥𝖮𝖱 𝖭𝖮𝖶";
|
||||
this.SkipUpdate.Text = "Skip for now";
|
||||
this.SkipUpdate.Click += new System.EventHandler(this.SkipUpdate_Click);
|
||||
//
|
||||
// YesUpdate
|
||||
//
|
||||
this.YesUpdate.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.YesUpdate.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
|
||||
this.YesUpdate.BackColor = System.Drawing.Color.Transparent;
|
||||
this.YesUpdate.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.YesUpdate.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.YesUpdate.ForeColor = System.Drawing.Color.White;
|
||||
this.YesUpdate.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.YesUpdate.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.YesUpdate.Location = new System.Drawing.Point(339, 245);
|
||||
this.YesUpdate.Name = "YesUpdate";
|
||||
this.YesUpdate.Radius = 5;
|
||||
this.YesUpdate.Size = new System.Drawing.Size(111, 31);
|
||||
this.YesUpdate.Stroke = true;
|
||||
this.YesUpdate.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.YesUpdate.TabIndex = 2;
|
||||
this.YesUpdate.Text = "Update Now";
|
||||
this.YesUpdate.Transparency = false;
|
||||
this.YesUpdate.Click += new System.EventHandler(this.YesUpdate_Click);
|
||||
//
|
||||
// UpdateForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoValidate = System.Windows.Forms.AutoValidate.EnablePreventFocusChange;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(29)))), ((int)(((byte)(29)))));
|
||||
this.ClientSize = new System.Drawing.Size(462, 291);
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
|
||||
this.ClientSize = new System.Drawing.Size(480, 320);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.panel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.Name = "UpdateForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseDown);
|
||||
|
||||
219
UpdateForm.cs
@@ -1,11 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
@@ -15,29 +10,220 @@ namespace AndroidSideloader
|
||||
private bool mouseDown;
|
||||
private Point lastLocation;
|
||||
|
||||
// Modern theme colors
|
||||
private static readonly Color BackgroundColor = Color.FromArgb(20, 24, 29);
|
||||
private static readonly Color PanelColor = Color.FromArgb(28, 32, 38);
|
||||
private static readonly Color TextColor = Color.White;
|
||||
private static readonly Color SecondaryTextColor = Color.FromArgb(160, 165, 175);
|
||||
private static readonly Color BorderColor = Color.FromArgb(60, 65, 75);
|
||||
|
||||
public UpdateForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.CenterToScreen();
|
||||
CurVerLabel.Text += " " + Updater.LocalVersion;
|
||||
UpdateVerLabel.Text += " " + Updater.currentVersion;
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
|
||||
ApplyModernTheme();
|
||||
CenterToScreen();
|
||||
CurVerLabel.Text = $"Current Version: {Updater.LocalVersion}";
|
||||
UpdateVerLabel.Text = $"Update Version: {Updater.currentVersion}";
|
||||
UpdateTextBox.Text = Updater.changelog;
|
||||
}
|
||||
|
||||
private void ApplyModernTheme()
|
||||
{
|
||||
// Form settings
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
this.BackColor = BackgroundColor;
|
||||
this.DoubleBuffered = true;
|
||||
|
||||
// Enable double buffering on panels for smooth rounded corners
|
||||
EnableDoubleBuffering(panel1);
|
||||
EnableDoubleBuffering(panel3);
|
||||
|
||||
// Add custom paint handler for rounded panel1 (main container)
|
||||
panel1.Paint += Panel1_Paint;
|
||||
panel1.BackColor = Color.Transparent;
|
||||
|
||||
// Add custom paint handler for rounded panel3 (changelog container)
|
||||
panel3.Paint += Panel3_Paint;
|
||||
panel3.BackColor = Color.Transparent;
|
||||
|
||||
// Update textbox to have matching background
|
||||
UpdateTextBox.BackColor = PanelColor;
|
||||
|
||||
// Add title label
|
||||
var titleLabel = new Label
|
||||
{
|
||||
Text = "Update Available",
|
||||
Font = new Font("Segoe UI", 12F, FontStyle.Bold),
|
||||
ForeColor = TextColor,
|
||||
BackColor = Color.Transparent,
|
||||
AutoSize = true,
|
||||
Location = new Point(20, 15)
|
||||
};
|
||||
panel1.Controls.Add(titleLabel);
|
||||
titleLabel.BringToFront();
|
||||
|
||||
// Add close button
|
||||
var closeButton = new Label
|
||||
{
|
||||
Text = "✕",
|
||||
Font = new Font("Segoe UI", 10F),
|
||||
ForeColor = SecondaryTextColor,
|
||||
BackColor = Color.Transparent,
|
||||
AutoSize = true,
|
||||
Cursor = Cursors.Hand,
|
||||
Location = new Point(this.ClientSize.Width - 30, 10),
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Right
|
||||
};
|
||||
closeButton.Click += (s, e) => Close();
|
||||
closeButton.MouseEnter += (s, e) => closeButton.ForeColor = Color.FromArgb(220, 80, 80);
|
||||
closeButton.MouseLeave += (s, e) => closeButton.ForeColor = SecondaryTextColor;
|
||||
panel1.Controls.Add(closeButton);
|
||||
closeButton.BringToFront();
|
||||
|
||||
// Apply custom painting for form rounded corners and border
|
||||
this.Paint += UpdateForm_Paint;
|
||||
}
|
||||
|
||||
private void EnableDoubleBuffering(Panel panel)
|
||||
{
|
||||
typeof(Panel).InvokeMember("DoubleBuffered",
|
||||
System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic,
|
||||
null, panel, new object[] { true });
|
||||
}
|
||||
|
||||
private void Panel1_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
var panel = sender as Panel;
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
int radius = 12;
|
||||
var rect = new Rectangle(0, 0, panel.Width - 1, panel.Height - 1);
|
||||
|
||||
using (var path = CreateRoundedRectPath(rect, radius))
|
||||
{
|
||||
// Fill background
|
||||
using (var brush = new SolidBrush(BackgroundColor))
|
||||
{
|
||||
e.Graphics.FillPath(brush, path);
|
||||
}
|
||||
|
||||
// Draw border
|
||||
using (var pen = new Pen(BorderColor, 1f))
|
||||
{
|
||||
e.Graphics.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply rounded region to clip children
|
||||
using (var regionPath = CreateRoundedRectPath(new Rectangle(0, 0, panel.Width, panel.Height), radius))
|
||||
{
|
||||
panel.Region = new Region(regionPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void Panel3_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
var panel = sender as Panel;
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
int radius = 10;
|
||||
var rect = new Rectangle(0, 0, panel.Width - 1, panel.Height - 1);
|
||||
|
||||
using (var path = CreateRoundedRectPath(rect, radius))
|
||||
{
|
||||
// Fill background
|
||||
using (var brush = new SolidBrush(PanelColor))
|
||||
{
|
||||
e.Graphics.FillPath(brush, path);
|
||||
}
|
||||
|
||||
// Draw border
|
||||
using (var pen = new Pen(BorderColor, 1f))
|
||||
{
|
||||
e.Graphics.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply rounded region to clip children
|
||||
using (var regionPath = CreateRoundedRectPath(new Rectangle(0, 0, panel.Width, panel.Height), radius))
|
||||
{
|
||||
panel.Region = new Region(regionPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateForm_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
int w = this.ClientSize.Width;
|
||||
int h = this.ClientSize.Height;
|
||||
int radius = 12;
|
||||
|
||||
// Draw border
|
||||
using (var borderPen = new Pen(BorderColor, 1f))
|
||||
using (var path = CreateRoundedRectPath(new Rectangle(0, 0, w - 1, h - 1), radius))
|
||||
{
|
||||
e.Graphics.DrawPath(borderPen, path);
|
||||
}
|
||||
|
||||
// Apply rounded region
|
||||
using (var regionPath = CreateRoundedRectPath(new Rectangle(0, 0, w, h), radius))
|
||||
{
|
||||
this.Region = new Region(regionPath);
|
||||
}
|
||||
}
|
||||
|
||||
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
|
||||
if (radius <= 0)
|
||||
{
|
||||
path.AddRectangle(rect);
|
||||
return path;
|
||||
}
|
||||
|
||||
int diameter = radius * 2;
|
||||
diameter = Math.Min(diameter, Math.Min(rect.Width, rect.Height));
|
||||
radius = diameter / 2;
|
||||
|
||||
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
|
||||
|
||||
// Top left arc
|
||||
path.AddArc(arcRect, 180, 90);
|
||||
// Top right arc
|
||||
arcRect.X = rect.Right - diameter;
|
||||
path.AddArc(arcRect, 270, 90);
|
||||
// Bottom right arc
|
||||
arcRect.Y = rect.Bottom - diameter;
|
||||
path.AddArc(arcRect, 0, 90);
|
||||
// Bottom left arc
|
||||
arcRect.X = rect.Left;
|
||||
path.AddArc(arcRect, 90, 90);
|
||||
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
|
||||
private void YesUpdate_Click(object sender, EventArgs e)
|
||||
{
|
||||
Updater.doUpdate();
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SkipUpdate_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void UpdateTextBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void UpdateForm_MouseDown(object sender, MouseEventArgs e)
|
||||
@@ -50,10 +236,9 @@ namespace AndroidSideloader
|
||||
{
|
||||
if (mouseDown)
|
||||
{
|
||||
this.Location = new Point(
|
||||
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
|
||||
|
||||
this.Update();
|
||||
Location = new Point(
|
||||
Location.X - lastLocation.X + e.X, Location.Y - lastLocation.Y + e.Y);
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,4 +247,4 @@ namespace AndroidSideloader
|
||||
mouseDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
Updater.cs
@@ -1,73 +1,110 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using System.Net.Http;
|
||||
using System.IO;
|
||||
using AndroidSideloader;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class Updater
|
||||
internal class Updater
|
||||
{
|
||||
public static string AppName { get; set; }
|
||||
public static string Repostory { get; set; }
|
||||
private static string RawGitHubUrl;
|
||||
private static string GitHubUrl;
|
||||
public static string Repository { get; set; }
|
||||
private static readonly string RawGitHubUrl = "https://raw.githubusercontent.com/VRPirates/rookie";
|
||||
public static readonly string GitHubUrl = "https://github.com/VRPirates/rookie";
|
||||
|
||||
static readonly public string LocalVersion = "2.15";
|
||||
public static readonly string LocalVersion = "3.0.1";
|
||||
public static string currentVersion = string.Empty;
|
||||
public static string changelog = string.Empty;
|
||||
|
||||
//Check if there is a new version of the sideloader
|
||||
private static bool IsUpdateAvailable()
|
||||
// Check if there is a new version of the sideloader
|
||||
private static async Task<bool> IsUpdateAvailableAsync()
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
currentVersion = await client.GetStringAsync($"{RawGitHubUrl}/master/version");
|
||||
changelog = await client.GetStringAsync($"{RawGitHubUrl}/master/changelog.txt");
|
||||
currentVersion = currentVersion.Trim();
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare versions - only return true if server version is greater than local version
|
||||
return CompareVersions(currentVersion, LocalVersion.Trim()) > 0;
|
||||
}
|
||||
|
||||
// Compares two semantic version strings (e.g., "2.35")
|
||||
// returns: 1 if version1 > version2, -1 if version1 < version2, 0 if equal
|
||||
private static int CompareVersions(string version1, string version2)
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
try
|
||||
{
|
||||
currentVersion = client.GetStringAsync($"{RawGitHubUrl}/master/version").Result;
|
||||
changelog = client.GetStringAsync($"{RawGitHubUrl}/master/changelog.txt").Result;
|
||||
client.Dispose();
|
||||
currentVersion = currentVersion.Trim();
|
||||
// Parse versions into parts
|
||||
string[] parts1 = version1.Split('.');
|
||||
string[] parts2 = version2.Split('.');
|
||||
|
||||
// Compare each part
|
||||
int maxLength = Math.Max(parts1.Length, parts2.Length);
|
||||
for (int i = 0; i < maxLength; i++)
|
||||
{
|
||||
int v1 = i < parts1.Length && int.TryParse(parts1[i], out int p1) ? p1 : 0;
|
||||
int v2 = i < parts2.Length && int.TryParse(parts2[i], out int p2) ? p2 : 0;
|
||||
|
||||
if (v1 > v2) return 1;
|
||||
if (v1 < v2) return -1;
|
||||
}
|
||||
|
||||
return 0; // Versions are equal
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback to string comparison if parsing fails
|
||||
return string.Compare(version1, version2, StringComparison.Ordinal);
|
||||
}
|
||||
catch { return false; }
|
||||
return LocalVersion.Trim() != currentVersion;
|
||||
}
|
||||
|
||||
//Call this to ask the user if they want to update
|
||||
public static void Update()
|
||||
// Ask the user if they want to update
|
||||
public static async Task Update()
|
||||
{
|
||||
RawGitHubUrl = $"https://raw.githubusercontent.com/nerdunit/androidsideloader";
|
||||
GitHubUrl = $"https://github.com/nerdunit/androidsideloader";
|
||||
if (IsUpdateAvailable())
|
||||
if (await IsUpdateAvailableAsync())
|
||||
{
|
||||
UpdateForm upForm = new UpdateForm();
|
||||
upForm.ShowDialog(); ;
|
||||
_ = upForm.ShowDialog();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//If the user wants to update
|
||||
// If the user wants to update
|
||||
public static void doUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
ADB.RunAdbCommandToString("kill-server");
|
||||
var fileClient = new WebClient();
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
Logger.Log($"Downloading update from {GitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe to {AppName} v{currentVersion}.exe");
|
||||
fileClient.DownloadFile($"{GitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe", $"{AppName} v{currentVersion}.exe");
|
||||
fileClient.Dispose();
|
||||
Logger.Log($"Starting {AppName} v{currentVersion}.exe");
|
||||
Process.Start($"{AppName} v{currentVersion}.exe");
|
||||
//Delete current version
|
||||
|
||||
using (WebClient fileClient = new WebClient())
|
||||
{
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
|
||||
Logger.Log($"Downloading update from {GitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe to {AppName} v{currentVersion}.exe");
|
||||
fileClient.DownloadFile($"{GitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe", $"{AppName} v{currentVersion}.exe");
|
||||
|
||||
Logger.Log($"Starting {AppName} v{currentVersion}.exe");
|
||||
Process.Start($"{AppName} v{currentVersion}.exe");
|
||||
}
|
||||
|
||||
// Delete current version
|
||||
AndroidSideloader.Utilities.GeneralUtilities.Melt();
|
||||
}
|
||||
catch { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle specific exceptions that might occur during the update process
|
||||
Logger.Log($"Update failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
190
UsernameForm.Designer.cs
generated
@@ -1,96 +1,94 @@
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
partial class UsernameForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.button1 = new AndroidSideloader.RoundButton();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
|
||||
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "TextBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.textBox1.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
|
||||
this.textBox1.ForeColor = System.Drawing.Color.White;
|
||||
this.textBox1.Location = new System.Drawing.Point(13, 13);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.Size = new System.Drawing.Size(418, 24);
|
||||
this.textBox1.TabIndex = 0;
|
||||
this.textBox1.Text = "Enter your username here";
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
|
||||
this.button1.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
|
||||
this.button1.BackColor = System.Drawing.Color.Transparent;
|
||||
this.button1.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.button1.ForeColor = System.Drawing.Color.White;
|
||||
this.button1.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.button1.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.button1.Location = new System.Drawing.Point(13, 51);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Radius = 5;
|
||||
this.button1.Size = new System.Drawing.Size(418, 34);
|
||||
this.button1.Stroke = true;
|
||||
this.button1.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.button1.TabIndex = 2;
|
||||
this.button1.Text = "Create User.Json";
|
||||
this.button1.Transparency = false;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||
//
|
||||
// UsernameForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.BackgroundImage = global::AndroidSideloader.Properties.Resources.pattern_cubes_1_1_1_0_0_0_1__000000_212121;
|
||||
this.ClientSize = new System.Drawing.Size(443, 100);
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.ForeColor = System.Drawing.Color.White;
|
||||
this.MaximumSize = new System.Drawing.Size(459, 139);
|
||||
this.MinimumSize = new System.Drawing.Size(459, 139);
|
||||
this.Name = "UsernameForm";
|
||||
this.ShowIcon = false;
|
||||
this.Text = "USER.JSON";
|
||||
this.Load += new System.EventHandler(this.usernameForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private RoundButton button1;
|
||||
}
|
||||
}
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
partial class UsernameForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.button1 = new AndroidSideloader.RoundButton();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
|
||||
this.textBox1.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
|
||||
this.textBox1.ForeColor = System.Drawing.Color.White;
|
||||
this.textBox1.Location = new System.Drawing.Point(13, 13);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.Size = new System.Drawing.Size(418, 23);
|
||||
this.textBox1.TabIndex = 0;
|
||||
this.textBox1.Text = "Enter your username here";
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
|
||||
this.button1.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
|
||||
this.button1.BackColor = System.Drawing.Color.Transparent;
|
||||
this.button1.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.button1.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
|
||||
this.button1.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
|
||||
this.button1.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
|
||||
this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
|
||||
this.button1.ForeColor = System.Drawing.Color.White;
|
||||
this.button1.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.button1.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
|
||||
this.button1.Location = new System.Drawing.Point(13, 51);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Radius = 5;
|
||||
this.button1.Size = new System.Drawing.Size(418, 34);
|
||||
this.button1.Stroke = true;
|
||||
this.button1.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
|
||||
this.button1.TabIndex = 2;
|
||||
this.button1.Text = "Create User.Json";
|
||||
this.button1.Transparency = false;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||
//
|
||||
// UsernameForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
|
||||
this.ClientSize = new System.Drawing.Size(443, 100);
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.ForeColor = System.Drawing.Color.White;
|
||||
this.MaximumSize = new System.Drawing.Size(459, 139);
|
||||
this.MinimumSize = new System.Drawing.Size(459, 139);
|
||||
this.Name = "UsernameForm";
|
||||
this.Text = "USER.JSON";
|
||||
this.Load += new System.EventHandler(this.usernameForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private RoundButton button1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
@@ -12,9 +12,12 @@ namespace AndroidSideloader
|
||||
public UsernameForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Use same icon as the executable
|
||||
this.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
}
|
||||
|
||||
string defaultText;
|
||||
private string defaultText;
|
||||
|
||||
private void usernameForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
@@ -26,7 +29,7 @@ namespace AndroidSideloader
|
||||
{
|
||||
if (textBox1.Text == defaultText || textBox1.Text.Length == 0)
|
||||
{
|
||||
MessageBox.Show("Please enter your username first");
|
||||
_ = MessageBox.Show("Please enter your username first");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,12 +37,16 @@ namespace AndroidSideloader
|
||||
{
|
||||
createUserJson(textBox1.Text);
|
||||
|
||||
});
|
||||
t1.IsBackground = true;
|
||||
})
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
t1.Start();
|
||||
|
||||
while (t1.IsAlive)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
MainForm.notify("Done");
|
||||
|
||||
@@ -49,11 +56,11 @@ namespace AndroidSideloader
|
||||
|
||||
public static void createUserJson(string username)
|
||||
{
|
||||
ADB.RunAdbCommandToString($"shell settings put global username {username}");
|
||||
foreach (var jsonFileName in userJsons)
|
||||
_ = ADB.RunAdbCommandToString($"shell settings put global username \"{username}\"");
|
||||
foreach (string jsonFileName in userJsons)
|
||||
{
|
||||
createUserJsonByName(username, jsonFileName);
|
||||
ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{jsonFileName}\" " + " /sdcard/");
|
||||
_ = ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{jsonFileName}\" " + " /sdcard/");
|
||||
File.Delete(jsonFileName);
|
||||
}
|
||||
|
||||
|
||||
554
Utilities/DnsHelper.cs
Normal file
@@ -0,0 +1,554 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
// Provides DNS fallback functionality using Cloudflare DNS (1.1.1.1, 1.0.0.1) if system DNS fails to resolve critical hostnames
|
||||
// Also provides a proxy for rclone that handles DNS resolution
|
||||
public static class DnsHelper
|
||||
{
|
||||
private static readonly string[] FallbackDnsServers = { "1.1.1.1", "1.0.0.1" };
|
||||
private static readonly string[] CriticalHostnames =
|
||||
{
|
||||
"raw.githubusercontent.com",
|
||||
"downloads.rclone.org",
|
||||
"vrpirates.wiki",
|
||||
"github.com"
|
||||
};
|
||||
|
||||
private static readonly ConcurrentDictionary<string, IPAddress> _dnsCache =
|
||||
new ConcurrentDictionary<string, IPAddress>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
// Local proxy for rclone
|
||||
private static TcpListener _proxyListener;
|
||||
private static CancellationTokenSource _proxyCts;
|
||||
private static int _proxyPort;
|
||||
private static bool _initialized;
|
||||
private static bool _proxyRunning;
|
||||
|
||||
public static bool UseFallbackDns { get; private set; }
|
||||
|
||||
// Gets the proxy URL for rclone to use, or empty string if not needed
|
||||
public static string ProxyUrl => _proxyRunning ? $"http://127.0.0.1:{_proxyPort}" : string.Empty;
|
||||
|
||||
// Called after vrp-public.json is created/updated to test the hostname
|
||||
// Enable fallback DNS if the hostname fails on system DNS but works with fallback DNS
|
||||
public static void TestPublicConfigDns()
|
||||
{
|
||||
string hostname = GetPublicConfigHostname();
|
||||
if (string.IsNullOrEmpty(hostname))
|
||||
return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// If already using fallback, just pre-resolve the new hostname
|
||||
if (UseFallbackDns)
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Pre-resolved public config hostname {hostname} -> {ip}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if system DNS can resolve the public config hostname
|
||||
bool systemDnsWorks = TestHostnameWithSystemDns(hostname);
|
||||
|
||||
if (!systemDnsWorks)
|
||||
{
|
||||
Logger.Log($"System DNS failed for {hostname}. Testing fallback...", LogLevel.WARNING);
|
||||
|
||||
// Test if fallback DNS works for this hostname
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
UseFallbackDns = true;
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Enabled fallback DNS for {hostname} -> {ip}", LogLevel.INFO);
|
||||
ServicePointManager.DnsRefreshTimeout = 0;
|
||||
|
||||
// Pre-resolve base hostnames too
|
||||
PreResolveHostnames(CriticalHostnames);
|
||||
|
||||
// Start proxy if not already running
|
||||
if (!_proxyRunning)
|
||||
{
|
||||
StartProxy();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"Both system and fallback DNS failed for {hostname}", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"System DNS works for public config hostname: {hostname}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPublicConfigHostname()
|
||||
{
|
||||
try
|
||||
{
|
||||
string configPath = Path.Combine(Environment.CurrentDirectory, "vrp-public.json");
|
||||
if (!File.Exists(configPath))
|
||||
return null;
|
||||
|
||||
var config = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(configPath));
|
||||
if (config != null && config.TryGetValue("baseUri", out string baseUri))
|
||||
{
|
||||
return ExtractHostname(baseUri);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to get hostname from vrp-public.json: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string[] GetCriticalHostnames()
|
||||
{
|
||||
var hostnames = new List<string>(CriticalHostnames);
|
||||
|
||||
string host = GetPublicConfigHostname();
|
||||
if (!string.IsNullOrWhiteSpace(host) && !hostnames.Contains(host))
|
||||
{
|
||||
hostnames.Add(host);
|
||||
Logger.Log($"Added {host} from vrp-public.json to critical hostnames");
|
||||
}
|
||||
|
||||
return hostnames.ToArray();
|
||||
}
|
||||
|
||||
private static string ExtractHostname(string uriString)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(uriString)) return null;
|
||||
|
||||
if (!uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
|
||||
!uriString.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
uriString = "https://" + uriString;
|
||||
}
|
||||
|
||||
if (Uri.TryCreate(uriString, UriKind.Absolute, out Uri uri))
|
||||
return uri.Host;
|
||||
|
||||
// Fallback: manual extraction
|
||||
string hostname = uriString.Replace("https://", "").Replace("http://", "");
|
||||
int idx = hostname.IndexOfAny(new[] { '/', ':' });
|
||||
return idx > 0 ? hostname.Substring(0, idx) : hostname;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
Logger.Log("Testing DNS resolution for critical hostnames...");
|
||||
var hostnames = GetCriticalHostnames();
|
||||
|
||||
if (TestDns(hostnames, useSystem: true))
|
||||
{
|
||||
Logger.Log("System DNS is working correctly.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log("System DNS failed. Testing Cloudflare DNS fallback...", LogLevel.WARNING);
|
||||
if (TestDns(hostnames, useSystem: false))
|
||||
{
|
||||
UseFallbackDns = true;
|
||||
Logger.Log("Using Cloudflare DNS fallback.", LogLevel.INFO);
|
||||
PreResolveHostnames(hostnames);
|
||||
ServicePointManager.DnsRefreshTimeout = 0;
|
||||
StartProxy();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log("Both system and fallback DNS failed.", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cleanup() => StopProxy();
|
||||
|
||||
private static bool TestHostnameWithSystemDns(string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
return addresses?.Length > 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TestDns(string[] hostnames, bool useSystem)
|
||||
{
|
||||
if (useSystem)
|
||||
{
|
||||
return hostnames.All(h =>
|
||||
{
|
||||
try { return Dns.GetHostAddresses(h)?.Length > 0; }
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
return FallbackDnsServers.Any(server =>
|
||||
{
|
||||
try { return ResolveWithDns(hostnames[0], server)?.Count > 0; }
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
private static void PreResolveHostnames(string[] hostnames)
|
||||
{
|
||||
foreach (string hostname in hostnames)
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Pre-resolved {hostname} -> {ip}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IPAddress ResolveWithFallbackDns(string hostname)
|
||||
{
|
||||
foreach (string server in FallbackDnsServers)
|
||||
{
|
||||
try
|
||||
{
|
||||
var addresses = ResolveWithDns(hostname, server);
|
||||
if (addresses?.Count > 0) return addresses[0];
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<IPAddress> ResolveWithDns(string hostname, string dnsServer, int timeoutMs = 5000)
|
||||
{
|
||||
using (var udp = new UdpClient { Client = { ReceiveTimeout = timeoutMs, SendTimeout = timeoutMs } })
|
||||
{
|
||||
byte[] query = BuildDnsQuery(hostname);
|
||||
udp.Send(query, query.Length, new IPEndPoint(IPAddress.Parse(dnsServer), 53));
|
||||
IPEndPoint remoteEp = null;
|
||||
return ParseDnsResponse(udp.Receive(ref remoteEp));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] BuildDnsQuery(string hostname)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var writer = new BinaryWriter(ms))
|
||||
{
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)new Random().Next(0, ushort.MaxValue)));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0x0100)); // Flags
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Questions
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0)); // Answer RRs
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0)); // Authority RRs
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0)); // Additional RRs
|
||||
|
||||
foreach (string label in hostname.Split('.'))
|
||||
{
|
||||
writer.Write((byte)label.Length);
|
||||
writer.Write(Encoding.ASCII.GetBytes(label));
|
||||
}
|
||||
writer.Write((byte)0);
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Type A
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Class IN
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<IPAddress> ParseDnsResponse(byte[] response)
|
||||
{
|
||||
var addresses = new List<IPAddress>();
|
||||
if (response.Length < 12) return addresses;
|
||||
|
||||
int pos = 12;
|
||||
while (pos < response.Length && response[pos] != 0) pos += response[pos] + 1;
|
||||
pos += 5;
|
||||
|
||||
int answerCount = (response[6] << 8) | response[7];
|
||||
for (int i = 0; i < answerCount && pos + 12 <= response.Length; i++)
|
||||
{
|
||||
pos += (response[pos] & 0xC0) == 0xC0 ? 2 : SkipName(response, pos);
|
||||
if (pos + 10 > response.Length) break;
|
||||
|
||||
ushort type = (ushort)((response[pos] << 8) | response[pos + 1]);
|
||||
ushort rdLength = (ushort)((response[pos + 8] << 8) | response[pos + 9]);
|
||||
pos += 10;
|
||||
|
||||
if (pos + rdLength > response.Length) break;
|
||||
if (type == 1 && rdLength == 4)
|
||||
addresses.Add(new IPAddress(new[] { response[pos], response[pos + 1], response[pos + 2], response[pos + 3] }));
|
||||
pos += rdLength;
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
private static int SkipName(byte[] data, int pos)
|
||||
{
|
||||
int start = pos;
|
||||
while (pos < data.Length && data[pos] != 0) pos += data[pos] + 1;
|
||||
return pos - start + 1;
|
||||
}
|
||||
|
||||
public static IPAddress ResolveHostname(string hostname, bool alwaysTryFallback = false)
|
||||
{
|
||||
if (_dnsCache.TryGetValue(hostname, out IPAddress cached))
|
||||
return cached;
|
||||
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
if (addresses?.Length > 0)
|
||||
{
|
||||
_dnsCache[hostname] = addresses[0];
|
||||
return addresses[0];
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (alwaysTryFallback || UseFallbackDns || !_initialized)
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HttpWebRequest CreateWebRequest(string url)
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
|
||||
if (!UseFallbackDns)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dns.GetHostAddresses(uri.Host);
|
||||
return (HttpWebRequest)WebRequest.Create(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
if (UseFallbackDns)
|
||||
{
|
||||
var ip = ResolveHostname(uri.Host, alwaysTryFallback: true);
|
||||
if (ip != null)
|
||||
{
|
||||
var builder = new UriBuilder(uri) { Host = ip.ToString() };
|
||||
var request = (HttpWebRequest)WebRequest.Create(builder.Uri);
|
||||
request.Host = uri.Host;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
return (HttpWebRequest)WebRequest.Create(url);
|
||||
}
|
||||
|
||||
private static void StartProxy()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Find an available port
|
||||
_proxyListener = new TcpListener(IPAddress.Loopback, 0);
|
||||
_proxyListener.Start();
|
||||
_proxyPort = ((IPEndPoint)_proxyListener.LocalEndpoint).Port;
|
||||
_proxyCts = new CancellationTokenSource();
|
||||
_proxyRunning = true;
|
||||
|
||||
Logger.Log($"Started DNS proxy on port {_proxyPort}");
|
||||
|
||||
// Accept connections in background
|
||||
Task.Run(() => ProxyAcceptLoop(_proxyCts.Token));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to start DNS proxy: {ex.Message}", LogLevel.WARNING);
|
||||
_proxyRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void StopProxy()
|
||||
{
|
||||
_proxyRunning = false;
|
||||
_proxyCts?.Cancel();
|
||||
try { _proxyListener?.Stop(); } catch { }
|
||||
}
|
||||
|
||||
private static async Task ProxyAcceptLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested && _proxyRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = await _proxyListener.AcceptTcpClientAsync();
|
||||
_ = HandleProxyClient(client, ct);
|
||||
}
|
||||
catch (ObjectDisposedException) { break; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!ct.IsCancellationRequested)
|
||||
Logger.Log($"Proxy accept error: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task HandleProxyClient(TcpClient client, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (client)
|
||||
using (var stream = client.GetStream())
|
||||
{
|
||||
client.ReceiveTimeout = client.SendTimeout = 30000;
|
||||
|
||||
var buffer = new byte[8192];
|
||||
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, ct);
|
||||
if (bytesRead == 0) return;
|
||||
|
||||
string request = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
||||
string[] lines = request.Split(new[] { "\r\n" }, StringSplitOptions.None);
|
||||
if (lines.Length == 0) return;
|
||||
|
||||
string[] requestLine = lines[0].Split(' ');
|
||||
if (requestLine.Length < 2) return;
|
||||
|
||||
if (requestLine[0] == "CONNECT")
|
||||
// HTTPS proxy - tunnel mode
|
||||
await HandleConnectRequest(stream, requestLine[1], ct);
|
||||
else
|
||||
// HTTP proxy - forward mode
|
||||
await HandleHttpRequest(stream, request, requestLine[1], ct);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!ct.IsCancellationRequested)
|
||||
Logger.Log($"Proxy client error: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task HandleConnectRequest(NetworkStream clientStream, string target, CancellationToken ct)
|
||||
{
|
||||
// Parse host:port
|
||||
string[] parts = target.Split(':');
|
||||
string host = parts[0];
|
||||
int port = parts.Length > 1 && int.TryParse(parts[1], out int p) ? p : 443;
|
||||
|
||||
// Resolve hostname
|
||||
IPAddress ip = ResolveHostname(host, alwaysTryFallback: true);
|
||||
if (ip == null)
|
||||
{
|
||||
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Connect to target
|
||||
using (var targetClient = new TcpClient())
|
||||
{
|
||||
await targetClient.ConnectAsync(ip, port);
|
||||
using (var targetStream = targetClient.GetStream())
|
||||
{
|
||||
// Send 200 OK to client
|
||||
await SendResponse(clientStream, "HTTP/1.1 200 Connection Established\r\n\r\n", ct);
|
||||
// Tunnel data bidirectionally
|
||||
await Task.WhenAny(RelayData(clientStream, targetStream, ct), RelayData(targetStream, clientStream, ct));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"CONNECT tunnel error to {host}: {ex.Message}", LogLevel.WARNING);
|
||||
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task HandleHttpRequest(NetworkStream clientStream, string request, string url, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
IPAddress ip = ResolveHostname(uri.Host, alwaysTryFallback: true);
|
||||
if (ip == null)
|
||||
{
|
||||
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var targetClient = new TcpClient())
|
||||
{
|
||||
await targetClient.ConnectAsync(ip, uri.Port > 0 ? uri.Port : 80);
|
||||
using (var targetStream = targetClient.GetStream())
|
||||
{
|
||||
// Modify request to use relative path
|
||||
string modifiedRequest = request.Replace(url, uri.PathAndQuery);
|
||||
byte[] requestBytes = Encoding.ASCII.GetBytes(modifiedRequest);
|
||||
await targetStream.WriteAsync(requestBytes, 0, requestBytes.Length, ct);
|
||||
|
||||
// Relay response
|
||||
await RelayData(targetStream, clientStream, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"HTTP proxy error: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task SendResponse(NetworkStream stream, string response, CancellationToken ct)
|
||||
{
|
||||
byte[] bytes = Encoding.ASCII.GetBytes(response);
|
||||
try { await stream.WriteAsync(bytes, 0, bytes.Length, ct); } catch { }
|
||||
}
|
||||
|
||||
private static async Task RelayData(NetworkStream from, NetworkStream to, CancellationToken ct)
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
try
|
||||
{
|
||||
int bytesRead;
|
||||
while ((bytesRead = await from.ReadAsync(buffer, 0, buffer.Length, ct)) > 0)
|
||||
await to.WriteAsync(buffer, 0, bytesRead, ct);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Utilities/FileSystemUtilities.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
internal static class FileSystemUtilities
|
||||
{
|
||||
public static bool TryDeleteDirectory(string directoryPath, int maxRetries = 3, int delayMs = 150) // 3x 150ms = 450ms total
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(directoryPath))
|
||||
return true;
|
||||
|
||||
if (!Directory.Exists(directoryPath))
|
||||
return true;
|
||||
|
||||
Exception lastError = null;
|
||||
|
||||
// Retry deletion several times in case of lock ups
|
||||
for (int attempt = 0; attempt <= maxRetries; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
StripReadOnlyAttributes(directoryPath);
|
||||
Directory.Delete(directoryPath, true);
|
||||
return true;
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
|
||||
{
|
||||
lastError = ex;
|
||||
|
||||
if (attempt < maxRetries)
|
||||
{
|
||||
Thread.Sleep(delayMs);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Non-retryable error
|
||||
lastError = ex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort: rename then delete
|
||||
try
|
||||
{
|
||||
string renamedPath = directoryPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
|
||||
+ ".deleting." + DateTime.UtcNow.Ticks;
|
||||
|
||||
Directory.Move(directoryPath, renamedPath);
|
||||
|
||||
StripReadOnlyAttributes(renamedPath);
|
||||
Directory.Delete(renamedPath, true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lastError = ex;
|
||||
}
|
||||
|
||||
Logger.Log($"Failed to delete directory: {directoryPath}. Error: {lastError}", LogLevel.WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void StripReadOnlyAttributes(string directoryPath)
|
||||
{
|
||||
var root = new DirectoryInfo(directoryPath);
|
||||
if (!root.Exists) return;
|
||||
|
||||
root.Attributes &= ~FileAttributes.ReadOnly;
|
||||
|
||||
foreach (var dir in root.EnumerateDirectories("*", SearchOption.AllDirectories))
|
||||
{
|
||||
dir.Attributes &= ~FileAttributes.ReadOnly;
|
||||
}
|
||||
|
||||
foreach (var file in root.EnumerateFiles("*", SearchOption.AllDirectories))
|
||||
{
|
||||
file.Attributes &= ~FileAttributes.ReadOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,13 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System.Windows.Forms;
|
||||
using System.Net.Http;
|
||||
using System.IO;
|
||||
using AndroidSideloader;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
|
||||
class GeneralUtilities
|
||||
internal class GeneralUtilities
|
||||
{
|
||||
public static long GetDirectorySize(string folderPath)
|
||||
{
|
||||
@@ -28,13 +24,15 @@ namespace AndroidSideloader.Utilities
|
||||
|
||||
public static void ExecuteCommand(string command)
|
||||
{
|
||||
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
|
||||
processInfo.CreateNoWindow = true;
|
||||
processInfo.UseShellExecute = false;
|
||||
processInfo.RedirectStandardError = true;
|
||||
processInfo.RedirectStandardOutput = true;
|
||||
ProcessStartInfo processInfo = new ProcessStartInfo("cmd.exe", "/c " + command)
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true
|
||||
};
|
||||
|
||||
var process = Process.Start(processInfo);
|
||||
Process process = Process.Start(processInfo);
|
||||
|
||||
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
|
||||
CommandOutput += e.Data;
|
||||
@@ -51,7 +49,7 @@ namespace AndroidSideloader.Utilities
|
||||
|
||||
public static void Melt()
|
||||
{
|
||||
Process.Start(new ProcessStartInfo()
|
||||
_ = Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
Arguments = "/C choice /C Y /N /D Y /T 5 & Del \"" + Application.ExecutablePath + "\"",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
@@ -60,7 +58,8 @@ namespace AndroidSideloader.Utilities
|
||||
});
|
||||
Environment.Exit(0);
|
||||
}
|
||||
static Random rand = new Random();
|
||||
|
||||
private static readonly Random rand = new Random();
|
||||
public static string randomString(int length)
|
||||
{
|
||||
string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
@@ -69,7 +68,7 @@ namespace AndroidSideloader.Utilities
|
||||
int randomInteger = rand.Next(0, valid.Length);
|
||||
while (0 < length--)
|
||||
{
|
||||
res.Append(valid[randomInteger]);
|
||||
_ = res.Append(valid[randomInteger]);
|
||||
randomInteger = rand.Next(0, valid.Length);
|
||||
}
|
||||
return res.ToString();
|
||||
@@ -77,7 +76,7 @@ namespace AndroidSideloader.Utilities
|
||||
|
||||
public static ProcessOutput startProcess(string process, string path, string command)
|
||||
{
|
||||
Logger.Log($"Ran process {process} with command {command} in path {path}");
|
||||
_ = Logger.Log($"Ran process {process} with command {command} in path {path}");
|
||||
Process cmd = new Process();
|
||||
cmd.StartInfo.FileName = "cmd.exe";
|
||||
cmd.StartInfo.RedirectStandardInput = true;
|
||||
@@ -86,16 +85,16 @@ namespace AndroidSideloader.Utilities
|
||||
cmd.StartInfo.WorkingDirectory = path;
|
||||
cmd.StartInfo.CreateNoWindow = true;
|
||||
cmd.StartInfo.UseShellExecute = false;
|
||||
cmd.Start();
|
||||
_ = cmd.Start();
|
||||
cmd.StandardInput.WriteLine(command);
|
||||
cmd.StandardInput.Flush();
|
||||
cmd.StandardInput.Close();
|
||||
cmd.WaitForExit();
|
||||
string error = cmd.StandardError.ReadToEnd();
|
||||
string output = cmd.StandardOutput.ReadToEnd();
|
||||
Logger.Log($"Output: {output}");
|
||||
Logger.Log($"Error: {error}");
|
||||
return new ProcessOutput(output,error);
|
||||
_ = Logger.Log($"Output: {output}");
|
||||
_ = Logger.Log($"Error: {error}", LogLevel.ERROR);
|
||||
return new ProcessOutput(output, error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,110 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
class Logger
|
||||
{
|
||||
public string logfile = Properties.Settings.Default.CurrentLogPath;
|
||||
public static bool Log(string text, bool ret = true)
|
||||
{
|
||||
|
||||
string time = DateTime.Now.ToString("hh:mmtt(UTC): ");
|
||||
if (text.Length > 5)
|
||||
{
|
||||
|
||||
string newline = "\n";
|
||||
if (text.Length > 40 && text.Contains("\n"))
|
||||
newline += "\n\n";
|
||||
try {File.AppendAllText(Properties.Settings.Default.CurrentLogPath, time + text + newline); } catch { }
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
using AndroidSideloader.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace AndroidSideloader
|
||||
{
|
||||
public enum LogLevel
|
||||
{
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
TRACE,
|
||||
FATAL
|
||||
}
|
||||
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly SettingsManager settings = SettingsManager.Instance;
|
||||
private static readonly object lockObject = new object();
|
||||
private static string logFilePath = settings.CurrentLogPath;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set default log path if not already set
|
||||
if (string.IsNullOrEmpty(logFilePath))
|
||||
{
|
||||
logFilePath = Path.Combine(Environment.CurrentDirectory, "debuglog.txt");
|
||||
}
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
string logDirectory = Path.GetDirectoryName(logFilePath);
|
||||
if (!string.IsNullOrEmpty(logDirectory) && !Directory.Exists(logDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(logDirectory);
|
||||
}
|
||||
|
||||
// Create log file if it doesn't exist
|
||||
if (!File.Exists(logFilePath))
|
||||
{
|
||||
using (FileStream fs = File.Create(logFilePath))
|
||||
{
|
||||
// Create empty file
|
||||
}
|
||||
}
|
||||
|
||||
// Update settings with log path
|
||||
settings.CurrentLogPath = logFilePath;
|
||||
settings.Save();
|
||||
|
||||
// Initial log entry, make it stand out
|
||||
string time = DateTime.UtcNow.ToString("hh:mm:ss.fff tt (UTC): ");
|
||||
Log($"\n\n{time}------------ Logger initialized ------------", LogLevel.INFO);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error initializing logger: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Log(string text, LogLevel logLevel = LogLevel.INFO, bool ret = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text) || text.Length <= 5)
|
||||
return ret;
|
||||
|
||||
// Initialize logger if not already initialized
|
||||
if (string.IsNullOrEmpty(logFilePath))
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
string time = DateTime.UtcNow.ToString("hh:mm:ss.fff tt (UTC): ");
|
||||
string newline = text.Length > 40 && text.Contains("\n") ? "\n\n" : "\n";
|
||||
string logEntry = time + "[" + logLevel.ToString().ToUpper() + "] [" + GetCallerInfo() + "] " + text + newline;
|
||||
|
||||
try
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
File.AppendAllText(logFilePath, logEntry);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error writing to log: {ex.Message}");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static string GetCallerInfo()
|
||||
{
|
||||
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(true);
|
||||
if (stackTrace.FrameCount >= 3)
|
||||
{
|
||||
var frame = stackTrace.GetFrame(2);
|
||||
var method = frame.GetMethod();
|
||||
string className = method.DeclaringType?.Name;
|
||||
string methodName = method.Name;
|
||||
string callerInfo = $"{className}.{methodName}";
|
||||
return callerInfo;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
81
Utilities/Metrics.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
internal class Metrics
|
||||
{
|
||||
public static async void CountDownload(string packageName, string versionCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var apiUrl = "https://api.vrpirates.wiki/metrics/add";
|
||||
|
||||
var requestBody = new
|
||||
{
|
||||
packagename = packageName,
|
||||
versioncode = versionCode
|
||||
};
|
||||
var json = JsonConvert.SerializeObject(requestBody);
|
||||
string res = await Task.Run(() => sendToApi(apiUrl, json, "post"));
|
||||
_ = Logger.Log(res);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Unable to log download: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static async Task<string> sendToApi(string apiUrl, string requestBody = null, string type = "get")
|
||||
{
|
||||
string token = "cm9va2llOkN0UHlyTE9oUGoxWXg1cE9KdDNBSkswZ25n";
|
||||
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var request = new HttpRequestMessage();
|
||||
|
||||
// Set the HTTP method
|
||||
request.Method = type.ToLower() == "post" ? HttpMethod.Post : HttpMethod.Get;
|
||||
|
||||
// For GET requests with parameters, append them to the URL
|
||||
if (request.Method == HttpMethod.Get && !string.IsNullOrEmpty(requestBody))
|
||||
{
|
||||
var uriBuilder = new UriBuilder(apiUrl);
|
||||
uriBuilder.Query = requestBody;
|
||||
request.RequestUri = uriBuilder.Uri;
|
||||
}
|
||||
else
|
||||
{
|
||||
request.RequestUri = new Uri(apiUrl);
|
||||
}
|
||||
|
||||
// For POST requests, set the content
|
||||
if (request.Method == HttpMethod.Post && !string.IsNullOrEmpty(requestBody))
|
||||
{
|
||||
request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
// Add headers to the request
|
||||
request.Headers.Add("Authorization", token);
|
||||
request.Headers.Add("Origin", "rookie");
|
||||
|
||||
string responseContent = "";
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await client.SendAsync(request);
|
||||
responseContent = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Unable to get Metrics Data: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
|
||||
return responseContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
332
Utilities/SettingsManager.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
public class SettingsManager : IDisposable
|
||||
{
|
||||
private static readonly Lazy<SettingsManager> _instance = new Lazy<SettingsManager>(() => new SettingsManager());
|
||||
private static readonly string settingsFilePath = Path.Combine(
|
||||
Environment.CurrentDirectory,
|
||||
"settings.json");
|
||||
|
||||
// Custom converters for special types
|
||||
public class FontConverter : JsonConverter<Font>
|
||||
{
|
||||
public override Font ReadJson(JsonReader reader, Type objectType, Font existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jo = JObject.Load(reader);
|
||||
string fontFamily = jo["FontFamily"]?.Value<string>() ?? "Microsoft Sans Serif";
|
||||
float fontSize = jo["Size"]?.Value<float>() ?? 11.25f;
|
||||
return new Font(fontFamily, fontSize);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, Font value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("FontFamily");
|
||||
writer.WriteValue(value.FontFamily.Name);
|
||||
writer.WritePropertyName("Size");
|
||||
writer.WriteValue(value.Size);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorConverter : JsonConverter<Color>
|
||||
{
|
||||
public override Color ReadJson(JsonReader reader, Type objectType, Color existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jo = JObject.Load(reader);
|
||||
int a = jo["A"]?.Value<int>() ?? 255;
|
||||
int r = jo["R"]?.Value<int>() ?? 0;
|
||||
int g = jo["G"]?.Value<int>() ?? 0;
|
||||
int b = jo["B"]?.Value<int>() ?? 0;
|
||||
return Color.FromArgb(a, r, g, b);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("A");
|
||||
writer.WriteValue(value.A);
|
||||
writer.WritePropertyName("R");
|
||||
writer.WriteValue(value.R);
|
||||
writer.WritePropertyName("G");
|
||||
writer.WriteValue(value.G);
|
||||
writer.WritePropertyName("B");
|
||||
writer.WriteValue(value.B);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(FontConverter))]
|
||||
public Font FontStyle { get; set; } = new Font("Microsoft Sans Serif", 11.25f);
|
||||
[JsonConverter(typeof(FontConverter))]
|
||||
public Font BigFontStyle { get; set; } = new Font("Microsoft Sans Serif", 14f);
|
||||
[JsonConverter(typeof(ColorConverter))]
|
||||
public Color FontColor { get; set; } = Color.White;
|
||||
[JsonConverter(typeof(ColorConverter))]
|
||||
public Color ComboBoxColor { get; set; } = Color.FromArgb(25, 25, 25);
|
||||
[JsonConverter(typeof(ColorConverter))]
|
||||
public Color SubButtonColor { get; set; } = Color.FromArgb(25, 25, 25);
|
||||
[JsonConverter(typeof(ColorConverter))]
|
||||
public Color TextBoxColor { get; set; } = Color.FromArgb(25, 25, 25);
|
||||
[JsonConverter(typeof(ColorConverter))]
|
||||
public Color ButtonColor { get; set; } = Color.Black;
|
||||
[JsonConverter(typeof(ColorConverter))]
|
||||
public Color BackColor { get; set; } = Color.FromArgb(1, 1, 1);
|
||||
public bool CheckForUpdates { get; set; } = true;
|
||||
public bool EnableMessageBoxes { get; set; } = true;
|
||||
public bool FirstRun { get; set; } = true;
|
||||
public bool DeleteAllAfterInstall { get; set; } = true;
|
||||
public bool AutoUpdateConfig { get; set; } = true;
|
||||
public bool UserJsonOnGameInstall { get; set; } = false;
|
||||
public bool CallUpgrade { get; set; } = true;
|
||||
public string BackPicturePath { get; set; } = string.Empty;
|
||||
public bool SpoofGames { get; set; } = false;
|
||||
public bool ResignAPKs { get; set; } = false;
|
||||
public string IPAddress { get; set; } = string.Empty;
|
||||
public string InstalledApps { get; set; } = string.Empty;
|
||||
public string ADBPath { get; set; } = string.Empty;
|
||||
public string MainDir { get; set; } = string.Empty;
|
||||
public bool Delsh { get; set; } = false;
|
||||
public string CurrPckg { get; set; } = string.Empty;
|
||||
public string ADBFolder { get; set; } = string.Empty;
|
||||
public bool WirelessADB { get; set; } = false;
|
||||
public string CurrentGamename { get; set; } = string.Empty;
|
||||
public bool PackageNameToCB { get; set; } = false;
|
||||
public bool DownUpHeld { get; set; } = false;
|
||||
public string CurrentLogPath { get; set; } = string.Empty;
|
||||
public string CurrentLogName { get; set; } = string.Empty;
|
||||
public string CurrentCrashPath { get; set; } = string.Empty;
|
||||
public string CurrentCrashName { get; set; } = string.Empty;
|
||||
public bool AdbDebugWarned { get; set; } = false;
|
||||
public bool NodeviceMode { get; set; } = false;
|
||||
public bool BMBFChecked { get; set; } = true;
|
||||
public string GamesList { get; set; } = string.Empty;
|
||||
public bool UploadedGameList { get; set; } = false;
|
||||
public string GlobalUsername { get; set; } = string.Empty;
|
||||
public DateTime LastTimeShared { get; set; } = new DateTime(1969, 4, 20, 16, 20, 0);
|
||||
public bool AutoReinstall { get; set; } = false;
|
||||
public string NonAppPackages { get; set; } = string.Empty;
|
||||
public DateTime LastLaunch { get; set; } = new DateTime(1969, 4, 20, 16, 20, 0);
|
||||
public string SubmittedUpdates { get; set; } = string.Empty;
|
||||
public bool ListUpped { get; set; } = false;
|
||||
public DateTime LastLaunch2 { get; set; } = new DateTime(1969, 4, 20, 16, 20, 0);
|
||||
public bool Wired { get; set; } = false;
|
||||
public string AppPackages { get; set; } = string.Empty;
|
||||
public string DownloadDir { get; set; } = string.Empty;
|
||||
public bool CustomDownloadDir { get; set; } = false;
|
||||
public bool CustomBackupDir { get; set; } = false;
|
||||
public string BackupDir { get; set; } = string.Empty;
|
||||
public bool SingleThreadMode { get; set; } = true;
|
||||
public bool VirtualFilesystemCompatibility { get; set; } = false;
|
||||
public bool UpdateSettings { get; set; } = true;
|
||||
public string UUID { get; set; } = Guid.NewGuid().ToString();
|
||||
public bool CreatePubMirrorFile { get; set; } = true;
|
||||
public bool UseDownloadedFiles { get; set; } = false;
|
||||
public float BandwidthLimit { get; set; } = 0f;
|
||||
public string[] FavoritedGames { get; set; } = new string[0];
|
||||
public bool useProxy { get; set; } = false;
|
||||
public string ProxyAddress { get; set; } = string.Empty;
|
||||
public string ProxyPort { get; set; } = string.Empty;
|
||||
public string selectedMirror { get; set; } = string.Empty;
|
||||
public bool TrailersEnabled { get; set; } = true;
|
||||
public bool UseGalleryView { get; set; } = true;
|
||||
|
||||
// Window state persistence
|
||||
public int WindowX { get; set; } = -1;
|
||||
public int WindowY { get; set; } = -1;
|
||||
public int WindowWidth { get; set; } = -1;
|
||||
public int WindowHeight { get; set; } = -1;
|
||||
public bool WindowMaximized { get; set; } = false;
|
||||
|
||||
// Sort state persistence
|
||||
public int SortColumn { get; set; } = 0;
|
||||
public bool SortAscending { get; set; } = true;
|
||||
|
||||
// Download queue persistence
|
||||
public string[] QueuedGames { get; set; } = new string[0];
|
||||
|
||||
private SettingsManager()
|
||||
{
|
||||
Load();
|
||||
Save();
|
||||
}
|
||||
|
||||
public static SettingsManager Instance => _instance.Value;
|
||||
|
||||
public void Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(this, settings);
|
||||
File.WriteAllText(settingsFilePath, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error saving settings: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
Debug.WriteLine("Loading settings...");
|
||||
if (!File.Exists(settingsFilePath))
|
||||
{
|
||||
CreateDefaultSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(settingsFilePath);
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Error = (sender, args) =>
|
||||
{
|
||||
Debug.WriteLine($"Error deserializing setting: {args.ErrorContext.Error.Message}");
|
||||
args.ErrorContext.Handled = true;
|
||||
}
|
||||
};
|
||||
|
||||
JsonConvert.PopulateObject(json, this, settings);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error loading settings: {ex.Message}");
|
||||
CreateDefaultSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateDefaultSettings()
|
||||
{
|
||||
FontStyle = new Font("Microsoft Sans Serif", 11.25f);
|
||||
BigFontStyle = new Font("Microsoft Sans Serif", 14f);
|
||||
FontColor = Color.White;
|
||||
ComboBoxColor = Color.FromArgb(25, 25, 25);
|
||||
SubButtonColor = Color.FromArgb(25, 25, 25);
|
||||
TextBoxColor = Color.FromArgb(25, 25, 25);
|
||||
ButtonColor = Color.Black;
|
||||
BackColor = Color.FromArgb(1, 1, 1);
|
||||
CheckForUpdates = true;
|
||||
EnableMessageBoxes = true;
|
||||
FirstRun = true;
|
||||
DeleteAllAfterInstall = true;
|
||||
AutoUpdateConfig = true;
|
||||
UserJsonOnGameInstall = false;
|
||||
CallUpgrade = true;
|
||||
BackPicturePath = string.Empty;
|
||||
SpoofGames = false;
|
||||
ResignAPKs = false;
|
||||
IPAddress = string.Empty;
|
||||
InstalledApps = string.Empty;
|
||||
ADBPath = string.Empty;
|
||||
MainDir = string.Empty;
|
||||
Delsh = false;
|
||||
CurrPckg = string.Empty;
|
||||
ADBFolder = string.Empty;
|
||||
WirelessADB = false;
|
||||
CurrentGamename = string.Empty;
|
||||
PackageNameToCB = false;
|
||||
DownUpHeld = false;
|
||||
CurrentLogPath = string.Empty;
|
||||
CurrentLogName = string.Empty;
|
||||
CurrentCrashPath = string.Empty;
|
||||
CurrentCrashName = string.Empty;
|
||||
AdbDebugWarned = false;
|
||||
NodeviceMode = false;
|
||||
BMBFChecked = true;
|
||||
GamesList = string.Empty;
|
||||
UploadedGameList = false;
|
||||
GlobalUsername = string.Empty;
|
||||
LastTimeShared = new DateTime(1969, 4, 20, 16, 20, 0);
|
||||
AutoReinstall = false;
|
||||
NonAppPackages = string.Empty;
|
||||
LastLaunch = new DateTime(1969, 4, 20, 16, 20, 0);
|
||||
SubmittedUpdates = string.Empty;
|
||||
ListUpped = false;
|
||||
LastLaunch2 = new DateTime(1969, 4, 20, 16, 20, 0);
|
||||
Wired = false;
|
||||
AppPackages = string.Empty;
|
||||
DownloadDir = string.Empty;
|
||||
CustomDownloadDir = false;
|
||||
CustomBackupDir = false;
|
||||
BackupDir = string.Empty;
|
||||
SingleThreadMode = true;
|
||||
VirtualFilesystemCompatibility = false;
|
||||
UpdateSettings = true;
|
||||
UUID = Guid.NewGuid().ToString();
|
||||
CreatePubMirrorFile = true;
|
||||
UseDownloadedFiles = false;
|
||||
BandwidthLimit = 0f;
|
||||
FavoritedGames = new string[0];
|
||||
useProxy = false;
|
||||
ProxyAddress = string.Empty;
|
||||
ProxyPort = string.Empty;
|
||||
selectedMirror = string.Empty;
|
||||
TrailersEnabled = true;
|
||||
UseGalleryView = true;
|
||||
WindowX = -1;
|
||||
WindowY = -1;
|
||||
WindowWidth = -1;
|
||||
WindowHeight = -1;
|
||||
WindowMaximized = false;
|
||||
SortColumn = 0;
|
||||
SortAscending = true;
|
||||
QueuedGames = new string[0];
|
||||
|
||||
Save();
|
||||
Debug.WriteLine("Default settings created.");
|
||||
}
|
||||
|
||||
public void AddFavoriteGame(string packageName)
|
||||
{
|
||||
if (!FavoritedGames.Contains(packageName))
|
||||
{
|
||||
var list = FavoritedGames.ToList();
|
||||
list.Add(packageName);
|
||||
FavoritedGames = list.ToArray();
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveFavoriteGame(string packageName)
|
||||
{
|
||||
if (FavoritedGames.Contains(packageName))
|
||||
{
|
||||
var list = FavoritedGames.ToList();
|
||||
list.Remove(packageName);
|
||||
FavoritedGames = list.ToArray();
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetEffectiveBackupDir()
|
||||
{
|
||||
if (CustomBackupDir && Directory.Exists(BackupDir))
|
||||
{
|
||||
return BackupDir;
|
||||
}
|
||||
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Rookie Backups");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
FontStyle?.Dispose();
|
||||
BigFontStyle?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
class StringUtilities
|
||||
internal class StringUtilities
|
||||
{
|
||||
public static string RemoveEverythingAfterFirst(string s, string removeMe)
|
||||
{
|
||||
int index = s.IndexOf(removeMe);
|
||||
if (index > 0)
|
||||
{
|
||||
s = s.Substring(0, index);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -20,7 +19,10 @@ namespace AndroidSideloader.Utilities
|
||||
{
|
||||
int index = s.LastIndexOf(removeMe);
|
||||
if (index > 0)
|
||||
{
|
||||
s = s.Substring(0, index);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -28,7 +30,10 @@ namespace AndroidSideloader.Utilities
|
||||
{
|
||||
int index = s.IndexOf(removeMe);
|
||||
if (index > 0)
|
||||
{
|
||||
s = s.Substring(index);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -50,8 +55,19 @@ namespace AndroidSideloader.Utilities
|
||||
{
|
||||
int index = s.LastIndexOf(removeMe);
|
||||
if (index > 0)
|
||||
{
|
||||
s = s.Substring(index);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static bool TryParseDouble(string value, out double result)
|
||||
{
|
||||
return double.TryParse(value,
|
||||
System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
out result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
class UpdateGameData
|
||||
internal class UpdateGameData
|
||||
{
|
||||
public UpdateGameData(String gameName, String packageName, ulong installedVersionInt)
|
||||
public UpdateGameData(string gameName, string packageName, ulong installedVersionInt)
|
||||
{
|
||||
this.GameName = gameName;
|
||||
this.Packagename = packageName;
|
||||
this.InstalledVersionInt = installedVersionInt;
|
||||
GameName = gameName;
|
||||
Packagename = packageName;
|
||||
InstalledVersionInt = installedVersionInt;
|
||||
}
|
||||
public string GameName { get; set; }
|
||||
public string Packagename { get; set; }
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
class UploadGame
|
||||
internal class UploadGame
|
||||
{
|
||||
public UploadGame(string Uploadcommand, string Pckgcommand, string Uploadgamename, ulong Uploadversion, bool isUpdate)
|
||||
{
|
||||
this.Uploadcommand = Uploadcommand;
|
||||
this.Pckgcommand = Pckgcommand;
|
||||
this.Uploadgamename = Uploadgamename;
|
||||
this.Uploadversion = Uploadversion;
|
||||
@@ -18,14 +11,12 @@ namespace AndroidSideloader.Utilities
|
||||
}
|
||||
public UploadGame()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public bool isUpdate { get; set; }
|
||||
|
||||
public string Uploadcommand { get; set; }
|
||||
|
||||
public string Pckgcommand { get; set; }
|
||||
|
||||
|
||||
public string Uploadgamename { get; set; }
|
||||
|
||||
public ulong Uploadversion { get; set; }
|
||||
|
||||
223
Utilities/Zip.cs
@@ -1,53 +1,220 @@
|
||||
using System;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
class Zip
|
||||
public class ExtractionException : Exception
|
||||
{
|
||||
public ExtractionException(string message) : base(message) { }
|
||||
}
|
||||
|
||||
internal class Zip
|
||||
{
|
||||
private static readonly SettingsManager settings = SettingsManager.Instance;
|
||||
|
||||
// Progress callback: (percent, eta)
|
||||
public static Action<float, TimeSpan?> ExtractionProgressCallback { get; set; }
|
||||
public static Action<string> ExtractionStatusCallback { get; set; }
|
||||
|
||||
public static void ExtractFile(string sourceArchive, string destination)
|
||||
{
|
||||
var args = $"x \"{sourceArchive}\" -y -o\"{destination}\"";
|
||||
string args = $"x \"{sourceArchive}\" -y -o\"{destination}\" -bsp1";
|
||||
DoExtract(args);
|
||||
}
|
||||
|
||||
public static void ExtractFile(string sourceArchive, string destination, string password)
|
||||
{
|
||||
var args = $"x \"{sourceArchive}\" -y -o\"{destination}\" -p\"{password}\"";
|
||||
string args = $"x \"{sourceArchive}\" -y -o\"{destination}\" -p\"{password}\" -bsp1";
|
||||
DoExtract(args);
|
||||
}
|
||||
|
||||
private static string extractionError = null;
|
||||
private static bool errorMessageShown = false;
|
||||
|
||||
private static void DoExtract(string args)
|
||||
{
|
||||
if (!File.Exists(Environment.CurrentDirectory + "\\7z.exe") || !File.Exists(Environment.CurrentDirectory + "\\7z.dll"))
|
||||
if (!File.Exists(Path.Combine(Environment.CurrentDirectory, "7z.exe")) || !File.Exists(Path.Combine(Environment.CurrentDirectory, "7z.dll")))
|
||||
{
|
||||
Logger.Log("Begin download 7-zip");
|
||||
WebClient client = new WebClient();
|
||||
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/7z.exe", "7z.exe");
|
||||
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/7z.dll", "7z.dll");
|
||||
Logger.Log("Complete download 7-zip");
|
||||
_ = Logger.Log("Begin download 7-zip");
|
||||
string architecture = Environment.Is64BitOperatingSystem ? "64" : "";
|
||||
try
|
||||
{
|
||||
// Use DNS fallback download method from GetDependencies
|
||||
GetDependencies.DownloadFileWithDnsFallback($"https://github.com/VRPirates/rookie/raw/master/7z{architecture}.exe", "7z.exe");
|
||||
GetDependencies.DownloadFileWithDnsFallback($"https://github.com/VRPirates/rookie/raw/master/7z{architecture}.dll", "7z.dll");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = FlexibleMessageBox.Show(Program.form, $"You are unable to access the GitHub page with the Exception: {ex.Message}\nSome files may be missing (7z)");
|
||||
_ = FlexibleMessageBox.Show(Program.form, "7z was unable to be downloaded\nRookie will now close");
|
||||
Application.Exit();
|
||||
}
|
||||
_ = Logger.Log("Complete download 7-zip");
|
||||
}
|
||||
ProcessStartInfo pro = new ProcessStartInfo();
|
||||
pro.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
pro.FileName = "7z.exe";
|
||||
pro.Arguments = args;
|
||||
pro.CreateNoWindow = true;
|
||||
pro.UseShellExecute = false;
|
||||
|
||||
Logger.Log($"Extract: 7z {args}");
|
||||
|
||||
Process x = Process.Start(pro);
|
||||
x.WaitForExit();
|
||||
if (x.ExitCode != 0)
|
||||
ProcessStartInfo pro = new ProcessStartInfo
|
||||
{
|
||||
Logger.Log($"Extract failed");
|
||||
Logger.Log(x.StandardOutput.ReadToEnd());
|
||||
throw new ApplicationException($"Extracting failed, status code {x.ExitCode}");
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
FileName = "7z.exe",
|
||||
Arguments = args,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true
|
||||
};
|
||||
|
||||
_ = Logger.Log($"Extract: 7z {string.Join(" ", args.Split(' ').Where(a => !a.StartsWith("-p")))}");
|
||||
|
||||
// Throttle percent reports
|
||||
float lastReportedPercent = -1;
|
||||
|
||||
// ETA engine (percent units)
|
||||
var etaEstimator = new EtaEstimator(alpha: 0.10, reanchorThreshold: 0.20, minSampleSeconds: 0.10);
|
||||
|
||||
// Smooth progress (sub-percent) interpolation (because 7z -bsp1 is integer-only)
|
||||
System.Threading.Timer smoothTimer = null;
|
||||
int extractingFlag = 1; // 1 = extracting, 0 = stop
|
||||
float smoothLastTickPercent = 0f;
|
||||
DateTime smoothLastTickTime = DateTime.UtcNow;
|
||||
float smoothLastReported = -1f;
|
||||
const int SmoothIntervalMs = 80; // ~12.5 updates/sec
|
||||
const float SmoothReportDelta = 0.10f; // report only if change >= 0.10%
|
||||
|
||||
using (Process x = new Process())
|
||||
{
|
||||
x.StartInfo = pro;
|
||||
|
||||
if (MainForm.isInDownloadExtract && x != null)
|
||||
{
|
||||
// Smooth sub-percent UI, while keeping ETA ticking
|
||||
smoothTimer = new System.Threading.Timer(_ =>
|
||||
{
|
||||
if (System.Threading.Volatile.Read(ref extractingFlag) == 0) return;
|
||||
if (smoothLastTickPercent <= 0) return; // need at least one 7z tick
|
||||
|
||||
// Use current ETA to approximate seconds-per-percent
|
||||
TimeSpan? displayEta = etaEstimator.GetDisplayEta();
|
||||
if (!displayEta.HasValue) return; // Skip until ETA exists
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var elapsed = (now - smoothLastTickTime).TotalSeconds;
|
||||
|
||||
// Approx seconds-per-percent from remaining ETA / remaining percent
|
||||
double remainingPercent = Math.Max(1.0, 100.0 - smoothLastTickPercent);
|
||||
double spp = Math.Max(0.05, displayEta.Value.TotalSeconds / remainingPercent);
|
||||
|
||||
float candidate = smoothLastTickPercent + (float)(elapsed / spp);
|
||||
|
||||
// Clamp
|
||||
float floorTick = (float)Math.Floor(smoothLastTickPercent);
|
||||
float ceiling = Math.Min(99.99f, floorTick + 0.999f);
|
||||
|
||||
if (candidate > ceiling) candidate = ceiling;
|
||||
if (candidate < smoothLastTickPercent) candidate = smoothLastTickPercent;
|
||||
|
||||
if (smoothLastReported >= 0 && Math.Abs(candidate - smoothLastReported) < SmoothReportDelta) return;
|
||||
smoothLastReported = candidate;
|
||||
|
||||
try
|
||||
{
|
||||
MainForm mainForm = (MainForm)Application.OpenForms[0];
|
||||
if (mainForm != null && !mainForm.IsDisposed)
|
||||
{
|
||||
mainForm.BeginInvoke((Action)(() => mainForm.SetProgress(candidate)));
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// ETA countdown ticks even if 7z percent is unchanged
|
||||
ExtractionProgressCallback?.Invoke(candidate, etaEstimator.GetDisplayEta());
|
||||
|
||||
}, null, SmoothIntervalMs, SmoothIntervalMs);
|
||||
|
||||
x.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
var match = Regex.Match(e.Data, @"^\s*(\d+)%");
|
||||
if (match.Success && float.TryParse(match.Groups[1].Value, out float percent))
|
||||
{
|
||||
// Update ETA from integer percent
|
||||
if (percent <= 0.0f) etaEstimator.Reset();
|
||||
else if (percent < 100.0f) etaEstimator.Update(totalUnits: 100, doneUnits: (long)Math.Round(percent));
|
||||
|
||||
// Reset smoothing baseline on each integer tick
|
||||
smoothLastTickPercent = percent;
|
||||
smoothLastTickTime = DateTime.UtcNow;
|
||||
smoothLastReported = percent;
|
||||
|
||||
if (Math.Abs(percent - lastReportedPercent) >= 0.1f)
|
||||
{
|
||||
lastReportedPercent = percent;
|
||||
|
||||
MainForm mainForm = (MainForm)Application.OpenForms[0];
|
||||
if (mainForm != null)
|
||||
{
|
||||
mainForm.Invoke((Action)(() => mainForm.SetProgress(percent)));
|
||||
}
|
||||
|
||||
ExtractionProgressCallback?.Invoke(percent, etaEstimator.GetDisplayEta());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
x.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
var error = e.Data;
|
||||
if (error.Contains("There is not enough space on the disk") && !errorMessageShown)
|
||||
{
|
||||
errorMessageShown = true;
|
||||
Program.form.Invoke(new Action(() =>
|
||||
{
|
||||
_ = FlexibleMessageBox.Show(Program.form, $"Not enough space to extract archive.\r\nMake sure your {Path.GetPathRoot(settings.DownloadDir)} drive has at least double the space of the game, then try again.",
|
||||
"NOT ENOUGH SPACE",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
return;
|
||||
}));
|
||||
}
|
||||
_ = Logger.Log(error, LogLevel.ERROR);
|
||||
extractionError = $"Extracting failed: {error}"; // Store the error message directly
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
x.Start();
|
||||
x.BeginOutputReadLine();
|
||||
x.BeginErrorReadLine();
|
||||
x.WaitForExit();
|
||||
|
||||
// Stop smoother
|
||||
System.Threading.Interlocked.Exchange(ref extractingFlag, 0);
|
||||
smoothTimer?.Dispose();
|
||||
smoothTimer = null;
|
||||
|
||||
// Clear callbacks
|
||||
ExtractionProgressCallback?.Invoke(100, null);
|
||||
ExtractionStatusCallback?.Invoke("");
|
||||
|
||||
errorMessageShown = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(extractionError))
|
||||
{
|
||||
string errorMessage = extractionError;
|
||||
extractionError = null; // Reset the error message
|
||||
throw new ExtractionException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
22
build.cmd
Normal file
@@ -0,0 +1,22 @@
|
||||
@echo off
|
||||
REM Default to Release if no argument is provided
|
||||
SET CONFIG=Release
|
||||
IF NOT "%1"=="" (
|
||||
IF /I "%1"=="debug" SET CONFIG=Debug
|
||||
)
|
||||
|
||||
REM Windows Batch script version
|
||||
REM Attempts to find MSBuild from common Visual Studio 2022 installation paths
|
||||
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" (
|
||||
SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe"
|
||||
) ELSE IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe" (
|
||||
SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe"
|
||||
) ELSE IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" (
|
||||
SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
|
||||
) ELSE (
|
||||
echo MSBuild not found! Please check your Visual Studio installation.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Building in %CONFIG% configuration...
|
||||
%MSBUILD% AndroidSideloader.sln /t:AndroidSideloader /p:Configuration=%CONFIG%
|
||||
@@ -1,12 +1,12 @@
|
||||
RSL 2.15
|
||||
RSL 3.0.1
|
||||
|
||||
- Massive UI Changes:
|
||||
- Rounded buttons
|
||||
- Added version Number at Bottom Left
|
||||
- Changed fonts to some extend
|
||||
- Added background pattern to category buttons and MainForm background
|
||||
- Added an animation when opening/closing category
|
||||
- Overall darker theme
|
||||
- New splash
|
||||
|
||||
~Chax
|
||||
- Fixed popularity ranking not working on some systems
|
||||
- Fixed favorites not updating immediately when removing items
|
||||
- Improved YouTube trailer matching accuracy
|
||||
- Implemented real-time progress updates for drag and drop operations
|
||||
- Refined backup button labels and dialogs
|
||||
- Gallery View: Added grouped tiles for games with multiple versions (e.g. Beat Saber)
|
||||
- ListView: Uninstall button now shows on hover instead of click
|
||||
- Public config file is now created automatically without prompt
|
||||
- Sideloading status label now shows device connection state
|
||||
- Download button text now reflects sideloading status
|
||||
34708
debuglog.txt
BIN
dep/rclone-v1.67.0-windows-386.zip
Normal file
BIN
dep/rclone-v1.67.0-windows-amd64.zip
Normal file
BIN
dependencies.7z
Normal file
12
donators.txt
@@ -1,12 +0,0 @@
|
||||
CC0E0834BFEBFBFF000906E9;5000;ROOKIE.WTF
|
||||
184204E0178BFBFF00870F10;0;Flow
|
||||
E5148390BFEBFBFF000906EA;250;Gotard
|
||||
5ECC5497178BFBFF00870F10;1024;Saidis21
|
||||
B0374BE2BFEBFBFF00040651;0;ecirbaf
|
||||
926C60A8178BFBFF00800F82;250;ThePhantomPickaxe
|
||||
2A8C5999BFEBFBFF0001067A;0;karl
|
||||
80ACB80FBFEBFBFF000206C2;4096;JJ-4
|
||||
9AA172C9BFEBFBFF000906ED;1024;Clayton Bigsby
|
||||
645C9EADBFEBFBFF000906EA;5000;Heracide
|
||||
1C51D0CD178BFBFF00870F10;0;Mr.Tibby
|
||||
287B5C6CBFEBFBFF000906EA;0;videobeer
|
||||
BIN
icon.ico
|
Before Width: | Height: | Size: 401 KiB After Width: | Height: | Size: 31 KiB |
@@ -1,6 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="4.1.0" targetFramework="net452" />
|
||||
<package id="Fody" version="6.0.0" targetFramework="net452" developmentDependency="true" />
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net452" />
|
||||
<package id="AdvancedSharpAdbClient" version="3.5.15" targetFramework="net452" />
|
||||
<package id="Costura.Fody" version="5.7.0" targetFramework="net452" developmentDependency="true" />
|
||||
<package id="Fody" version="6.8.1" targetFramework="net452" developmentDependency="true" />
|
||||
<package id="Microsoft.NETCore.Platforms" version="7.0.4" targetFramework="net452" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.2478.35" targetFramework="net452" />
|
||||
<package id="NETStandard.Library" version="2.0.3" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
|
||||
<package id="System.Collections" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Globalization" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.IO" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Linq" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Net.Http" version="4.3.4" targetFramework="net452" />
|
||||
<package id="System.Net.Primitives" version="4.3.1" targetFramework="net452" />
|
||||
<package id="System.ObjectModel" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Reflection" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Runtime" version="4.3.1" targetFramework="net452" />
|
||||
<package id="System.Runtime.Extensions" version="4.3.1" targetFramework="net452" />
|
||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Text.RegularExpressions" version="4.3.1" targetFramework="net452" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.1" targetFramework="net452" />
|
||||
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net452" />
|
||||
</packages>
|
||||
BIN
packages/Costura.Fody.4.1.0/.signature.p7s
vendored
BIN
packages/Costura.Fody.4.1.0/Costura.Fody.4.1.0.nupkg
vendored
@@ -1,5 +0,0 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<WeaverFiles Include="$(MsBuildThisFileDirectory)..\weaver\$(MSBuildThisFileName).dll" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||