Compare commits
1148
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cdccd6a54 | ||
|
|
829a333d7f | ||
|
|
42984efe25 | ||
|
|
7656468636 | ||
|
|
448a169bc3 | ||
|
|
27cacc03a2 | ||
|
|
2002db57d9 | ||
|
|
0aad1ef358 | ||
|
|
d8f5b5e910 | ||
|
|
3d5c832cec | ||
|
|
bc467ac335 | ||
|
|
aee5f38fb5 | ||
|
|
a4612a127d | ||
|
|
7a21f11b64 | ||
|
|
4775715b66 | ||
|
|
c481d5fca9 | ||
|
|
be65e6816d | ||
|
|
1f2200c584 | ||
|
|
52b58dc79b | ||
|
|
de92e4670c | ||
|
|
4806bb89eb | ||
|
|
0cdbf9ce99 | ||
|
|
a7bde644a4 | ||
|
|
e461b4654e | ||
|
|
8d7f2dfee8 | ||
|
|
bf5bc08671 | ||
|
|
437bef3d03 | ||
|
|
024079c4bc | ||
|
|
ed53f509ee | ||
|
|
6b90aedae8 | ||
|
|
4db73ff3d1 | ||
|
|
4a092f0920 | ||
|
|
186c1f80e6 | ||
|
|
59c8be9ac2 | ||
|
|
eb2c4c02d2 | ||
|
|
fe2fd354fd | ||
|
|
16fd8925ff | ||
|
|
661302d90f | ||
|
|
2c8dd6e89a | ||
|
|
91fe8a8fb4 | ||
|
|
cc3456758e | ||
|
|
c2dc772905 | ||
|
|
9915e8d2df | ||
|
|
5c79dbe1c2 | ||
|
|
f83e97404a | ||
|
|
f704d54178 | ||
|
|
3577e3b70c | ||
|
|
000bd5e7d3 | ||
|
|
4d3e8d4354 | ||
|
|
0d51b40676 | ||
|
|
054f03480e | ||
|
|
114b46ccee | ||
|
|
0715c0cfcf | ||
|
|
a51a146780 | ||
|
|
c2c3ea68fa | ||
|
|
8e40da9fb4 | ||
|
|
d6b744533b | ||
|
|
df1d411ae0 | ||
|
|
2904616d67 | ||
|
|
61eac6feca | ||
|
|
1f29f2ddc5 | ||
|
|
fbff3eadde | ||
|
|
7c8a76616c | ||
|
|
465d52df67 | ||
|
|
57e69b0d98 | ||
|
|
a799828de0 | ||
|
|
e6ad306e24 | ||
|
|
5ff1e0a0a6 | ||
|
|
09048a7a21 | ||
|
|
2e2e890875 | ||
|
|
271b1cdfee | ||
|
|
bc06512250 | ||
|
|
a94af3a4db | ||
|
|
924a34b458 | ||
|
|
f73b880b6d | ||
|
|
a53a9eaeaa | ||
|
|
88390f0fc9 | ||
|
|
c6721841ac | ||
|
|
dfa77311f2 | ||
|
|
57e241ab7d | ||
|
|
50b97aac8a | ||
|
|
6166b29b29 | ||
|
|
7ee1331263 | ||
|
|
0cc0299215 | ||
|
|
a7e0f2ae2b | ||
|
|
c38e0aa61e | ||
|
|
9496da151a | ||
|
|
5cec11c6dd | ||
|
|
a285bf4270 | ||
|
|
344c418412 | ||
|
|
5464053fa0 | ||
|
|
8036fc332b | ||
|
|
c1cb5c23ae | ||
|
|
dbb25fbabd | ||
|
|
d75a339a02 | ||
|
|
6fd15a05ff | ||
|
|
0d991138c0 | ||
|
|
5264a397a0 | ||
|
|
c2fe5e6c3c | ||
|
|
7c232b70ed | ||
|
|
8761d23bda | ||
|
|
81203ef531 | ||
|
|
743356af01 | ||
|
|
036cf4846c | ||
|
|
7f97394861 | ||
|
|
d439469f39 | ||
|
|
8ec891d0bc | ||
|
|
bb318aeeb1 | ||
|
|
6621f7c2a2 | ||
|
|
108e212c56 | ||
|
|
f923db90ea | ||
|
|
e5a0e9617b | ||
|
|
e0d27dd97c | ||
|
|
5d49fc586b | ||
|
|
e1beef2e29 | ||
|
|
0803e73949 | ||
|
|
e7b8dd56fe | ||
|
|
add56248e1 | ||
|
|
90a539d361 | ||
|
|
ed2645e3ff | ||
|
|
cdc8d2eaf2 | ||
|
|
bdb9dc670c | ||
|
|
32b3a035a8 | ||
|
|
c44aea13d6 | ||
|
|
ce4bb21782 | ||
|
|
fa5716d651 | ||
|
|
c7971c9860 | ||
|
|
9d3e7c53de | ||
|
|
81c4e1c019 | ||
|
|
a4125653cf | ||
|
|
3c3b51d6ab | ||
|
|
9e21dee290 | ||
|
|
c341e493f8 | ||
|
|
e6325c74d8 | ||
|
|
e703adb168 | ||
|
|
ae2b9e0cce | ||
|
|
6db84cbc12 | ||
|
|
db41faee3e | ||
|
|
905158bb07 | ||
|
|
a08782de4e | ||
|
|
0fcbffab26 | ||
|
|
30d6ccbd9a | ||
|
|
cd7f3f8b52 | ||
|
|
4b57fa9414 | ||
|
|
9d3099f816 | ||
|
|
a0c02b2fd1 | ||
|
|
df8c86fe4c | ||
|
|
008a24bfff | ||
|
|
5484766ef1 | ||
|
|
b36a3bfbdb | ||
|
|
7fc842c9ef | ||
|
|
8615faff4a | ||
|
|
ba05c831cc | ||
|
|
3f11a14d92 | ||
|
|
0284dec33a | ||
|
|
8d376d9e5a | ||
|
|
ce731b1832 | ||
|
|
64a8552647 | ||
|
|
e0b06449ec | ||
|
|
64d62b10a1 | ||
|
|
1a3cf8695d | ||
|
|
1251dd1d2d | ||
|
|
06d5b1a779 | ||
|
|
c18a3dde9e | ||
|
|
6961bc073a | ||
|
|
e1b6f8d66f | ||
|
|
b95edec916 | ||
|
|
8756cd1f20 | ||
|
|
8122c92bbf | ||
|
|
3e53455a05 | ||
|
|
07ddb66264 | ||
|
|
4fef230a06 | ||
|
|
2d73131863 | ||
|
|
f90ae6bade | ||
|
|
b4a45a17c7 | ||
|
|
8767540164 | ||
|
|
fb8e327856 | ||
|
|
344b30aa62 | ||
|
|
d776693aea | ||
|
|
aaf2f9c6c9 | ||
|
|
5fbabfbe23 | ||
|
|
42645a5414 | ||
|
|
5af63e0adf | ||
|
|
ba430052de | ||
|
|
a81ebed663 | ||
|
|
920883ada1 | ||
|
|
41c5f57ccc | ||
|
|
2aa7862fe1 | ||
|
|
22795bab81 | ||
|
|
9ae1c0c1bb | ||
|
|
c155e560ba | ||
|
|
f92dd71d35 | ||
|
|
474f9f0197 | ||
|
|
aee76ba2ff | ||
|
|
398b6fc37b | ||
|
|
454cea3556 | ||
|
|
90816b5c67 | ||
|
|
7c1ac4b267 | ||
|
|
c145b64441 | ||
|
|
2ad5ab7a87 | ||
|
|
95fd69c5da | ||
|
|
1a3f18cbc2 | ||
|
|
f4031ead02 | ||
|
|
37b7783b40 | ||
|
|
8059743e0b | ||
|
|
2c1beedf8b | ||
|
|
484510da77 | ||
|
|
ddf046cd20 | ||
|
|
1c5316ba4e | ||
|
|
5503caed79 | ||
|
|
1f11530d04 | ||
|
|
95b5fca205 | ||
|
|
7432fe7aba | ||
|
|
c4630042c7 | ||
|
|
16f4178e36 | ||
|
|
421d080ec7 | ||
|
|
381a759c4b | ||
|
|
08bb1e1174 | ||
|
|
7fec602f34 | ||
|
|
1f9aca7399 | ||
|
|
6b5c5bedea | ||
|
|
0901af5106 | ||
|
|
5ef7b85e87 | ||
|
|
7facf974e6 | ||
|
|
eb21d3d11c | ||
|
|
03e8d7873e | ||
|
|
11faab902f | ||
|
|
9c1b00ef23 | ||
|
|
f40d3a5aac | ||
|
|
07aa13d9b0 | ||
|
|
0b267091ba | ||
|
|
ead6860674 | ||
|
|
a87c34f1fd | ||
|
|
4e4813fd5c | ||
|
|
58e728f26c | ||
|
|
35282945cc | ||
|
|
18965af7d8 | ||
|
|
a3987abf11 | ||
|
|
58ab5cf4cf | ||
|
|
6f115d1766 | ||
|
|
568a489993 | ||
|
|
2e50607a90 | ||
|
|
560321f4a3 | ||
|
|
afc0173423 | ||
|
|
da5ac90189 | ||
|
|
d8d435c994 | ||
|
|
0e225db32d | ||
|
|
e06e5ac3a7 | ||
|
|
a073314c28 | ||
|
|
c643776790 | ||
|
|
a67f3cd11e | ||
|
|
04087259c3 | ||
|
|
3f6177150d | ||
|
|
3f339821f7 | ||
|
|
9abef592fb | ||
|
|
a561f05b32 | ||
|
|
a8c4f0d505 | ||
|
|
93551d6b2d | ||
|
|
6ff176e5d4 | ||
|
|
cdec126f54 | ||
|
|
2885129531 | ||
|
|
f84a04356a | ||
|
|
621bc6aef7 | ||
|
|
e4dfb30870 | ||
|
|
2b4da660c7 | ||
|
|
a870e09609 | ||
|
|
32f3a11713 | ||
|
|
104ae44b84 | ||
|
|
17f8932ff4 | ||
|
|
0d4d820993 | ||
|
|
878bf49dc4 | ||
|
|
fe8ab52595 | ||
|
|
dd1a3774f8 | ||
|
|
7e1bd28d26 | ||
|
|
59593db4ec | ||
|
|
6694739a4f | ||
|
|
4323802862 | ||
|
|
c2056853e0 | ||
|
|
d15a439477 | ||
|
|
bb59cfa68a | ||
|
|
144b502c25 | ||
|
|
b6c8992441 | ||
|
|
7a5124a820 | ||
|
|
f5cac67d38 | ||
|
|
5b38ea3b3f | ||
|
|
e6a687264b | ||
|
|
6d16fbe260 | ||
|
|
047c6c94be | ||
|
|
41229fbab0 | ||
|
|
8fb885a373 | ||
|
|
dc294ccef0 | ||
|
|
24ef392b1c | ||
|
|
da1efc7261 | ||
|
|
c42245abf3 | ||
|
|
76dc857a43 | ||
|
|
df11c3b517 | ||
|
|
f6500096fa | ||
|
|
792c0afe06 | ||
|
|
11f7faa0ad | ||
|
|
75f03ac207 | ||
|
|
b1df22d207 | ||
|
|
47737a72f8 | ||
|
|
0331bcfa7b | ||
|
|
0928227fac | ||
|
|
8fbc961f47 | ||
|
|
1f667b4133 | ||
|
|
379d6aab8e | ||
|
|
82e164b351 | ||
|
|
f4ca06d27e | ||
|
|
a1fe7bb5db | ||
|
|
f01d5efa92 | ||
|
|
9d0e607c0b | ||
|
|
413c58c936 | ||
|
|
c83b6e4c76 | ||
|
|
c5d1e73dc6 | ||
|
|
35d8b6106d | ||
|
|
6d9f0b9413 | ||
|
|
2d98e6c40b | ||
|
|
10a300b614 | ||
|
|
902d50cef4 | ||
|
|
c518ce4482 | ||
|
|
4d719e4308 | ||
|
|
5bd52c23ae | ||
|
|
2755c93147 | ||
|
|
25c5182877 | ||
|
|
5af8cb9745 | ||
|
|
45ca60570c | ||
|
|
d65334086e | ||
|
|
c2b3e3f88e | ||
|
|
7b3b939cc6 | ||
|
|
0995366ae2 | ||
|
|
16be89be00 | ||
|
|
3bf1a8d398 | ||
|
|
1e876a9217 | ||
|
|
2d21a85259 | ||
|
|
87ef92eff8 | ||
|
|
0e16bbf4f5 | ||
|
|
edb79e3d7d | ||
|
|
1c6ba006b5 | ||
|
|
6350dbc397 | ||
|
|
827ab9f82d | ||
|
|
587e729bdc | ||
|
|
851265e14a | ||
|
|
b553ef1c75 | ||
|
|
5570f8be88 | ||
|
|
775f4f12fe | ||
|
|
1410aaf7ef | ||
|
|
b85aece87b | ||
|
|
4caf2f1e6e | ||
|
|
60eb78c27f | ||
|
|
701edfa823 | ||
|
|
e234f3bce4 | ||
|
|
f80241b5c0 | ||
|
|
9adc74ff46 | ||
|
|
fbc4d054b0 | ||
|
|
3676e1f568 | ||
|
|
88832da5ea | ||
|
|
2175dad72f | ||
|
|
7c45258976 | ||
|
|
01e1ccb4bf | ||
|
|
966312373e | ||
|
|
b1b06f480b | ||
|
|
ea1252c07c | ||
|
|
871695731c | ||
|
|
b7e1326489 | ||
|
|
d02ae1e212 | ||
|
|
6af700e187 | ||
|
|
01f0175467 | ||
|
|
86d85aec3c | ||
|
|
c2001c24f6 | ||
|
|
7726ad974c | ||
|
|
1f859997f4 | ||
|
|
1c20fd4c19 | ||
|
|
bdee61948d | ||
|
|
6c903dcd20 | ||
|
|
dd5cf0eace | ||
|
|
c713d9a59b | ||
|
|
2029447d86 | ||
|
|
81f225be5b | ||
|
|
6258e524d9 | ||
|
|
cf3ecaa325 | ||
|
|
9c9afa9925 | ||
|
|
9ee1357b53 | ||
|
|
cf376364ba | ||
|
|
0fa5a97661 | ||
|
|
a3c7b2a6fb | ||
|
|
a1cc6c5adf | ||
|
|
86051d3b01 | ||
|
|
28e5bbf2de | ||
|
|
9373375a95 | ||
|
|
295f37b9f5 | ||
|
|
06c526ef74 | ||
|
|
d4f737167d | ||
|
|
8c3be43f25 | ||
|
|
880487f841 | ||
|
|
2d73e10bbf | ||
|
|
6a37a8e9e4 | ||
|
|
4868e506f3 | ||
|
|
db9721e96a | ||
|
|
34c560e105 | ||
|
|
c65f20f8bb | ||
|
|
0fefcafba8 | ||
|
|
730e61836f | ||
|
|
f212fdcae8 | ||
|
|
9acffafda0 | ||
|
|
1a62889cb9 | ||
|
|
4ff5ea9fec | ||
|
|
77bc356f4b | ||
|
|
be5633f29c | ||
|
|
1bf6c00e4c | ||
|
|
9cc5eab93d | ||
|
|
39bd57b3f6 | ||
|
|
a50452fb58 | ||
|
|
63229b42c1 | ||
|
|
8e5f3ec3b6 | ||
|
|
61a4ef17a4 | ||
|
|
4498d231ad | ||
|
|
eb659dd453 | ||
|
|
7aa3205c79 | ||
|
|
3a49e3ba01 | ||
|
|
cb07a9c8dd | ||
|
|
bd8a20e64c | ||
|
|
dcb0471d33 | ||
|
|
49c1ca45c8 | ||
|
|
e2ca160507 | ||
|
|
0a3b6f5bc0 | ||
|
|
2391174a0a | ||
|
|
1ddaa8d162 | ||
|
|
54e5930e8d | ||
|
|
dad839ca56 | ||
|
|
8d60831e65 | ||
|
|
837a888b37 | ||
|
|
39dae8f8e8 | ||
|
|
90761b1599 | ||
|
|
75394d2239 | ||
|
|
bf3dab1585 | ||
|
|
f224645c9c | ||
|
|
36a9d621b4 | ||
|
|
f1c2d2c95a | ||
|
|
b71581d48a | ||
|
|
81e85fba7e | ||
|
|
ed6244919d | ||
|
|
782ff2bb66 | ||
|
|
2a02efec0d | ||
|
|
a74c48d8d0 | ||
|
|
5054dbdc7d | ||
|
|
0db27e1690 | ||
|
|
93937be836 | ||
|
|
2649b21ac7 | ||
|
|
d83dc9370d | ||
|
|
c3bae00331 | ||
|
|
13b5ad11a8 | ||
|
|
bf90cbd9ee | ||
|
|
ac25b978e3 | ||
|
|
6549c3e51a | ||
|
|
aa301b007c | ||
|
|
d17663bb6e | ||
|
|
49ae2bdbe3 | ||
|
|
f2bc513869 | ||
|
|
6abc2e4cf9 | ||
|
|
0fba48dd73 | ||
|
|
9fa484d378 | ||
|
|
697189a2b9 | ||
|
|
b39493bd3d | ||
|
|
44e1f1b265 | ||
|
|
e73855a830 | ||
|
|
4e50cf3f8d | ||
|
|
7869a3163f | ||
|
|
036e9939c7 | ||
|
|
b743f64b3e | ||
|
|
0f40f58801 | ||
|
|
f52a20aa1a | ||
|
|
158ca27531 | ||
|
|
e48ed3aac6 | ||
|
|
733ed9daf0 | ||
|
|
f15ea0ee00 | ||
|
|
e95bd7e3c1 | ||
|
|
af667093ef | ||
|
|
5b3c8fd9da | ||
|
|
cc76d48f00 | ||
|
|
994cfa9f21 | ||
|
|
cee15d5ebb | ||
|
|
6fe72ebb9f | ||
|
|
a4cc33d3ce | ||
|
|
7eeb1c3bf2 | ||
|
|
ca49a100fa | ||
|
|
fd41df894f | ||
|
|
82b85e6bfd | ||
|
|
b154e4c5f0 | ||
|
|
03112dd9f7 | ||
|
|
ef51d5d2b9 | ||
|
|
58577e74f7 | ||
|
|
54aac33525 | ||
|
|
b27cef0d1b | ||
|
|
5dfc3b4f02 | ||
|
|
5acf70169c | ||
|
|
0e388f5888 | ||
|
|
2a5c5cb24f | ||
|
|
58ec32be6f | ||
|
|
21fb5fc48b | ||
|
|
d6fcafe8e0 | ||
|
|
95ade723f9 | ||
|
|
de31594250 | ||
|
|
0ff208c2f9 | ||
|
|
92c69e3d97 | ||
|
|
c065eaac6b | ||
|
|
fed9d76bcb | ||
|
|
fdb9819ca9 | ||
|
|
90b773dd52 | ||
|
|
206ffd17c8 | ||
|
|
5363378ea1 | ||
|
|
bee1e760b8 | ||
|
|
996760489f | ||
|
|
65af8e24c1 | ||
|
|
d59ef7ddfe | ||
|
|
9ab654b290 | ||
|
|
7217e75a15 | ||
|
|
ae4847d056 | ||
|
|
88b882c74d | ||
|
|
7b12cb9922 | ||
|
|
06a6d6e575 | ||
|
|
20f043885a | ||
|
|
7ff5d24d10 | ||
|
|
70059b25d8 | ||
|
|
a7f23c7b72 | ||
|
|
c056add894 | ||
|
|
fbca333163 | ||
|
|
52b153ba82 | ||
|
|
6b9bc3cdd9 | ||
|
|
c6647ff807 | ||
|
|
b4c2d075ab | ||
|
|
4835485085 | ||
|
|
937b01e55b | ||
|
|
3630b44d38 | ||
|
|
086b07ace9 | ||
|
|
1efdad97eb | ||
|
|
4bd2b31e1d | ||
|
|
97cd94de4a | ||
|
|
820b9fd969 | ||
|
|
a64f4d1377 | ||
|
|
15e9b5c712 | ||
|
|
c8302d6024 | ||
|
|
cc98e5bdb8 | ||
|
|
9f07840030 | ||
|
|
534bd61c3a | ||
|
|
e68847ca77 | ||
|
|
8a91ccd47e | ||
|
|
e082511d59 | ||
|
|
146d4d42e8 | ||
|
|
d364b2c87a | ||
|
|
257b2e33f2 | ||
|
|
b6afe6f5db | ||
|
|
d6959cd074 | ||
|
|
96f752c6ac | ||
|
|
f8fa4b6c67 | ||
|
|
db7a94a10c | ||
|
|
6aa9eef8ea | ||
|
|
dac5053eb5 | ||
|
|
c0a3a6c54f | ||
|
|
b2a34380b6 | ||
|
|
1237a9f8ac | ||
|
|
0a6d00b4ab | ||
|
|
27c8a1575f | ||
|
|
f7a137537c | ||
|
|
8953ee1f7f | ||
|
|
8da5f35c33 | ||
|
|
0bc2d2b896 | ||
|
|
3167dfab09 | ||
|
|
6c1130aed2 | ||
|
|
bded70f6c6 | ||
|
|
097a6feeb7 | ||
|
|
bd2d49de85 | ||
|
|
4dd43961d4 | ||
|
|
9c968d1f4f | ||
|
|
261592a6b3 | ||
|
|
a5b45c318d | ||
|
|
d50f42a8b0 | ||
|
|
1ec2e1dd4b | ||
|
|
62bd5588e3 | ||
|
|
1c6fd7050d | ||
|
|
94a5ddcc5f | ||
|
|
5b756b0c7a | ||
|
|
d940bb63d6 | ||
|
|
4610626cc7 | ||
|
|
09704a2f0f | ||
|
|
bce4952254 | ||
|
|
4b7fb82710 | ||
|
|
acb06b6953 | ||
|
|
c11bee25d1 | ||
|
|
7543021cff | ||
|
|
019c29bfae | ||
|
|
1c7e010aa2 | ||
|
|
a7c9b7dd58 | ||
|
|
8e0ff61597 | ||
|
|
8d5cc68a87 | ||
|
|
3e765ba22c | ||
|
|
bea91dd654 | ||
|
|
d14f9a7a4d | ||
|
|
8694d39dcb | ||
|
|
7c808f608f | ||
|
|
42856485fc | ||
|
|
76e768dda8 | ||
|
|
59d243bb5b | ||
|
|
3a6cd04a84 | ||
|
|
4b0bc25e0b | ||
|
|
2ef6206599 | ||
|
|
e092da882c | ||
|
|
9c10b06390 | ||
|
|
65208fba3c | ||
|
|
36d13cdd72 | ||
|
|
f9c3484c0e | ||
|
|
f8e22cbfbc | ||
|
|
5da7f8e2f4 | ||
|
|
c7bfc871c1 | ||
|
|
fd26567990 | ||
|
|
d27e304136 | ||
|
|
7f91075a92 | ||
|
|
4436c1d9f1 | ||
|
|
69822b4071 | ||
|
|
91117a5dea | ||
|
|
2a1b799f7e | ||
|
|
119d759105 | ||
|
|
b94462fdf0 | ||
|
|
2820a132d8 | ||
|
|
46625fdecc | ||
|
|
3ec0cfad4d | ||
|
|
6e08ec86ae | ||
|
|
125abe9e36 | ||
|
|
eaf94aa97f | ||
|
|
8a0c0f61f5 | ||
|
|
a49efd7403 | ||
|
|
6196b828c3 | ||
|
|
7a5421706e | ||
|
|
43f62669e9 | ||
|
|
f1d77a639c | ||
|
|
b2e6f55487 | ||
|
|
c6b520fb65 | ||
|
|
e5d5447957 | ||
|
|
3048b098b5 | ||
|
|
b71430f135 | ||
|
|
20bae023d9 | ||
|
|
9fd973c496 | ||
|
|
97ed8000b8 | ||
|
|
c7f18e434f | ||
|
|
6d5b9dd188 | ||
|
|
af59a13dd9 | ||
|
|
771ac02c77 | ||
|
|
925065b317 | ||
|
|
2893050504 | ||
|
|
849a48597c | ||
|
|
ab85d0b03a | ||
|
|
7ce2dd95e2 | ||
|
|
07032c21db | ||
|
|
9cb56466c8 | ||
|
|
c49e985013 | ||
|
|
fbd3f1798a | ||
|
|
66a53f3486 | ||
|
|
45acdecedc | ||
|
|
ec105f2b55 | ||
|
|
858c5b9342 | ||
|
|
b548f6adf3 | ||
|
|
719147997c | ||
|
|
9489ddad5e | ||
|
|
f479c36fcd | ||
|
|
9a925e7100 | ||
|
|
7e7f091ab5 | ||
|
|
8aa6c41037 | ||
|
|
f30994b82e | ||
|
|
873b83cb31 | ||
|
|
4a04f50f98 | ||
|
|
ff31cb0377 | ||
|
|
8c16e3dc42 | ||
|
|
799d06dd10 | ||
|
|
985a2b30c6 | ||
|
|
66a8c909ee | ||
|
|
6439021fc2 | ||
|
|
0a09423e10 | ||
|
|
119ae933e2 | ||
|
|
1fd27c5acf | ||
|
|
e3f338c91f | ||
|
|
39723bcf5b | ||
|
|
d570a77bd5 | ||
|
|
7b1fcfb15a | ||
|
|
17ba841440 | ||
|
|
6ea830cbc7 | ||
|
|
179b1769ae | ||
|
|
3cae6da5d7 | ||
|
|
b1ce420393 | ||
|
|
a8d1bdc8a8 | ||
|
|
f9d0d239b8 | ||
|
|
877153a998 | ||
|
|
35c7c4c08d | ||
|
|
e3340a76db | ||
|
|
94cef1b5f8 | ||
|
|
ecc224776e | ||
|
|
7deb1bba58 | ||
|
|
7ff965c73d | ||
|
|
9cc136bfda | ||
|
|
8ef0aeef13 | ||
|
|
d906c1103b | ||
|
|
7bfdc6255c | ||
|
|
c5162a05aa | ||
|
|
d5353a87dc | ||
|
|
3072531c24 | ||
|
|
d87ff342d4 | ||
|
|
3266b8ccd6 | ||
|
|
03cc03b6bf | ||
|
|
2df8cc5f2a | ||
|
|
8fd7116759 | ||
|
|
bd4310e6e8 | ||
|
|
dfa7ba031e | ||
|
|
6ddea672ad | ||
|
|
047378a11d | ||
|
|
3420c4abb0 | ||
|
|
15a8d70f5f | ||
|
|
91f90a6609 | ||
|
|
e170b70999 | ||
|
|
b489011d24 | ||
|
|
58adfbd261 | ||
|
|
3bb18b6daf | ||
|
|
120bf18416 | ||
|
|
428c4ef7d6 | ||
|
|
40fc05fc15 | ||
|
|
2e913223a2 | ||
|
|
48f12a912c | ||
|
|
0228c0b8a1 | ||
|
|
ba07aeb4d7 | ||
|
|
529b13f18b | ||
|
|
5720fddb59 | ||
|
|
f5c80b230a | ||
|
|
87ee01bac9 | ||
|
|
126ad044f2 | ||
|
|
b636648457 | ||
|
|
bf3672a8c4 | ||
|
|
e6478d5161 | ||
|
|
ddea78aa4b | ||
|
|
b872fb17b8 | ||
|
|
4ec2c17df1 | ||
|
|
38a51f48d0 | ||
|
|
838897611c | ||
|
|
f42150063c | ||
|
|
d164d1219d | ||
|
|
fb71b4d781 | ||
|
|
f338738c1e | ||
|
|
fb704c7388 | ||
|
|
c99bca4200 | ||
|
|
92f43acb80 | ||
|
|
a7c85a24f2 | ||
|
|
fe5616b3f7 | ||
|
|
5c882c5ce2 | ||
|
|
61a4ed43b9 | ||
|
|
b242ad7ae4 | ||
|
|
1b02e806f8 | ||
|
|
eaf23a24ba | ||
|
|
ce64296c01 | ||
|
|
6e3716fe01 | ||
|
|
dcdd83243b | ||
|
|
986ec2987c | ||
|
|
c98609db5d | ||
|
|
0b4e3c6303 | ||
|
|
bc3e5a706d | ||
|
|
0b56d9dd23 | ||
|
|
62ccdf8eba | ||
|
|
72f4226419 | ||
|
|
f6a45beac5 | ||
|
|
a657ddef58 | ||
|
|
726e38ff2e | ||
|
|
191d3f760e | ||
|
|
2cd3b0f39c | ||
|
|
abd990eef7 | ||
|
|
cd875af7d7 | ||
|
|
b1e8f93371 | ||
|
|
64afd0222b | ||
|
|
32369f1f38 | ||
|
|
f00be506cc | ||
|
|
248fd1ce9c | ||
|
|
3e2d4bb665 | ||
|
|
92689941ca | ||
|
|
c46110cfea | ||
|
|
b5250e0b8d | ||
|
|
0e81397305 | ||
|
|
95d306eaed | ||
|
|
339a4fe01f | ||
|
|
48cdbc7681 | ||
|
|
5e85ba10f4 | ||
|
|
ea7dd7aba5 | ||
|
|
c60b766f37 | ||
|
|
da9ded2ae1 | ||
|
|
29eb517bb9 | ||
|
|
84a3f6caff | ||
|
|
b34821463a | ||
|
|
127abbaaeb | ||
|
|
d462d42775 | ||
|
|
5e80ad7e4e | ||
|
|
e1aadade5f | ||
|
|
77d6f5d977 | ||
|
|
c4ae2ec0a3 | ||
|
|
07ee9269b7 | ||
|
|
3ee43f1c50 | ||
|
|
dd65196af9 | ||
|
|
5547de006b | ||
|
|
0fbf571c60 | ||
|
|
f5f05697b6 | ||
|
|
5f179f6a26 | ||
|
|
37c6d29e84 | ||
|
|
0e81ba31cb | ||
|
|
1f24d32109 | ||
|
|
ff16f84c43 | ||
|
|
5b929bf515 | ||
|
|
bdcb3db238 | ||
|
|
f7960b1695 | ||
|
|
825d1b95da | ||
|
|
0e7abaf3f0 | ||
|
|
2731989ae8 | ||
|
|
5ad09e11df | ||
|
|
653d2eeeee | ||
|
|
756ad615ed | ||
|
|
dd6abafad5 | ||
|
|
0434f06bb5 | ||
|
|
50971098ad | ||
|
|
1787f10fca | ||
|
|
6d2684db70 | ||
|
|
f0f1b3a946 | ||
|
|
ae9b703726 | ||
|
|
10512fb74b | ||
|
|
ce9bdba30c | ||
|
|
188c98589c | ||
|
|
e5fa42ff14 | ||
|
|
f42aa95003 | ||
|
|
b16dc816b6 | ||
|
|
b86fe4d65d | ||
|
|
d7e17416f1 | ||
|
|
91355f1dd5 | ||
|
|
ae9e3ed07c | ||
|
|
f701993b0f | ||
|
|
c5bf617f65 | ||
|
|
f09cae1684 | ||
|
|
99d7f06981 | ||
|
|
eaaf7e2bbf | ||
|
|
897382de2b | ||
|
|
55d02a8412 | ||
|
|
7733582238 | ||
|
|
754c8339df | ||
|
|
ebf7baaa65 | ||
|
|
8b26b12813 | ||
|
|
5deb4186f9 | ||
|
|
d3d501f94a | ||
|
|
634f1213d4 | ||
|
|
6fa97ee435 | ||
|
|
05b3342763 | ||
|
|
d434f42d12 | ||
|
|
084f13eda4 | ||
|
|
ed59b54618 | ||
|
|
df282b95ad | ||
|
|
1b38533c83 | ||
|
|
8f4c370ab2 | ||
|
|
9360ea4d85 | ||
|
|
c87d6581c8 | ||
|
|
7133fc6c03 | ||
|
|
46af5af250 | ||
|
|
5b9cc6778c | ||
|
|
5260ad8243 | ||
|
|
2996772020 | ||
|
|
d37534cb6b | ||
|
|
92eb48c21e | ||
|
|
d9e867cb6e | ||
|
|
f200c6e59a | ||
|
|
c668f3bf9a | ||
|
|
bd7afee09b | ||
|
|
ff09a4aec0 | ||
|
|
1e6c60f2ed | ||
|
|
beedb1538d | ||
|
|
8463f9e963 | ||
|
|
ce8f88b8d4 | ||
|
|
ff7d080b5a | ||
|
|
12ad83c607 | ||
|
|
cdf5d2c37c | ||
|
|
9af8e1729e | ||
|
|
d5219ed322 | ||
|
|
7af9a72e77 | ||
|
|
08817bde7e | ||
|
|
d1e9aadd71 | ||
|
|
b6307182cd | ||
|
|
cc70e55b53 | ||
|
|
ed08e97a50 | ||
|
|
44904786d9 | ||
|
|
12b67ce189 | ||
|
|
21b0edf092 | ||
|
|
2adb446d80 | ||
|
|
60738458bb | ||
|
|
a591026258 | ||
|
|
1bab7fa17c | ||
|
|
2713216728 | ||
|
|
f9a529275a | ||
|
|
e992203b7c | ||
|
|
0ed057d705 | ||
|
|
9b70ca6faf | ||
|
|
422c3e4a6c | ||
|
|
6dac880d61 | ||
|
|
c911b2d64e | ||
|
|
39f72f9058 | ||
|
|
2bff354ad0 | ||
|
|
cb55e9b96f | ||
|
|
33f551d464 | ||
|
|
282fa7bdda | ||
|
|
0abd97e8e1 | ||
|
|
5dd616685d | ||
|
|
aff99be92d | ||
|
|
c255f1e498 | ||
|
|
70342daf07 | ||
|
|
f95672e57d | ||
|
|
8f5da42df4 | ||
|
|
4022903069 | ||
|
|
4600c185e4 | ||
|
|
30e8ec0038 | ||
|
|
367b212ca3 | ||
|
|
6533feb62b | ||
|
|
95ef37f6a3 | ||
|
|
6216c66d95 | ||
|
|
02b6e4a728 | ||
|
|
00c1e926e6 | ||
|
|
ef8109e2e8 | ||
|
|
732ee76957 | ||
|
|
b97d2261de | ||
|
|
c362bfc8da | ||
|
|
cc445e4aea | ||
|
|
4ac83d59b5 | ||
|
|
5025a5fa94 | ||
|
|
b8cb19c8db | ||
|
|
593153de8f | ||
|
|
6c36b83d64 | ||
|
|
1381fdd3bb | ||
|
|
f680a37eb1 | ||
|
|
4531b7af52 | ||
|
|
0c4d1af2dc | ||
|
|
d6a18ecca6 | ||
|
|
dc768952c3 | ||
|
|
57cdcfcbd1 | ||
|
|
fb4837ce40 | ||
|
|
b85e1e6937 | ||
|
|
727201ece9 | ||
|
|
c711c3126e | ||
|
|
cdcf218160 | ||
|
|
ee652593c0 | ||
|
|
90773529e6 | ||
|
|
0134a7c82c | ||
|
|
fec3d40d7d | ||
|
|
bdf36f42d3 | ||
|
|
23967490e9 | ||
|
|
3bcd197618 | ||
|
|
ac3eba5654 | ||
|
|
9576856b0b | ||
|
|
f17975c92f | ||
|
|
07a24eab2f | ||
|
|
edc9276fac | ||
|
|
c7531eb652 | ||
|
|
5c1452ff57 | ||
|
|
e467044e41 | ||
|
|
5c5780f720 | ||
|
|
7119bab9c9 | ||
|
|
2eccc92510 | ||
|
|
b9e0fcdb04 | ||
|
|
5c15912b1b | ||
|
|
ac6525e49a | ||
|
|
3e67973a27 | ||
|
|
ed4e295e71 | ||
|
|
73b57399d5 | ||
|
|
9e0b67478d | ||
|
|
341eb37ff4 | ||
|
|
6d68a77e42 | ||
|
|
b50f56a5d4 | ||
|
|
e226438b09 | ||
|
|
a5db0793d6 | ||
|
|
07e1f1a1d3 | ||
|
|
de77e3484b | ||
|
|
24571ea22f | ||
|
|
515f90105c | ||
|
|
0d305dbc7e | ||
|
|
05bf888ba6 | ||
|
|
a2a53e8215 | ||
|
|
e6290b8aba | ||
|
|
aa5f6e7cbe | ||
|
|
054b447236 | ||
|
|
52db475469 | ||
|
|
6282800fdb | ||
|
|
20517fdf51 | ||
|
|
40400817c1 | ||
|
|
834e454eb2 | ||
|
|
2747c9efc8 | ||
|
|
c2cc782ee3 | ||
|
|
d414e79b6b | ||
|
|
9e0f95ed94 | ||
|
|
167da56a0b | ||
|
|
af213869c8 | ||
|
|
39b9e42f62 | ||
|
|
1aa07afabc | ||
|
|
84d7d0bef6 | ||
|
|
fbb7f2320e | ||
|
|
506f5c7597 | ||
|
|
38d3a40d7a | ||
|
|
44cb073de8 | ||
|
|
8a680e5429 | ||
|
|
16dbdc5ec3 | ||
|
|
4cece4566c | ||
|
|
2340cbbbb2 | ||
|
|
e00feded18 | ||
|
|
d7c5e88c00 | ||
|
|
7462d739f4 | ||
|
|
f1bbdeac45 | ||
|
|
178bdbf988 | ||
|
|
82a5d40a10 | ||
|
|
c888bd3f3c | ||
|
|
53f45f49c3 | ||
|
|
3c108c7520 | ||
|
|
11bce261ae | ||
|
|
5f8204c48e | ||
|
|
f6043ed413 | ||
|
|
5ab22cd5c4 | ||
|
|
ee20e461d2 | ||
|
|
9fa6513d4b | ||
|
|
e86c7b190a | ||
|
|
0b2c5dc578 | ||
|
|
55b569c057 | ||
|
|
02d6fb3b14 | ||
|
|
8ed21f8fa9 | ||
|
|
6c1a12b345 | ||
|
|
05f4462195 | ||
|
|
e4bb903391 | ||
|
|
5028fe9d7f | ||
|
|
9bca7a3598 | ||
|
|
dddb414c7d | ||
|
|
ad67bed400 | ||
|
|
5ffa2fac40 | ||
|
|
cca1bc6607 | ||
|
|
55f49d7d3a | ||
|
|
a24f8bef3d | ||
|
|
c41a0de1af | ||
|
|
d4c8b795fa | ||
|
|
47c219ad8c | ||
|
|
59b34ddf3e | ||
|
|
01f1e3993c | ||
|
|
c21cadad1d | ||
|
|
307d15ff24 | ||
|
|
5edebee51e | ||
|
|
3d936f4abd | ||
|
|
e725c05e9c | ||
|
|
5a8a33cebc | ||
|
|
da28a5feca | ||
|
|
a058e84ddb | ||
|
|
49ccf080ad | ||
|
|
176a9a89b6 | ||
|
|
40f907300d | ||
|
|
0219b14844 | ||
|
|
08acebd2c6 | ||
|
|
9bf0109c0d | ||
|
|
1f31ddd8d0 | ||
|
|
9540fb68dc | ||
|
|
432975f409 | ||
|
|
8b2acc764a | ||
|
|
f79ca38ef4 | ||
|
|
446cc973d6 | ||
|
|
a847d6a3eb | ||
|
|
67f9d9bbd9 | ||
|
|
2d49885572 | ||
|
|
a940674c6f | ||
|
|
7bbb073552 | ||
|
|
105d784b4a | ||
|
|
23eb0fef69 | ||
|
|
b9afb74a01 | ||
|
|
edfb68c946 | ||
|
|
66897e8e93 | ||
|
|
3b754b79e7 | ||
|
|
11fa834af7 | ||
|
|
d319c97430 | ||
|
|
744f9866da | ||
|
|
251746a57e | ||
|
|
b1bbfe7e1b | ||
|
|
7a911de8ca | ||
|
|
e5398cc1be | ||
|
|
b87f28f8bf | ||
|
|
5f8e16eb5d | ||
|
|
f83e1cc0b7 | ||
|
|
447bc94100 | ||
|
|
17cdb9c87b | ||
|
|
2cb35c17b2 | ||
|
|
0e0ca2a504 | ||
|
|
dca61fcd16 | ||
|
|
d0a198c6ad | ||
|
|
c1211123dd | ||
|
|
3a9d4ffa12 | ||
|
|
5855dc2abf | ||
|
|
ed3e6314d1 | ||
|
|
b83a36d41a | ||
|
|
1beaf3f436 | ||
|
|
0bb9145288 | ||
|
|
ba76a1f0fd | ||
|
|
f0732ae3c3 | ||
|
|
8a761382f0 | ||
|
|
481e3ba041 | ||
|
|
4615a174f0 | ||
|
|
18de5e9289 | ||
|
|
122c6d8b80 | ||
|
|
d00f93ee94 | ||
|
|
bbc2a8132a | ||
|
|
f4e61583fa | ||
|
|
9ee72b2c6b | ||
|
|
dd2c17e4ac | ||
|
|
e87dde9c6a | ||
|
|
83a5723dee | ||
|
|
3e6b968400 | ||
|
|
c3f9dffd50 | ||
|
|
972504202e | ||
|
|
d26b0bed38 | ||
|
|
e5b886ed21 | ||
|
|
d9e6082f1a | ||
|
|
67001e272b | ||
|
|
5534aa3fda | ||
|
|
55e73d3469 | ||
|
|
8a7b03676d | ||
|
|
0adafcb433 | ||
|
|
356eb98b94 | ||
|
|
86b5af9210 | ||
|
|
c4a5406330 | ||
|
|
857e6ff86b | ||
|
|
5bec30d2c7 | ||
|
|
c7a226999f | ||
|
|
1bea6d3f3e | ||
|
|
ffa70d5684 | ||
|
|
8de9ea9c1b | ||
|
|
f8c4393074 | ||
|
|
79cada7128 | ||
|
|
4c40edd00c | ||
|
|
20ab276cef | ||
|
|
689f2d3876 | ||
|
|
c403deb38d | ||
|
|
d90ecbb8d1 | ||
|
|
ae16a513ed | ||
|
|
7339a28d92 | ||
|
|
d544a633cc | ||
|
|
a6b78dca57 | ||
|
|
7dd78345f1 | ||
|
|
0a67c2a910 | ||
|
|
4e9475a6eb | ||
|
|
b5a6a8d027 | ||
|
|
1e1869718f | ||
|
|
ee69e29153 | ||
|
|
137ba631af | ||
|
|
aa972fa5b3 |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
ea0425fab4379ae5f7e9db05a22d4b7afd709560
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
3b92d8876dd59d5afc60a53bb23b103cede6a194
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,51 +0,0 @@
|
||||
package com.vk.core.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
public class VKLayoutInflater extends LayoutInflater {
|
||||
|
||||
private final static String[] DEFAULT_PACKAGES = {
|
||||
"android.widget.", "android.webkit.", "android.app."
|
||||
};
|
||||
|
||||
public VKLayoutInflater(LayoutInflater original, Context context) {
|
||||
super(original, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutInflater cloneInContext(Context newContext) {
|
||||
return new VKLayoutInflater(this, newContext);
|
||||
}
|
||||
|
||||
public final View createView(View parent, String name, Context context, AttributeSet attrs) {
|
||||
if (!name.startsWith("android.")) {
|
||||
try {
|
||||
return onCreateView(parent, name, attrs);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return createView(name, null, attrs);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
|
||||
for (var defPackage : DEFAULT_PACKAGES) {
|
||||
try {
|
||||
View view = createView(name, defPackage, attrs);
|
||||
if (view != null) return view;
|
||||
} catch (ClassCastException | ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateView(name, attrs);
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package com.vk.core.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.InflateException;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.OsUtil;
|
||||
import com.vk.core.view.NavigationSpinner;
|
||||
import com.vk.core.view.TextViewColorStateListAndAlphaSupportPreV23;
|
||||
import com.vk.core.view.VKAppBarLayout;
|
||||
|
||||
public class VKUILayoutFactory implements LayoutInflater.Factory2 {
|
||||
|
||||
private final static int[] FONT_ATTR = { android.R.attr.font };
|
||||
private AppCompatDelegate mDelegate;
|
||||
private VKLayoutInflater mInflater;
|
||||
|
||||
public VKUILayoutFactory(AppCompatDelegate delegate, VKLayoutInflater inflater) {
|
||||
mDelegate = delegate;
|
||||
mInflater = inflater;
|
||||
}
|
||||
|
||||
private void setTypeface(TextView textView, Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, FONT_ATTR, android.R.attr.textViewStyle, 0);
|
||||
if (ta == null) return;
|
||||
Font font = Font.Companion.a(ta.getString(0));
|
||||
if (font != null && Build.VERSION.SDK_INT < font.a())
|
||||
textView.setTypeface(font.c());
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
|
||||
View view = null;
|
||||
try {
|
||||
if (!(parent instanceof NavigationSpinner) && !OsUtil.b())
|
||||
view = new TextViewColorStateListAndAlphaSupportPreV23(context, attrs, 0);
|
||||
else if (mDelegate != null)
|
||||
view = mDelegate.createView(parent, name, context, attrs);
|
||||
else if (mInflater != null)
|
||||
view = mInflater.createView(parent, name, context, attrs);
|
||||
} catch (Throwable unused) {
|
||||
throw new InflateException(
|
||||
"parent=" + parent.getClass().getName()
|
||||
+ ":" + getResourceIdName(view)
|
||||
+ ", view=" + name
|
||||
+ ":" + getResourceIdName(context, attrs));
|
||||
}
|
||||
if (view == null &&
|
||||
("com.google.android.material.appbar.AppBarLayout".equals(name)
|
||||
|| "android.support.design.widget.AppBarLayout".equals(name)))
|
||||
view = new VKAppBarLayout(context, attrs);
|
||||
|
||||
if (view != null) {
|
||||
if (!(view.getTag() instanceof String)) {
|
||||
if (view instanceof TextView) {
|
||||
setTypeface((TextView) view, context, attrs);
|
||||
if (view instanceof CheckBox)
|
||||
VKThemeHelper.k.a((CheckBox) view);
|
||||
else if (view instanceof RadioButton)
|
||||
VKThemeHelper.k.a((RadioButton) view);
|
||||
else if (view instanceof SwitchCompat)
|
||||
VKThemeHelper.k.a((SwitchCompat) view);
|
||||
else if (view instanceof Switch)
|
||||
VKThemeHelper.k.a((Switch) view);
|
||||
} else if (view instanceof WebView) {
|
||||
VKThemeHelper.a((WebView) view);
|
||||
}
|
||||
VKThemeHelper.k.a(view, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private String getResourceIdName(View view) {
|
||||
try {
|
||||
if (view != null) {
|
||||
if (view.getId() != -1)
|
||||
return view.getResources().getResourceName(view.getId());
|
||||
return "NO_ID";
|
||||
}
|
||||
return "null";
|
||||
} catch (Throwable unused) {
|
||||
return "FAILED_TO_GET_ID";
|
||||
}
|
||||
}
|
||||
|
||||
private String getResourceIdName(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.id });
|
||||
int resId = ta.getResourceId(0, -1);
|
||||
ta.recycle();
|
||||
return resId != -1
|
||||
? context.getResources().getResourceName(resId)
|
||||
: "NO_ID";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
|
||||
return onCreateView(null, name, context, attrs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.vk.core.util;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.getDownloadsDir;
|
||||
import static ru.vtosters.lite.utils.Preferences.getMusicDir;
|
||||
import static ru.vtosters.lite.utils.Preferences.getPhotosDir;
|
||||
import static ru.vtosters.lite.utils.Preferences.getVideosDir;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.common.i.MediaUtils;
|
||||
import com.facebook.x.g.EncodedImage;
|
||||
import com.vk.core.concurrent.VkExecutors;
|
||||
import com.vk.imageloader.VKImageLoader;
|
||||
import com.vk.log.L;
|
||||
import com.vk.metrics.eventtracking.VkTracker;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
|
||||
import b.h.g.m.CameraUtils;
|
||||
import b.h.g.m.FileUtils;
|
||||
|
||||
public class DownloadUtils {
|
||||
public static final HashSet<Long> a = new HashSet<>();
|
||||
|
||||
public static void a(Context context, String str, String str2) {
|
||||
a(context, str, str2, false);
|
||||
}
|
||||
|
||||
public static void b(Context context, String str, String str2) {
|
||||
a(context, str, str2, true);
|
||||
}
|
||||
|
||||
private static void a(Context context, String str, String str2, boolean z) {
|
||||
try {
|
||||
b(context, str, str2, z);
|
||||
} catch (Exception e2) {
|
||||
L.d(e2);
|
||||
ToastUtils.a(context.getString(R.string.error) + " [" + e2.getMessage() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private static void b(final Context context, String str, String str2, boolean z) {
|
||||
if (TextUtils.isEmpty(str2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String file = a(str, str2);
|
||||
File b2;
|
||||
boolean c2 = MediaUtils.c(MediaUtils.b(str2));
|
||||
|
||||
if (str.endsWith("png") || str.endsWith("jpg") || str.endsWith("jpeg")) {
|
||||
b2 = new File(getPhotosDir(), file);
|
||||
} else if (str.endsWith("mp3") || str.endsWith("wav") || str.endsWith("ogg") || str.endsWith("aac") || str.endsWith("flac") || str.endsWith("m4a")) {
|
||||
b2 = new File(getMusicDir(), file);
|
||||
} else if (str.endsWith("mp4") || str.endsWith("mkv") || str.endsWith("avi") || str.endsWith("flv") || str.endsWith("wmv") || str.endsWith("mov") || str.endsWith("3gp")) {
|
||||
b2 = new File(getVideosDir(), file);
|
||||
} else {
|
||||
b2 = new File(getDownloadsDir(), file);
|
||||
}
|
||||
|
||||
if (c2) {
|
||||
EncodedImage c3 = VKImageLoader.c(Uri.parse(str2));
|
||||
final InputStream h = c3 == null ? null : c3.h();
|
||||
if (h != null) {
|
||||
try {
|
||||
if (b2.exists() || FileUtils.b(b2)) {
|
||||
VkExecutors.x.a().execute(() -> ToastUtils.a(context.getString(R.string.file_saved, b2.getAbsoluteFile())));
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
L.a(e2);
|
||||
}
|
||||
CameraUtils.a(context, b2, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(str2));
|
||||
request.setDestinationUri(Uri.fromFile(b2));
|
||||
request.setMimeType(FileUtils.f(new File(str)));
|
||||
request.setNotificationVisibility(1);
|
||||
request.allowScanningByMediaScanner();
|
||||
request.setTitle(str);
|
||||
DownloadManager a2 = a(context);
|
||||
if (a2 == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
long enqueue = a2.enqueue(request);
|
||||
if (!z) {
|
||||
return;
|
||||
}
|
||||
a.add(enqueue);
|
||||
} catch (IllegalArgumentException e3) {
|
||||
L.a(e3);
|
||||
b(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static String a(String str, String str2) {
|
||||
String lastPathSegment = Uri.parse(str2).getLastPathSegment();
|
||||
if (!TextUtils.isEmpty(str)) {
|
||||
String replace = str.replace('/', '_');
|
||||
return !replace.contains(".") ? lastPathSegment : replace;
|
||||
}
|
||||
return lastPathSegment;
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("Range")
|
||||
public static boolean a(Context context, Uri uri) {
|
||||
try {
|
||||
Cursor query = a(context).query(new DownloadManager.Query().setFilterByStatus(11));
|
||||
if (query != null && query.moveToFirst()) {
|
||||
while (!uri.toString().equals(query.getString(query.getColumnIndex("uri")))) {
|
||||
if (!query.moveToNext()) {
|
||||
query.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@SuppressLint("Range")
|
||||
int i = query.getInt(query.getColumnIndex("status"));
|
||||
@SuppressLint("Range")
|
||||
String string = query.getString(query.getColumnIndex("local_uri"));
|
||||
query.close();
|
||||
if (i == 1 || i == 2) {
|
||||
ToastUtils.a(R.string.download_is_in_progress);
|
||||
query.close();
|
||||
return true;
|
||||
} else if (i != 8) {
|
||||
query.close();
|
||||
return false;
|
||||
} else {
|
||||
boolean a2 = a(context, string);
|
||||
query.close();
|
||||
return a2;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (SQLiteException e2) {
|
||||
VkTracker.k.b(e2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void b(Context context) {
|
||||
if (context != null) {
|
||||
try {
|
||||
context.startActivity(new Intent("android.settings.APPLICATION_DETAILS_SETTINGS").setData(Uri.parse("package:com.android.providers.downloads")));
|
||||
} catch (ActivityNotFoundException e2) {
|
||||
L.a(e2);
|
||||
context.startActivity(new Intent("android.settings.MANAGE_APPLICATIONS_SETTINGS"));
|
||||
}
|
||||
ToastUtils.a("Please enable download manager", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean a(Context context, String str) {
|
||||
File file;
|
||||
try {
|
||||
try {
|
||||
file = new File(new URI(str));
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
Intent intent = new Intent("android.intent.action.VIEW");
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
String f2 = FileUtils.f(file);
|
||||
if (!TextUtils.isEmpty(f2)) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setDataAndType(FileUtils.n(file), f2);
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
throw new ActivityNotFoundException();
|
||||
} catch (ActivityNotFoundException unused) {
|
||||
return a(context, file);
|
||||
}
|
||||
} catch (ActivityNotFoundException unused2) {
|
||||
unused2.printStackTrace();
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
VkTracker.k.b(th);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean a(Context context, File file) {
|
||||
if (file != null && file.exists()) {
|
||||
Intent intent = new Intent("android.intent.action.VIEW");
|
||||
intent.setDataAndType(Uri.parse(file.getAbsolutePath()), "application/*");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
} catch (ActivityNotFoundException e2) {
|
||||
L.a(e2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static DownloadManager a(Context context) {
|
||||
return (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.vk.im.ui.views;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class Corners{
|
||||
private int topLeft;
|
||||
private int topRight;
|
||||
private int bottomLeft;
|
||||
private int bottomRight;
|
||||
|
||||
public Corners(int i, int i2, int i3, int i4){
|
||||
this.topLeft = i;
|
||||
this.topRight = i2;
|
||||
this.bottomLeft = i3;
|
||||
this.bottomRight = i4;
|
||||
}
|
||||
|
||||
public Corners(int i, int i2, int i3, int i4, int i5) {
|
||||
this((i5 & 1) != 0 ? 0 : i, (i5 & 2) != 0 ? 0 : i2, (i5 & 4) != 0 ? 0 : i3, (i5 & 8) != 0 ? 0 : i4);
|
||||
}
|
||||
|
||||
public Corners() {
|
||||
this(0, 0, 0, 0, 15);
|
||||
}
|
||||
|
||||
public static Corners a(Corners corners, int i, int i2, int i3, int i4, int i5, Object obj){
|
||||
if ((i5 & 1) != 0) {
|
||||
i = corners.topLeft;
|
||||
}
|
||||
if ((i5 & 2) != 0) {
|
||||
i2 = corners.topRight;
|
||||
}
|
||||
if ((i5 & 4) != 0) {
|
||||
i3 = corners.bottomLeft;
|
||||
}
|
||||
if ((i5 & 8) != 0) {
|
||||
i4 = corners.bottomRight;
|
||||
}
|
||||
corners.a(i, i2, i3, i4);
|
||||
return corners;
|
||||
}
|
||||
|
||||
public int a(){
|
||||
return this.bottomLeft;
|
||||
}
|
||||
|
||||
public int b(){
|
||||
return this.bottomRight;
|
||||
}
|
||||
|
||||
public int c(){
|
||||
return this.topLeft;
|
||||
}
|
||||
|
||||
public int d(){
|
||||
return this.topRight;
|
||||
}
|
||||
|
||||
public boolean e(){
|
||||
int i;
|
||||
int i2 = this.topLeft;
|
||||
int i3 = this.topRight;
|
||||
return i2 == i3 && i3 == (i = this.bottomRight) && this.bottomLeft == i;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj){
|
||||
if (this != obj) {
|
||||
if (!(obj instanceof Corners)) {
|
||||
return false;
|
||||
}
|
||||
Corners corners = (Corners) obj;
|
||||
return this.topLeft == corners.topLeft && this.topRight == corners.topRight && this.bottomLeft == corners.bottomLeft && this.bottomRight == corners.bottomRight;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean f(){
|
||||
return this.topLeft == 0 && e();
|
||||
}
|
||||
|
||||
public void g(){
|
||||
a(0, 0);
|
||||
}
|
||||
|
||||
public int hashCode(){
|
||||
return (((((this.topLeft * 31) + this.topRight) * 31) + this.bottomLeft) * 31) + this.bottomRight;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String toString(){
|
||||
return "Corners(topLeft=" + this.topLeft + ", topRight=" + this.topRight + ", bottomLeft=" + this.bottomLeft + ", bottomRight=" + this.bottomRight + ")";
|
||||
}
|
||||
|
||||
public Corners a(int i, int i2){
|
||||
if ((i2 & 1) > 0) {
|
||||
this.topLeft = i;
|
||||
}
|
||||
if ((i2 & 2) > 0) {
|
||||
this.topRight = i;
|
||||
}
|
||||
if ((i2 & 4) > 0) {
|
||||
this.bottomLeft = i;
|
||||
}
|
||||
if ((i2 & 8) > 0) {
|
||||
this.bottomRight = i;
|
||||
}
|
||||
if (i2 == 0) {
|
||||
this.topLeft = 0;
|
||||
this.topRight = 0;
|
||||
this.bottomLeft = 0;
|
||||
this.bottomRight = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Corners a(int i, int i2, int i3, int i4){
|
||||
this.topLeft = i;
|
||||
this.topRight = i2;
|
||||
this.bottomLeft = i3;
|
||||
this.bottomRight = i4;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Corners a(Corners corners){
|
||||
this.topLeft = corners.topLeft;
|
||||
this.topRight = corners.topRight;
|
||||
this.bottomLeft = corners.bottomLeft;
|
||||
this.bottomRight = corners.bottomRight;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.vk.im.ui.views.avatars;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.vk.im.ui.o;
|
||||
|
||||
public class StoryBorderView extends View {
|
||||
private boolean B;
|
||||
private final Paint a;
|
||||
private LinearGradient f15747b;
|
||||
private int f15748c;
|
||||
private int f15749d;
|
||||
private int f15750e;
|
||||
private int f15751f;
|
||||
private final int g;
|
||||
private final int h;
|
||||
|
||||
public StoryBorderView(Context context) {
|
||||
this(context, null, 0, 6);
|
||||
}
|
||||
|
||||
public StoryBorderView(Context context, AttributeSet attributeSet) {
|
||||
this(context, attributeSet, 0, 4);
|
||||
}
|
||||
|
||||
public StoryBorderView(Context context, AttributeSet attributeSet, int i, int i2) {
|
||||
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
|
||||
}
|
||||
|
||||
public int getBorderColor() {
|
||||
return this.f15749d;
|
||||
}
|
||||
|
||||
public int getBorderGradientEndColor() {
|
||||
return this.h;
|
||||
}
|
||||
|
||||
public int getBorderGradientStartColor() {
|
||||
return this.g;
|
||||
}
|
||||
|
||||
public int getBorderWidth() {
|
||||
return this.f15750e;
|
||||
}
|
||||
|
||||
public int getPadding() {
|
||||
return this.f15751f;
|
||||
}
|
||||
|
||||
public int getViewSize() {
|
||||
return this.f15748c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
canvas.drawOval(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(), this.a);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int i, int i2) {
|
||||
int i3 = this.f15748c;
|
||||
setMeasuredDimension(i3, i3);
|
||||
}
|
||||
|
||||
public void setBorderColor(int i) {
|
||||
if (this.f15749d != i) {
|
||||
this.f15749d = i;
|
||||
this.a.setColor(i);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setBorderWidth(int i) {
|
||||
if (this.f15750e != i) {
|
||||
this.f15750e = i;
|
||||
this.a.setStrokeWidth(i);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutParams(ViewGroup.LayoutParams layoutParams) {
|
||||
super.setLayoutParams(layoutParams);
|
||||
boolean z = false;
|
||||
this.f15748c = Math.min(layoutParams != null ? layoutParams.width : 0, layoutParams != null ? layoutParams.height : 0);
|
||||
this.f15747b = new LinearGradient(0.0f, 0.0f, 0.0f, this.f15748c, this.g, this.h, Shader.TileMode.MIRROR);
|
||||
if (this.f15748c > 0) {
|
||||
z = true;
|
||||
}
|
||||
if (z) {
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("Only exact size supported, specify avatar sizes in layout params");
|
||||
}
|
||||
|
||||
public void setLive(boolean z) {
|
||||
if (this.B != z) {
|
||||
this.a.setShader(z ? this.f15747b : null);
|
||||
this.a.setColor(z ? -1 : this.f15749d);
|
||||
this.B = z;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPadding(int i) {
|
||||
if (this.f15751f != i) {
|
||||
this.f15751f = i;
|
||||
setPadding(i, i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewSize(int i) {
|
||||
this.f15748c = i;
|
||||
}
|
||||
|
||||
public StoryBorderView(Context context, AttributeSet attributeSet, int i) {
|
||||
super(context, attributeSet, i);
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
this.a = paint;
|
||||
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, o.StoryBorderView);
|
||||
setBorderColor(obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderColor, 0));
|
||||
this.g = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientStartColor, 0);
|
||||
this.h = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientEndColor, 0);
|
||||
setBorderWidth(obtainStyledAttributes.getDimensionPixelSize(o.StoryBorderView_vkim_borderWidth, 0));
|
||||
obtainStyledAttributes.recycle();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
||||
package com.vk.sharing.view;
|
||||
|
||||
import static b.h.z.f.roboto_medium;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.view.DraweeHolder;
|
||||
import com.vk.core.util.ContextExtKt;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.im.ui.views.avatars.AbbreviationAvatarDrawable;
|
||||
import com.vk.imageloader.view.VKMultiImageView;
|
||||
import com.vk.navigation.NavigatorKeys;
|
||||
import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.a0;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
@UiThread
|
||||
public class TargetImageView extends VKMultiImageView {
|
||||
private static final int I = Screen.a(2);
|
||||
private final int B;
|
||||
private final int C;
|
||||
private Drawable D;
|
||||
private String[] F;
|
||||
private int G;
|
||||
private final RectF f21629d;
|
||||
private final Paint f21630e;
|
||||
private Canvas f21631f;
|
||||
private final RectF g;
|
||||
private final Paint h;
|
||||
|
||||
public TargetImageView(Context context, Drawable d) {
|
||||
this(context, null, 0, 6);
|
||||
}
|
||||
|
||||
public TargetImageView(Context context, AttributeSet attributeSet) {
|
||||
this(context, attributeSet, 0, 4);
|
||||
}
|
||||
|
||||
public TargetImageView(Context context, AttributeSet attributeSet, int i, int i2) {
|
||||
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
|
||||
}
|
||||
|
||||
private void e() {
|
||||
int i = this.G;
|
||||
for (int i2 = 0; i2 < i; i2++) {
|
||||
a(i2, this.F[i2]);
|
||||
}
|
||||
}
|
||||
|
||||
private void f() {
|
||||
int paddingLeft = getPaddingLeft();
|
||||
int paddingTop = getPaddingTop();
|
||||
int width = (getWidth() - paddingLeft) - getPaddingRight();
|
||||
int height = (getHeight() - paddingTop) - getPaddingBottom();
|
||||
int i = width / 2;
|
||||
int i2 = height / 2;
|
||||
int i3 = this.G;
|
||||
if (i3 == 1) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a2 = this.a.a(0);
|
||||
Drawable d2 = a2.d();
|
||||
if (d2 != null) {
|
||||
d2.setBounds(paddingLeft, paddingTop, width + paddingLeft, height + paddingTop);
|
||||
}
|
||||
} else if (i3 == 2) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a3 = this.a.a(0);
|
||||
Drawable d3 = a3.d();
|
||||
if (d3 != null) {
|
||||
int i4 = i + paddingLeft;
|
||||
int i5 = height + paddingTop;
|
||||
d3.setBounds(paddingLeft, paddingTop, i4, i5);
|
||||
DraweeHolder<GenericDraweeHierarchy> a4 = this.a.a(1);
|
||||
Drawable d4 = a4.d();
|
||||
if (d4 != null) {
|
||||
d4.setBounds(i4, paddingTop, paddingLeft + width, i5);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (i3 == 3) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a5 = this.a.a(0);
|
||||
Drawable d5 = a5.d();
|
||||
if (d5 != null) {
|
||||
int i6 = i + paddingLeft;
|
||||
int i7 = height + paddingTop;
|
||||
d5.setBounds(paddingLeft, paddingTop, i6, i7);
|
||||
DraweeHolder<GenericDraweeHierarchy> a6 = this.a.a(1);
|
||||
Drawable d6 = a6.d();
|
||||
if (d6 != null) {
|
||||
int i9 = paddingLeft + width;
|
||||
int i10 = i2 + paddingTop;
|
||||
d6.setBounds(i6, paddingTop, i9, i10);
|
||||
DraweeHolder<GenericDraweeHierarchy> a7 = this.a.a(2);
|
||||
Drawable d7 = a7.d();
|
||||
if (d7 != null) {
|
||||
d7.setBounds(i6, i10, i9, i7);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
DraweeHolder<GenericDraweeHierarchy> a8 = this.a.a(0);
|
||||
Drawable d8 = a8.d();
|
||||
if (d8 != null) {
|
||||
int i11 = i + paddingLeft;
|
||||
int i13 = i2 + paddingTop;
|
||||
d8.setBounds(paddingLeft, paddingTop, i11, i13);
|
||||
DraweeHolder<GenericDraweeHierarchy> a9 = this.a.a(1);
|
||||
Drawable d9 = a9.d();
|
||||
if (d9 != null) {
|
||||
int i16 = height + paddingTop;
|
||||
d9.setBounds(paddingLeft, i13, i11, i16);
|
||||
DraweeHolder<GenericDraweeHierarchy> a10 = this.a.a(2);
|
||||
Drawable d10 = a10.d();
|
||||
if (d10 != null) {
|
||||
int i18 = paddingLeft + width;
|
||||
d10.setBounds(i11, paddingTop, i18, i13);
|
||||
DraweeHolder<GenericDraweeHierarchy> a11 = this.a.a(3);
|
||||
Drawable d11 = a11.d();
|
||||
if (d11 != null) {
|
||||
d11.setBounds(i11, i13, i18, i16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void g() {
|
||||
if (getWidth() == 0 || getHeight() == 0) {
|
||||
return;
|
||||
}
|
||||
f();
|
||||
}
|
||||
|
||||
private AbbreviationAvatarDrawable getAbbreviationDrawable() {
|
||||
return a(getContext(), null, 2);
|
||||
}
|
||||
|
||||
private AbbreviationAvatarDrawable a(Context context, Typeface typeface, int i) {
|
||||
return new AbbreviationAvatarDrawable(context, (i & 2) != 0 ? ContextExtKt.e(context, roboto_medium) : typeface);
|
||||
}
|
||||
|
||||
public void a(String str) {
|
||||
Arrays.fill(this.F, null);
|
||||
if (str == null) {
|
||||
b();
|
||||
this.G = 1;
|
||||
g();
|
||||
e();
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(str);
|
||||
if (uri.getScheme().equals("vkchatphoto")) {
|
||||
this.G = 0;
|
||||
while (true) {
|
||||
String queryParameter = uri.getQueryParameter("photo" + this.G);
|
||||
if (queryParameter != null) {
|
||||
int i = this.G;
|
||||
this.G = i + 1;
|
||||
this.F[i] = queryParameter;
|
||||
} else {
|
||||
g();
|
||||
e();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (uri.getScheme().equals("vkchatplaceholder")) {
|
||||
this.G = 1;
|
||||
g();
|
||||
AbbreviationAvatarDrawable abbreviationDrawable = getAbbreviationDrawable();
|
||||
String queryParameter2 = uri.getQueryParameter(NavigatorKeys.Q);
|
||||
int parseInt = queryParameter2 != null ? Integer.parseInt(queryParameter2) : 0;
|
||||
String queryParameter3 = uri.getQueryParameter(NavigatorKeys.d);
|
||||
if (queryParameter3 == null) {
|
||||
queryParameter3 = "";
|
||||
}
|
||||
abbreviationDrawable.a(parseInt, queryParameter3);
|
||||
a(0, getAbbreviationDrawable());
|
||||
} else {
|
||||
this.F[0] = str;
|
||||
this.G = 1;
|
||||
g();
|
||||
e();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // android.view.View
|
||||
protected void onDraw(Canvas canvas) {
|
||||
Canvas canvas2 = this.f21631f;
|
||||
int pref = preferences.getInt("pic_rounding", 0);
|
||||
|
||||
if (canvas2 != null) {
|
||||
canvas2.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
}
|
||||
int i = this.G;
|
||||
for (int i2 = 0; i2 < i; i2++) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a2 = this.a.a(i2);
|
||||
Drawable d2 = a2.d();
|
||||
if (d2 != null) {
|
||||
Canvas canvas3 = this.f21631f;
|
||||
d2.draw(canvas3);
|
||||
}
|
||||
}
|
||||
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(this.f21629d, pref, pref, this.f21630e);
|
||||
} else {
|
||||
canvas.drawOval(this.f21629d, this.f21630e);
|
||||
}
|
||||
|
||||
if (isSelected()) {
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(this.g.left, this.g.top, this.g.right, this.g.bottom, pref, pref, this.h);
|
||||
} else {
|
||||
canvas.drawCircle(this.g.centerX(), this.g.centerY(), this.g.width() / 2, this.h);
|
||||
}
|
||||
|
||||
this.D.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // android.view.View
|
||||
protected void onSizeChanged(int i, int i2, int i3, int i4) {
|
||||
super.onSizeChanged(i, i2, i3, i4);
|
||||
int paddingLeft = getPaddingLeft();
|
||||
int paddingRight = getPaddingRight();
|
||||
int paddingTop = getPaddingTop();
|
||||
int i5 = i - paddingRight;
|
||||
int paddingBottom = i2 - getPaddingBottom();
|
||||
this.f21629d.set(paddingLeft, paddingTop, i5, paddingBottom);
|
||||
Bitmap createBitmap = Bitmap.createBitmap(i5, paddingBottom, Bitmap.Config.ARGB_8888);
|
||||
this.f21631f = new Canvas(createBitmap);
|
||||
Shader.TileMode tileMode = Shader.TileMode.CLAMP;
|
||||
this.f21630e.setShader(new BitmapShader(createBitmap, tileMode, tileMode));
|
||||
float f2 = I / 2;
|
||||
this.g.set(f2, f2, i - f2, (float) i2 - f2);
|
||||
float f4 = i / 2;
|
||||
this.h.setShader(new LinearGradient(f4, 0.0f, f4, (float) i2, this.B, this.C, Shader.TileMode.CLAMP));
|
||||
Drawable drawable = this.D;
|
||||
drawable.setBounds(i - drawable.getIntrinsicWidth(), i2 - this.D.getIntrinsicHeight(), i, i2);
|
||||
f();
|
||||
}
|
||||
|
||||
public TargetImageView(Context context, AttributeSet attributeSet, int i) {
|
||||
super(context, attributeSet, i);
|
||||
this.f21629d = new RectF();
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setDither(true);
|
||||
paint.setFilterBitmap(true);
|
||||
this.f21630e = paint;
|
||||
this.g = new RectF();
|
||||
Paint paint2 = new Paint();
|
||||
paint2.setAntiAlias(true);
|
||||
paint2.setStrokeWidth(I);
|
||||
paint2.setStyle(Paint.Style.STROKE);
|
||||
this.h = paint2;
|
||||
this.B = getAccentColor();
|
||||
this.C = this.B;
|
||||
Drawable c2 = ContextExtKt.c(context, R.drawable.ic_check_circle_composite_24_full);
|
||||
if (c2 != null) {
|
||||
this.D = c2;
|
||||
this.F = new String[4];
|
||||
int i2 = I * 2;
|
||||
setPadding(i2, i2, i2, i2);
|
||||
if (attributeSet != null) {
|
||||
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, a0.TargetImageView);
|
||||
setSelected(obtainStyledAttributes.getBoolean(0, false));
|
||||
obtainStyledAttributes.recycle();
|
||||
}
|
||||
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.user_placeholder);
|
||||
for (int i3 = 0; i3 <= 3; i3++) {
|
||||
a();
|
||||
DraweeHolder<GenericDraweeHierarchy> a3 = this.a.a(i3);
|
||||
a3.b().e(drawable);
|
||||
}
|
||||
setScaleType(ScalingUtils.b.o);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,8 +55,8 @@ public class DNRInjector {
|
||||
hashMap.put(DialogAction.valueOf("DNT_OFF"), getIdentifier("DNT_OFF", "string"));
|
||||
|
||||
|
||||
hashMap.put(DialogAction.valueOf("pinmsg"), getIdentifier("pinmsg", "string"));
|
||||
hashMap.put(DialogAction.valueOf("unpinmsg"), getIdentifier("unpinmsg", "string"));
|
||||
// hashMap.put(DialogAction.valueOf("pinmsg"), getIdentifier("pinmsg", "string"));
|
||||
// hashMap.put(DialogAction.valueOf("unpinmsg"), getIdentifier("unpinmsg", "string"));
|
||||
return hashMap;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,16 @@ public class AudioDownloader {
|
||||
}
|
||||
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
|
||||
var musicDir = new File(musicPath);
|
||||
if (!musicDir.exists()) {
|
||||
if (musicDir.mkdirs()) {
|
||||
Log.d("AudioDownloader", "Created music dir");
|
||||
} else {
|
||||
Log.e("AudioDownloader", "Failed to create music dir");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var tempId = track.d;
|
||||
var downloadPath = musicPath + File.separator + tempId;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package ru.vtosters.lite.downloaders;
|
||||
|
||||
import static ru.vtosters.lite.downloaders.VideoDownloader.downloadVideo;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.getPhotosDir;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Context;
|
||||
@@ -23,7 +24,7 @@ public class StoryDownloader {
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle("photo" + story.E.a);
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DCIM, "/Stories/photo" + story.E.a + ".jpg");
|
||||
request.setDestinationInExternalPublicDir(getPhotosDir().getAbsolutePath(), "/Stories/photo" + story.E.a + ".jpg");
|
||||
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
import static ru.vtosters.lite.utils.Preferences.getVideosDir;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DownloadManager;
|
||||
@@ -104,7 +105,7 @@ public class VideoDownloader {
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle(videoFile.toString());
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, videoFile + ".mp4");
|
||||
request.setDestinationInExternalPublicDir(getVideosDir().getAbsolutePath(), videoFile + ".mp4");
|
||||
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
return;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ public class VideoDownloader {
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle(videoFile.toString());
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, videoFile + ".mp4");
|
||||
request.setDestinationInExternalPublicDir(getVideosDir().getAbsolutePath(), videoFile + ".mp4");
|
||||
((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
}));
|
||||
builder.show();
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import com.vk.extensions.ViewExtKt;
|
||||
import com.vk.navigation.right.RightMenuPresenter;
|
||||
|
||||
import ru.vtosters.lite.ui.views.VTLCheckableButton;
|
||||
|
||||
public class DayNightButtonHook {
|
||||
|
||||
public static void injectOnClick(VTLCheckableButton button, RightMenuPresenter presenter) {
|
||||
button.postOnAnimationDelayed(() -> {
|
||||
var rect = ViewExtKt.e(button);
|
||||
presenter.a(new float[] { rect.centerX(), rect.centerY() });
|
||||
}, 550); // minimal delay for fix toggle animation
|
||||
button.toggle();
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,6 @@ import java.util.Map;
|
||||
|
||||
import ru.vtosters.lite.ui.components.DockBarEditorManager;
|
||||
import ru.vtosters.lite.ui.items.DockBarTab;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class DockBarInjector {
|
||||
private static final DockBarEditorManager sManager = DockBarEditorManager.getInstance();
|
||||
@@ -68,7 +67,6 @@ public class DockBarInjector {
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
public static void inject(BottomNavigationView navigationView) {
|
||||
navigationView.setBackgroundColor(ThemesUtils.getBackgroundContent());
|
||||
Menu menu = navigationView.getMenu();
|
||||
menu.clear();
|
||||
try {
|
||||
@@ -88,11 +86,14 @@ public class DockBarInjector {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (DockBarTab tab : sManager.getSelectedTabs())
|
||||
menu.add(0, tab.id, 0, tab.titleID)
|
||||
.setIcon(tab.iconID)
|
||||
.setCheckable(true);
|
||||
for (DockBarTab tab : sManager.getSelectedTabs()) {
|
||||
MenuItem add = menu.add(0, tab.id, 0, tab.titleID);
|
||||
Drawable drawable = getResources().getDrawable(tab.iconID);
|
||||
|
||||
add.setIcon(new RecoloredDrawable(drawable, getCSTDock()));
|
||||
add.setTitle(getGlobalContext().getString(tab.titleID));
|
||||
add.setCheckable(true);
|
||||
}
|
||||
if (getBoolValue("dockbar_tab_titles", true)) {
|
||||
var menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);
|
||||
for (int i = 0; i < menuView.getChildCount(); i++) {
|
||||
|
||||
@@ -17,14 +17,10 @@ import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.hasVerification;
|
||||
import static ru.vtosters.lite.utils.Preferences.podcastcatalog;
|
||||
import static ru.vtosters.lite.utils.Preferences.postsrecomm;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.accentColors;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.hex2;
|
||||
import static ru.vtosters.lite.utils.VTVerifications.isDeveloper;
|
||||
import static ru.vtosters.lite.utils.VTVerifications.isPrometheus;
|
||||
import static ru.vtosters.lite.utils.VTVerifications.isVerified;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vk.core.network.Network;
|
||||
@@ -37,7 +33,6 @@ import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -68,17 +63,6 @@ public class JsonInjectors {
|
||||
newItem.put(vktesters(id));
|
||||
}
|
||||
|
||||
// get text color from all items
|
||||
for (int i = 0; i < newItem.length(); i++) {
|
||||
var item = newItem.getJSONObject(i);
|
||||
if (item.has("text_color")) {
|
||||
var textColor = item.getString("text_color");
|
||||
if (accentColors.contains(Color.parseColor(textColor.startsWith("#") ? textColor : "#" + textColor))) {
|
||||
item.put("text_color", hex2(getAccentColor()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orig.put("buttons", newItem);
|
||||
|
||||
return orig;
|
||||
@@ -543,7 +527,7 @@ public class JsonInjectors {
|
||||
|
||||
Log.d("VKMusic", "title: " + title + " id: " + id + " url: " + url + " value: " + value);
|
||||
|
||||
if (url.contains(value)) {
|
||||
if (url.contains(value) && !value.isEmpty()) {
|
||||
catalog.put("default_section", id);
|
||||
if (dev()) Log.d("VKMusic", "Added " + title + " as default music section");
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.ui.dialogs.ServerDialog.sendRequest;
|
||||
import static ru.vtosters.lite.utils.CacheUtils.getInstance;
|
||||
import static ru.vtosters.lite.utils.DeletedMessagesHandler.reloadMessagesList;
|
||||
import static ru.vtosters.lite.utils.Preferences.checkupdates;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.isDarkTheme;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.setNeededTheme;
|
||||
@@ -18,11 +19,13 @@ import ru.vtosters.lite.ui.dialogs.ServerDialog;
|
||||
import ru.vtosters.lite.ui.dialogs.Start;
|
||||
|
||||
public class MainActivityInjector {
|
||||
|
||||
public static void inject(Activity activity) {
|
||||
setNeededTheme(activity);
|
||||
ServerDialog.activity = activity;
|
||||
sendRequest();
|
||||
if (checkupdates()) OTADialog.checkUpdates(activity);
|
||||
reloadMessagesList();
|
||||
Start.alert(activity);
|
||||
InstallGMS.alert(activity);
|
||||
DisableBattery.alert(activity);
|
||||
@@ -34,6 +37,7 @@ public class MainActivityInjector {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannels.createChannels();
|
||||
}
|
||||
|
||||
// VKIDProtection.alert(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isMusicBlock;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isNewsBlock;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isPostRecommendations;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isRecomsGroup;
|
||||
import static ru.vtosters.lite.utils.Preferences.ads;
|
||||
import static ru.vtosters.lite.utils.Preferences.adsslider;
|
||||
import static ru.vtosters.lite.utils.Preferences.authorsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.friendsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
|
||||
@@ -23,6 +27,7 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class NewsfeedHook {
|
||||
@@ -73,4 +78,42 @@ public class NewsfeedHook {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static String[] feedParams(){
|
||||
HashSet<String> params = new HashSet<>();
|
||||
params.add("post");
|
||||
params.add("photo");
|
||||
params.add("photo_tag");
|
||||
|
||||
if (!friendsrecomm()) {
|
||||
params.add("friends_recomm");
|
||||
}
|
||||
|
||||
if (!ads()) {
|
||||
params.add("app_widget");
|
||||
params.add("promo_button");
|
||||
}
|
||||
|
||||
if (!authorsrecomm()) {
|
||||
params.add("authors_rec");
|
||||
}
|
||||
|
||||
return params.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static void adsParams(HashSet hashSet) {
|
||||
if (ads() || adsslider()) {
|
||||
hashSet.add("ads_disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
hashSet.add("ads_app");
|
||||
hashSet.add("ads_site");
|
||||
hashSet.add("ads_post");
|
||||
hashSet.add("ads_app_slider");
|
||||
hashSet.add("ads_site_slider");
|
||||
hashSet.add("ads_app_video");
|
||||
hashSet.add("ads_post_pretty_cards");
|
||||
hashSet.add("ads_post_snippet_video");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class PicRoundingHook{
|
||||
private static final int pref = preferences.getInt("pic_rounding", 0);
|
||||
|
||||
public static RoundingParams inject() {
|
||||
if (pref > 0) {
|
||||
return customParams();
|
||||
} else {
|
||||
return new RoundingParams().a(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static RoundingParams inject(float orig) {
|
||||
if (pref > 0) {
|
||||
return customParams();
|
||||
} else {
|
||||
return new RoundingParams().b(orig);
|
||||
}
|
||||
}
|
||||
|
||||
public static RoundingParams inject(float orig, float orig2, float orig3, float orig4) {
|
||||
if (pref > 0) {
|
||||
return new RoundingParams().a(AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref));
|
||||
} else {
|
||||
return new RoundingParams().a(orig, orig2, orig3, orig4);
|
||||
}
|
||||
}
|
||||
|
||||
public static void inject(float orig, Canvas canvas, Paint paint){
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), paint);
|
||||
} else {
|
||||
canvas.drawCircle(orig, orig, orig, paint);
|
||||
}
|
||||
}
|
||||
|
||||
public static void inject(Bitmap bitmap, Bitmap bitmap2, Paint b2) {
|
||||
Shader.TileMode tileMode = Shader.TileMode.CLAMP;
|
||||
b2.setShader(new BitmapShader(bitmap2, tileMode, tileMode));
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
float width = bitmap2.getWidth() / 2;
|
||||
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), b2);
|
||||
} else {
|
||||
canvas.drawCircle(width, width, width, b2);
|
||||
}
|
||||
}
|
||||
|
||||
private static RoundingParams customParams(){
|
||||
return RoundingParams.b(AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref));
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import java.util.LinkedHashMap;
|
||||
|
||||
public class RequestDumper{
|
||||
public static void addParams(MethodCall.a paramslist, String method, LinkedHashMap params, String apiver) {
|
||||
if (method.contains("execute.getGiftByStickerId")) {
|
||||
if (method.contains("execute.getGiftByStickerId") || method.contains("execute.getNewsfeedCustom")) {
|
||||
apiver = "5.187";
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.milkshake;
|
||||
import static ru.vtosters.lite.utils.Preferences.superapp;
|
||||
import static ru.vtosters.lite.utils.Preferences.useNewSettings;
|
||||
import static ru.vtosters.lite.utils.Preferences.videonewcatalog;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
|
||||
@@ -33,8 +34,6 @@ import com.vtosters.lite.fragments.y2.VideosFragment;
|
||||
import com.vtosters.lite.general.fragments.GamesFragment;
|
||||
import com.vtosters.lite.general.fragments.PhotosFragment;
|
||||
|
||||
import ru.vtosters.lite.ui.fragments.VTSettings;
|
||||
|
||||
public class StartFragmentHook {
|
||||
public static Class getStartFragment() {
|
||||
if (vkme()) {
|
||||
@@ -56,7 +55,7 @@ public class StartFragmentHook {
|
||||
case "videos":
|
||||
return videonewcatalog() ? VideoCatalogFragment.class : VideosFragment.class;
|
||||
case "settings":
|
||||
return VTSettings.class;
|
||||
return useNewSettings();
|
||||
case "apps":
|
||||
return AppsFragment.class;
|
||||
case "discover":
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.getMusicDir;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
|
||||
import org.json.JSONException;
|
||||
@@ -53,12 +58,10 @@ public class MP3Downloader {
|
||||
if (responseNode.has("url")) {
|
||||
var url = responseNode.optString("url");
|
||||
Log.d("MP3Downloader", url);
|
||||
if (url != null) {
|
||||
if (url.endsWith(".mp3")) {
|
||||
downloadMP3(track.toString(), url);
|
||||
} else if (VKM3UParser.isM3U8(url)) {
|
||||
AudioDownloader.downloadM3U8(track);
|
||||
}
|
||||
if (url.endsWith(".mp3")) {
|
||||
downloadMP3(track.toString(), url);
|
||||
} else if (VKM3UParser.isM3U8(url)) {
|
||||
AudioDownloader.downloadM3U8(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,13 +72,14 @@ public class MP3Downloader {
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private static void downloadMP3(String title, String url) {
|
||||
var downloadManager = AndroidUtils.getGlobalContext().getSystemService(DownloadManager.class);
|
||||
var request = new DownloadManager.Request(Uri.parse(url))
|
||||
.setAllowedOverRoaming(true)
|
||||
.setTitle("Downloading " + title)
|
||||
.setDestinationInExternalFilesDir(AndroidUtils.getGlobalContext(),
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(),
|
||||
getMusicDir().getAbsolutePath(),
|
||||
title + ".mp3")
|
||||
.setVisibleInDownloadsUi(true);
|
||||
downloadManager.enqueue(request);
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.vk.core.view.TintTextView;
|
||||
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class Recolor {
|
||||
|
||||
private static int getColor(int original) {
|
||||
var color = VTLColors.getColor(original);
|
||||
if (color != -1) return color;
|
||||
return original;
|
||||
}
|
||||
|
||||
public static void recolorToolbar(Toolbar toolbar) {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
toolbar.setBackgroundColor(ThemesUtils.getHeaderBackground());
|
||||
}
|
||||
|
||||
public static void recolorIconToAccent(ImageView iv) {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
iv.setImageTintList(ColorStateList.valueOf(VTLColors.getAccentColor()));
|
||||
}
|
||||
|
||||
public static void recolorTextToAccent(TextView iv) {
|
||||
iv.setTextColor(VTLColors.getAccentColor());
|
||||
}
|
||||
|
||||
public static void recolorTintTextViewToAccent(TintTextView ttv) {
|
||||
ttv.setDrawableTint(VTLColors.getAccentColor());
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.ContextExtKt;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class VTLColors {
|
||||
private static final ThemesManager themesManager = ThemesManager.getInstance();
|
||||
private static final ThemeModel currentTheme = themesManager.getCurrentTheme();
|
||||
|
||||
public static int getAccentColor() {
|
||||
return getColor(R.attr.accent, R.attr.accentColor, R.attr.colorAccent, R.attr.vk_accent);
|
||||
}
|
||||
|
||||
public static int getTextPrimaryColor() {
|
||||
return getColor(R.attr.text_primary);
|
||||
}
|
||||
|
||||
public static int getTextSecondaryColor() {
|
||||
return getColor(R.attr.text_secondary);
|
||||
}
|
||||
|
||||
public static int getTabbarBackground() {
|
||||
return getColor(R.attr.tabbar_background);
|
||||
}
|
||||
|
||||
public static int getTabbarActiveColor() {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
return getColor(R.attr.tabbar_active_icon);
|
||||
return Preferences.dockbar_accent()
|
||||
? getAccentColor()
|
||||
: AndroidUtils.getResources().getColor(ThemesUtils.isDarkTheme() ? R.color.white : R.color.gray_700);
|
||||
}
|
||||
|
||||
public static int getTabbarInactiveColor() {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
return getColor(R.attr.tabbar_inactive_icon);
|
||||
return AndroidUtils.getResources().getColor(ThemesUtils.isDarkTheme() ? R.color.gray_500 : R.color.vk_steel_gray_300);
|
||||
}
|
||||
|
||||
public static int getBackgroundContent() {
|
||||
return getColor(R.attr.background_content);
|
||||
}
|
||||
|
||||
public static int getBackgroundPage() {
|
||||
return getColor(R.attr.background_page);
|
||||
}
|
||||
|
||||
public static int getHeaderBackground() {
|
||||
return getColor(R.attr.header_background);
|
||||
}
|
||||
|
||||
public static int getHeaderText() {
|
||||
return getColor(R.attr.header_text);
|
||||
}
|
||||
|
||||
//region Hooks
|
||||
|
||||
public static int getColor(int... attrs) {
|
||||
return getColor(attrs[0]);
|
||||
}
|
||||
|
||||
public static int getColor(int attr) {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = currentTheme.getColor(attr);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return VKThemeHelper.d(attr);
|
||||
}
|
||||
|
||||
public static int getColor(Context context, int colorId) {
|
||||
try {
|
||||
Log.d("VTLColors", "getColor(Landroid/content/Context;I): " + AndroidUtils.getResources().getResourceEntryName(colorId));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = currentTheme.getColor(colorId);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return ContextExtKt.h(context, colorId);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.utils.ReflectionUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class VTLResources {
|
||||
private static final int STYLE_NUM_ENTRIES = Build.VERSION.SDK_INT >= 29 ? 7 : 6;
|
||||
public static final SparseIntArray forcedAttrs = new SparseIntArray();
|
||||
public static final SparseIntArray otherAttrs = new SparseIntArray();
|
||||
|
||||
private static Field dataField;
|
||||
|
||||
static {
|
||||
try {
|
||||
dataField = ReflectionUtils.getDeclaredField(TypedArray.class, "mData");
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
otherAttrs.put(R.attr.vklib_alv_optionIconTint, R.attr.im_dropdown_icon_color);
|
||||
otherAttrs.put(R.attr.vkim_colorPrimary, R.attr.accent);
|
||||
otherAttrs.put(R.attr.statusBarColorBack, R.attr.statusBarColorBack);
|
||||
otherAttrs.put(R.attr.statusBarColorFront, R.attr.statusBarColorFront);
|
||||
// android attributes
|
||||
otherAttrs.put(android.R.attr.backgroundTint, R.attr.accent);
|
||||
otherAttrs.put(android.R.attr.tint, R.attr.accent);
|
||||
otherAttrs.put(android.R.attr.color, R.attr.accent);
|
||||
|
||||
forcedAttrs.put(-0x8e5515, R.attr.accent);
|
||||
forcedAttrs.put(-0xe6e6e6, R.attr.background_content);
|
||||
}
|
||||
|
||||
public static void prepareTypedArray(TypedArray target, int[] attrs) {
|
||||
if (!ThemesUtils.isCustomThemeApplied() || attrs == null) return;
|
||||
var theme = ThemesManager.getInstance().getCurrentTheme();
|
||||
var data = getData(target);
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
//var attr = attrs[i];
|
||||
var off = STYLE_NUM_ENTRIES * i;
|
||||
var type = data[off];
|
||||
var replacement = -1;
|
||||
if (type == TypedValue.TYPE_ATTRIBUTE) {
|
||||
replacement = theme.getColor(data[off + 0x1]);
|
||||
} else if (type == TypedValue.TYPE_INT_COLOR_ARGB8 || type == TypedValue.TYPE_INT_COLOR_RGB8) {
|
||||
replacement = forcedAttrs.get(data[off + 0x1], -1);
|
||||
if (replacement == -1
|
||||
&& ThemesUtils.accentColors.contains(data[off + 0x1]))
|
||||
replacement = ThemesUtils.getAccentColor();
|
||||
}
|
||||
if (replacement == -1) continue;
|
||||
try {
|
||||
data[off] = TypedValue.TYPE_INT_COLOR_RGB8; // type
|
||||
data[off + 0x1] = replacement; // data
|
||||
data[off + 0x2] = 0x0; // asset cookie
|
||||
data[off + 0x3] = 0x0; // resource id
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] getData(TypedArray target) {
|
||||
try {
|
||||
return (int[]) dataField.get(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
//region Hooks
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, int[] attrs) {
|
||||
var target = context.obtainStyledAttributes(attrs);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, int resId, int[] attrs) {
|
||||
var target = context.obtainStyledAttributes(resId, attrs);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, AttributeSet set, int[] attrs) {
|
||||
var target = context.obtainStyledAttributes(set, attrs);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
|
||||
var target = context.obtainStyledAttributes(set, attrs, defStyleAttr, defStyleRes);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static int getColor(Resources res, int colorId) {
|
||||
return VTLColors.getColor(colorId);//res.getColor(colorId);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static int getColor(Resources res, int colorId, Resources.Theme theme) {
|
||||
return VTLColors.getColor(colorId);
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForColorStateLists")
|
||||
public static ColorStateList getColorStateList(Resources res, int colorId) {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = VTLColors.getColor(colorId);
|
||||
if (color != -1)
|
||||
return ColorStateList.valueOf(color);
|
||||
}
|
||||
return res.getColorStateList(colorId);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static ColorStateList getColorStateList(Resources res, int colorId, Resources.Theme theme) {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = VTLColors.getColor(colorId);
|
||||
if (color != -1)
|
||||
return ColorStateList.valueOf(color);
|
||||
}
|
||||
return res.getColorStateList(colorId, theme);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package ru.vtosters.lite.themes.managers;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.themes.models.PaletteModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
|
||||
public class PalettesManager {
|
||||
|
||||
private static PalettesManager instance;
|
||||
|
||||
private static File palettesDir = new File(Environment.getExternalStorageDirectory(), "VTL/themes/palettes");
|
||||
|
||||
private List<PaletteModel> palettes = new ArrayList<>();
|
||||
|
||||
public static PalettesManager getInstance() {
|
||||
if (instance == null)
|
||||
instance = new PalettesManager();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public PalettesManager() {
|
||||
load();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
palettes.clear();
|
||||
if (!palettesDir.exists())
|
||||
palettesDir.mkdirs();
|
||||
final var palettes = palettesDir.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
var check = true;
|
||||
if (palettes == null || palettes.length == 0)
|
||||
check = copyPaletteFromAssets();
|
||||
if (check)
|
||||
parsePalettes();
|
||||
}
|
||||
|
||||
private boolean copyPaletteFromAssets() {
|
||||
try {
|
||||
final var manager = AndroidUtils.getGlobalContext().getAssets();
|
||||
final var assets = manager.list("vtl_themes/palettes/");
|
||||
if (assets == null || assets.length == 0) return false;
|
||||
var i = 0;
|
||||
for (var asset : assets) {
|
||||
try {
|
||||
IOUtils.copyFile(manager.open("vtl_themes/palettes/" + asset), new File(palettesDir, asset));
|
||||
i++;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return i > 0;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void parsePalettes() {
|
||||
var arr = palettesDir.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
if (arr == null || arr.length == 0)
|
||||
throw new RuntimeException("Can't load palettes");
|
||||
for (var file : arr) {
|
||||
try {
|
||||
var json = new JSONObject(IOUtils.readAllLines(file));
|
||||
palettes.add(PaletteModel.fromJson(json));
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PaletteModel getPalette(String id) {
|
||||
for (PaletteModel palette : palettes) {
|
||||
if (id.equals(palette.id))
|
||||
return palette;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PaletteModel getPalette(int i) {
|
||||
return palettes.get(i);
|
||||
}
|
||||
|
||||
public int getPalettesCount() {
|
||||
return palettes.size();
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
package ru.vtosters.lite.themes.managers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vtosters.lite.auth.VKAccountManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import ru.vtosters.lite.ui.dialogs.ThemesEditorBottomSheetDialog;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ThemesManager {
|
||||
|
||||
private static File themesDir;
|
||||
private static ThemesManager instance;
|
||||
private static ThemeModel currentTheme = null;
|
||||
private List<ThemeModel> themes = new ArrayList<>();
|
||||
|
||||
public static ThemesManager getInstance() {
|
||||
if (instance == null)
|
||||
instance = new ThemesManager();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ThemesManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
themes = new ArrayList<>();
|
||||
currentTheme = new ThemeModel().setName("Тема по умолчанию")
|
||||
.setAuthor("Разработчики ВК")
|
||||
.setDarkMode(ThemesUtils.isDarkTheme())
|
||||
.setId("default");
|
||||
themes.add(currentTheme);
|
||||
themesDir = new File(Environment.getExternalStorageDirectory(), "VTL/themes");
|
||||
if (!themesDir.exists()) {
|
||||
themesDir.mkdirs();
|
||||
return;
|
||||
}
|
||||
// Support themes from Sova V RE (.svt)
|
||||
var files = themesDir.listFiles((dir, name) -> name.endsWith(".vtlt") || name.endsWith(".svt") || name.endsWith(".json"));
|
||||
if (files == null || files.length == 0)
|
||||
return;
|
||||
var currentThemeId = AndroidUtils.getPreferences().getString("vtl_theme_id", "default");
|
||||
for (File file : files) {
|
||||
try {
|
||||
ThemeModel theme;
|
||||
var abs = file.getAbsolutePath();
|
||||
if (abs.endsWith(".svt") || abs.endsWith(".json"))
|
||||
theme = svt2vtlt(file);
|
||||
else
|
||||
theme = read(file);
|
||||
if (theme != null) {
|
||||
Log.d("ThemesManager", theme.toString());
|
||||
if (currentThemeId.equals(theme.id))
|
||||
currentTheme = theme;
|
||||
themes.add(theme);
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ("default".equals(currentTheme.id))
|
||||
setTheme(currentTheme);
|
||||
}
|
||||
|
||||
private ThemeModel svt2vtlt(File file) {
|
||||
try {
|
||||
var theme = read(file);
|
||||
save(theme);
|
||||
return theme;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
init();
|
||||
}
|
||||
|
||||
public File getThemeFile(ThemeModel theme) throws IOException {
|
||||
if (!themesDir.exists()) {
|
||||
themesDir.mkdirs();
|
||||
throw new FileNotFoundException("theme file not found");
|
||||
}
|
||||
|
||||
var themeFile = new File(themesDir, theme.id + ".svt");
|
||||
if (!themeFile.exists()) {
|
||||
themeFile = new File(themesDir, theme.id + ".vtlt");
|
||||
if (!themeFile.exists())
|
||||
themeFile.createNewFile();
|
||||
}
|
||||
|
||||
return themeFile;
|
||||
}
|
||||
|
||||
public void setTheme(ThemeModel theme) {
|
||||
AndroidUtils.getPreferences()
|
||||
.edit()
|
||||
.putString("vtl_theme_id", theme.id)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public ThemeModel getTheme(int i) {
|
||||
return themes.get(i);
|
||||
}
|
||||
|
||||
public ThemeModel getCurrentTheme() {
|
||||
return currentTheme;
|
||||
}
|
||||
|
||||
public int getThemesCount() {
|
||||
return themes.size();
|
||||
}
|
||||
|
||||
public boolean isCurrentTheme(ThemeModel theme) {
|
||||
return currentTheme.id.equals(theme.id);
|
||||
}
|
||||
|
||||
public boolean hasTheme(ThemeModel theme) {
|
||||
return hasTheme(theme.id);
|
||||
}
|
||||
|
||||
public boolean hasTheme(String id) {
|
||||
for (ThemeModel theme : themes) {
|
||||
if (id.equals(theme.id))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Theme file storing method from Sova V RE is storing json clearly or compressed with gzip.
|
||||
* If first byte byte is 0x1 or 0x2 json has been compressed with gzip,
|
||||
* but if first byte is 0x2 next int is length of json string. */
|
||||
|
||||
private ThemeModel read(InputStream fis) throws IOException, JSONException {
|
||||
InputStream is = fis;
|
||||
var first = is.read();
|
||||
if (first > 0x0 && first < 0x3) {
|
||||
var gzis = new GZIPInputStream(is);
|
||||
var dis = new DataInputStream(gzis);
|
||||
if (first == 0x2)
|
||||
dis.readInt();
|
||||
is = dis;
|
||||
}
|
||||
return ThemeModel.fromJson(IOUtils.readAllLines(is));
|
||||
}
|
||||
|
||||
private ThemeModel read(File file) throws IOException, JSONException {
|
||||
return read(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public void save(ThemeModel theme) throws IOException, JSONException {
|
||||
var buffer = theme.toJson().toString().getBytes(StandardCharsets.UTF_8);
|
||||
var fos = new FileOutputStream(getThemeFile(theme));
|
||||
// writing with data length
|
||||
fos.write(0x2);
|
||||
var gzos = new GZIPOutputStream(fos);
|
||||
var dos = new DataOutputStream(gzos);
|
||||
dos.writeInt(buffer.length);
|
||||
dos.write(buffer);
|
||||
dos.close();
|
||||
}
|
||||
|
||||
public void delete(ThemeModel theme) {
|
||||
try {
|
||||
getThemeFile(theme).delete();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
themes.remove(theme);
|
||||
if (isCurrentTheme(theme)) {
|
||||
setTheme(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void create(Activity activity, String name) throws JSONException, IOException {
|
||||
var id = name.toLowerCase().replace(" ", "-");
|
||||
if (hasTheme(id)) {
|
||||
var i = 1;
|
||||
while (hasTheme(id + "-" + i)) {
|
||||
i++;
|
||||
}
|
||||
id += "-" + i;
|
||||
}
|
||||
var userProfile = VKAccountManager.d().e1();
|
||||
ThemeModel theme = new ThemeModel()
|
||||
.setName(name)
|
||||
.setAuthor(userProfile.c + " " + userProfile.e)
|
||||
.setDarkMode(true)
|
||||
// .setColors(DEFAULT_COLORS)
|
||||
.setId(id);
|
||||
themes.add(theme);
|
||||
ThemesEditorBottomSheetDialog.create(activity, theme, false);
|
||||
save(theme);
|
||||
}
|
||||
|
||||
public void copy(ContentResolver contentResolver, Uri uri) throws IOException, JSONException {
|
||||
var theme = read(contentResolver.openInputStream(uri));
|
||||
if (isCurrentTheme(theme)) {
|
||||
int i = 1;
|
||||
while (hasTheme(theme.id + "-" + i)) {
|
||||
i++;
|
||||
}
|
||||
theme.id += "-" + i;
|
||||
}
|
||||
themes.add(theme);
|
||||
save(theme);
|
||||
}
|
||||
|
||||
public void share(Context context, ThemeModel theme) throws Exception {
|
||||
var vmPolicy = StrictMode.getVmPolicy();
|
||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());
|
||||
var intent = new Intent(Intent.ACTION_SEND)
|
||||
.setType("file/*")
|
||||
.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(getThemeFile(theme)));
|
||||
context.startActivity(Intent.createChooser(intent, ""));
|
||||
StrictMode.setVmPolicy(vmPolicy);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
public class ColorModel {
|
||||
|
||||
public String resName;
|
||||
public int id;
|
||||
public int color;
|
||||
|
||||
public ColorModel(int id, int color) {
|
||||
this.id = id;
|
||||
this.color = color;
|
||||
}
|
||||
public ColorModel(String resName, int id, int color) {
|
||||
this.resName = resName;
|
||||
this.id = id;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static ColorModel create(int id, int color) {
|
||||
return new ColorModel(id, color);
|
||||
}
|
||||
|
||||
public static ColorModel create(String resName, int id, int color) {
|
||||
return new ColorModel(resName, id, color);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PaletteModel {
|
||||
public String id;
|
||||
public String name;
|
||||
public String author;
|
||||
public List<ColorModel> colors = new ArrayList<>();
|
||||
|
||||
public PaletteModel() {
|
||||
|
||||
}
|
||||
|
||||
public PaletteModel(String id, String name, String author, List<ColorModel> colors) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public PaletteModel setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setAuthor(String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setColors(List<ColorModel> colors) {
|
||||
this.colors = colors;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setColor(String name, int color) {
|
||||
this.colors.add(new ColorModel(name, 0, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor(String name) {
|
||||
for (var item : colors)
|
||||
if (name.equals(item.resName))
|
||||
return item.color;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static PaletteModel fromJson(JSONObject json) throws JSONException {
|
||||
var palette = new PaletteModel()
|
||||
.setId(json.optString("palette_id"))
|
||||
.setName(json.optString("name"))
|
||||
.setAuthor(json.optString("author"));
|
||||
var paletteNode = json.getJSONArray("palette");
|
||||
for (int i = 0; i < paletteNode.length(); i++) {
|
||||
var colorNode = paletteNode.getJSONObject(i);
|
||||
var name = colorNode.getString("name");
|
||||
if (colorNode.has("colors")) {
|
||||
var colorsNode = colorNode.getJSONArray("colors");
|
||||
for (int j = 0; j < colorsNode.length(); j++) {
|
||||
var subColorNode = colorsNode.getJSONObject(j);
|
||||
var index = subColorNode.getString("index");
|
||||
var subColor = subColorNode.getString("color");
|
||||
if (!subColor.startsWith("#")) subColor = "#" + subColor;
|
||||
palette.setColor(name + " " + index, Color.parseColor(subColor));
|
||||
}
|
||||
} else {
|
||||
var color = colorNode.getString("color");
|
||||
if (!color.startsWith("#")) color = "#" + color;
|
||||
palette.setColor(name, Color.parseColor(color));
|
||||
}
|
||||
}
|
||||
return palette;
|
||||
}
|
||||
|
||||
public static PaletteModel valuesOf(String id, String name, String author, List<ColorModel> colors) {
|
||||
return new PaletteModel()
|
||||
.setId(id)
|
||||
.setName(name)
|
||||
.setAuthor(author)
|
||||
.setColors(colors);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.PalettesManager;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class ThemeModel {
|
||||
|
||||
public String author;
|
||||
public String name;
|
||||
public boolean isDarkMode;
|
||||
public String id;
|
||||
public List<ColorModel> colors = new ArrayList<>();
|
||||
|
||||
public ThemeModel() {
|
||||
}
|
||||
|
||||
public ThemeModel(String author, String name, boolean darkMode, String id, List<ColorModel> colors) {
|
||||
this.author = author;
|
||||
this.name = name;
|
||||
this.isDarkMode = darkMode;
|
||||
this.id = id;
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public ThemeModel setAuthor(String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setDarkMode(boolean b) {
|
||||
this.isDarkMode = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setColors(List<ColorModel> colors) {
|
||||
this.colors = colors;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setColor(int attrId, int color) {
|
||||
this.colors.add(new ColorModel(attrId, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor(int attrId) {
|
||||
for (var item : colors)
|
||||
if (attrId == item.id)
|
||||
return item.color;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static ThemeModel valuesOf(String author, String name, boolean darkMode, String id, List<ColorModel> colors) {
|
||||
var theme = new ThemeModel()
|
||||
.setAuthor(author)
|
||||
.setName(name)
|
||||
.setDarkMode(darkMode)
|
||||
.setId(id)
|
||||
.setColors(colors);
|
||||
return theme;
|
||||
}
|
||||
|
||||
public static ThemeModel fromJson(String json) throws JSONException {
|
||||
return fromJson(new JSONObject(json));
|
||||
}
|
||||
|
||||
public static ThemeModel fromJson(JSONObject json) {
|
||||
List<String> palettes;
|
||||
if (json.has("palettes")) {
|
||||
palettes = new ArrayList<>();
|
||||
var arr = json.optString("palettes")
|
||||
.split("\\||,|&|;");
|
||||
Collections.addAll(palettes, arr);
|
||||
}
|
||||
List<ColorModel> colors = new ArrayList<>();
|
||||
var colorsJson = json.optJSONObject("colors");
|
||||
var names = colorsJson.names();
|
||||
for (int i = 0; i < colorsJson.length(); i++) {
|
||||
var name = names.optString(i);
|
||||
var value = colorsJson.optString(name);
|
||||
int attrId;
|
||||
try {
|
||||
attrId = AndroidUtils.getIdentifier(name, "attr");
|
||||
} catch (Resources.NotFoundException e) {
|
||||
attrId = AndroidUtils.getIdentifier(name, "color");
|
||||
}
|
||||
final int color;
|
||||
if (value.contains(".")) {
|
||||
var paletteId = value.substring(0, value.indexOf("."));
|
||||
var palette = PalettesManager.getInstance().getPalette(paletteId);
|
||||
var paletteColor = value.substring(value.indexOf(".") + 1);
|
||||
color = palette.getColor(paletteColor);
|
||||
} else {
|
||||
color = Color.parseColor(value.startsWith("#") ? value : "#" + value);
|
||||
}
|
||||
colors.add(new ColorModel(name, attrId, color));
|
||||
}
|
||||
return valuesOf(
|
||||
json.optString("author"),
|
||||
json.optString("name"),
|
||||
json.optBoolean("dark"),
|
||||
json.optString("id"),
|
||||
colors
|
||||
);
|
||||
}
|
||||
|
||||
public JSONObject toJson() throws JSONException {
|
||||
var colorsJson = new JSONObject();
|
||||
for (var item : colors)
|
||||
colorsJson.put(item.resName, Integer.toHexString(item.color).toUpperCase());
|
||||
return new JSONObject()
|
||||
.put("author", this.author)
|
||||
.put("name", this.name)
|
||||
.put("dark", this.isDarkMode)
|
||||
.put("id", this.id)
|
||||
.put("colors", colorsJson);
|
||||
}
|
||||
|
||||
public ThemeModel clone() {
|
||||
return new ThemeModel(
|
||||
author,
|
||||
name,
|
||||
isDarkMode,
|
||||
id,
|
||||
colors.stream()
|
||||
.map(colorModel -> new ColorModel(colorModel.resName, colorModel.id, colorModel.color))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ViewModel {
|
||||
|
||||
@IdRes public int id;
|
||||
public List<Pair<Integer, Integer>> attrs = new ArrayList<>();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package ru.vtosters.lite.themes.proxy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.XmlRes;
|
||||
|
||||
import ru.vtosters.lite.themes.VTLResources;
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ProxyResources extends Resources {
|
||||
|
||||
private final Resources mOriginalResource;
|
||||
|
||||
public ProxyResources(Context context, Resources original) {
|
||||
this(original);
|
||||
}
|
||||
|
||||
public ProxyResources(Resources original) {
|
||||
super(original.getAssets(), original.getDisplayMetrics(), original.getConfiguration());
|
||||
mOriginalResource = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor(int id, @Nullable Resources.Theme theme) throws Resources.NotFoundException {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
var color = ThemesManager.getInstance().getCurrentTheme().getColor(id);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return mOriginalResource.getColor(id, theme);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@NonNull
|
||||
@Override
|
||||
public ColorStateList getColorStateList(@XmlRes int id, @Nullable Resources.Theme theme)
|
||||
throws Resources.NotFoundException {
|
||||
var target = mOriginalResource.getColorStateList(id, theme);
|
||||
if (ThemesUtils.isCustomThemeApplied() && ThemesUtils.isAccentedColor(target)) {
|
||||
return ColorStateList.valueOf(ThemesUtils.getAccentColor());
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Drawable getDrawableForDensity(int id, int density, @Nullable Resources.Theme theme) {
|
||||
return mOriginalResource.getDrawableForDensity(id, density, theme);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
|
||||
var ta = super.obtainAttributes(set, attrs);
|
||||
VTLResources.prepareTypedArray(ta, attrs);
|
||||
return ta;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package ru.vtosters.lite.ui.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuInflater;
|
||||
|
||||
import com.vk.core.ui.themes.ThemableActivity;
|
||||
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
public class VTLThemableActivity extends ThemableActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
LifecycleUtils.addActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LifecycleUtils.removeActivity(this);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package ru.vtosters.lite.ui.adapters;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vk.core.drawable.BorderDrawable;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.stories.view.StoryCircleImageView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.themes.models.ColorModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ColorPickerAdapter extends RecyclerView.Adapter<ColorPickerAdapter.ColorPickerViewHolder> {
|
||||
|
||||
private List<ColorModel> mColors;
|
||||
private OnColorSelectListener mSelectListener;
|
||||
|
||||
public ColorPickerAdapter(List<ColorModel> colors, OnColorSelectListener selectListener) {
|
||||
this.mColors = colors;
|
||||
this.mSelectListener = selectListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ColorPickerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
var container = LayoutInflater.from(parent.getContext())
|
||||
.inflate(AndroidUtils.getIdentifier("color_picker_item", "layout"), parent, false);
|
||||
return new ColorPickerViewHolder(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ColorPickerViewHolder holder, int pos) {
|
||||
holder.bind(mColors.get(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mColors.size();
|
||||
}
|
||||
|
||||
public class ColorPickerViewHolder extends RecyclerView.ViewHolder {
|
||||
private View mContainer;
|
||||
private FrameLayout mColorPreviewBorder;
|
||||
private StoryCircleImageView mColorPreview;
|
||||
private TextView mColorName;
|
||||
private TextView mColorValue;
|
||||
|
||||
public ColorPickerViewHolder(@NonNull View view) {
|
||||
super(view);
|
||||
|
||||
mContainer = view;
|
||||
mColorPreviewBorder = view.findViewById(AndroidUtils.getIdentifier("color_preview_border", "id"));
|
||||
mColorPreview = view.findViewById(AndroidUtils.getIdentifier("color_preview", "id"));
|
||||
mColorName = view.findViewById(AndroidUtils.getIdentifier("color_name", "id"));
|
||||
mColorValue = view.findViewById(AndroidUtils.getIdentifier("color_value", "id"));
|
||||
}
|
||||
|
||||
public void bind(ColorModel item) {
|
||||
mContainer.setOnClickListener(v -> mSelectListener.onColorSelected(ColorPickerAdapter.this, item));
|
||||
mColorPreviewBorder.setBackground(new BorderDrawable(ThemesUtils.isDarkTheme() ? Color.WHITE : Color.BLACK, Screen.c(24.0f), Screen.c(1.0f)));
|
||||
mColorPreview.setPlaceholderColor(item.color);
|
||||
mColorName.setText(item.resName);
|
||||
mColorValue.setText("#" + Integer.toHexString(item.color).toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnColorSelectListener {
|
||||
|
||||
void onColorSelected(ColorPickerAdapter adapter, ColorModel colorModel);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package ru.vtosters.lite.ui.adapters;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.PalettesManager;
|
||||
import ru.vtosters.lite.ui.dialogs.PalettesBottomSheetDialog;
|
||||
import ru.vtosters.lite.themes.models.PaletteModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class PalettesAdapter extends RecyclerView.Adapter<PalettesAdapter.PaletteViewHolder> {
|
||||
|
||||
private PalettesManager manager = PalettesManager.getInstance();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PaletteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
var container = LayoutInflater.from(parent.getContext()).inflate(
|
||||
AndroidUtils.getIdentifier("palette_manager_item", "layout"), parent, false
|
||||
);
|
||||
return new PaletteViewHolder(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull PaletteViewHolder holder, int pos) {
|
||||
holder.bind(manager.getPalette(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return manager.getPalettesCount();
|
||||
}
|
||||
|
||||
public static class PaletteViewHolder extends RecyclerView.ViewHolder {
|
||||
private View mContainer;
|
||||
private TextView mName;
|
||||
private TextView mAuthor;
|
||||
|
||||
public PaletteViewHolder(@NonNull View view) {
|
||||
super(view);
|
||||
|
||||
mContainer = view;
|
||||
mName = view.findViewById(R.id.name);
|
||||
mAuthor = view.findViewById(AndroidUtils.getIdentifier("author", "id"));
|
||||
}
|
||||
|
||||
public void bind(PaletteModel palette) {
|
||||
mContainer.setOnClickListener(v -> {
|
||||
PalettesBottomSheetDialog.create((Activity) v.getContext(), palette);
|
||||
});
|
||||
mName.setText(palette.name);
|
||||
mAuthor.setText(palette.author);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
package ru.vtosters.lite.ui.adapters;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vk.core.drawable.BorderDrawable;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.ui.dialogs.EditTextDialog;
|
||||
import ru.vtosters.lite.ui.dialogs.ThemesEditorBottomSheetDialog;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.ui.views.NoTouchRadioButton;
|
||||
import ru.vtosters.lite.ui.vkui.VKUIActionPopup;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ThemesAdapter extends RecyclerView.Adapter<ThemesAdapter.ThemeViewHolder> {
|
||||
|
||||
public ThemesManager mManager = ThemesManager.getInstance();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ThemeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
var container = LayoutInflater.from(parent.getContext()).inflate(
|
||||
AndroidUtils.getIdentifier("theme_manager_item", "layout"), parent, false
|
||||
);
|
||||
return new ThemeViewHolder(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ThemeViewHolder holder, int pos) {
|
||||
holder.bind(mManager.getTheme(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mManager.getThemesCount();
|
||||
}
|
||||
|
||||
public class ThemeViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ConstraintLayout mContainer;
|
||||
private FrameLayout mThemeModePreviewBorder;
|
||||
private ImageView mThemeModePreview;
|
||||
private TextView mName;
|
||||
private TextView mAuthor;
|
||||
private NoTouchRadioButton mRadioButton;
|
||||
|
||||
public ThemeViewHolder(@NonNull View view) {
|
||||
super(view);
|
||||
|
||||
mContainer = (ConstraintLayout) view;
|
||||
mThemeModePreviewBorder = view.findViewById(AndroidUtils.getIdentifier("theme_mode_preview_border", "id"));
|
||||
mThemeModePreview = view.findViewById(AndroidUtils.getIdentifier("theme_mode_preview", "id"));
|
||||
mName = view.findViewById(R.id.name);
|
||||
mAuthor = view.findViewById(AndroidUtils.getIdentifier("author", "id"));
|
||||
mRadioButton = view.findViewById(AndroidUtils.getIdentifier("selection", "id"));
|
||||
}
|
||||
|
||||
public void bind(ThemeModel theme) {
|
||||
var accent = getAccentColorFromCustomTheme(theme);
|
||||
mThemeModePreviewBorder.setBackground(new BorderDrawable(accent, Screen.c(24.0f), Screen.c(1.0f)));
|
||||
mThemeModePreview.setImageResource(AndroidUtils.getIdentifier(
|
||||
"vk_icon_" + (theme.isDarkMode ? "moon" : "sun") + "_outline_28",
|
||||
"drawable"));
|
||||
mThemeModePreview.setImageTintList(ColorStateList.valueOf(accent));
|
||||
var isCurrentTheme = mManager.isCurrentTheme(theme);
|
||||
if (!isCurrentTheme)
|
||||
mContainer.setOnClickListener(v -> {
|
||||
mManager.setTheme(theme);
|
||||
LifecycleUtils.restartApplication();
|
||||
});
|
||||
if (!"default".equals(theme.id))
|
||||
mContainer.setOnLongClickListener(v -> {
|
||||
showActionPopup(v.getContext(), v, isCurrentTheme, theme);
|
||||
return true;
|
||||
});
|
||||
else
|
||||
mContainer.setOnLongClickListener(null);
|
||||
mRadioButton.setChecked(isCurrentTheme);
|
||||
mName.setText(theme.name);
|
||||
mAuthor.setText(theme.author);
|
||||
}
|
||||
|
||||
private void showActionPopup(Context context, View anchorView, boolean isCurrentTheme, ThemeModel theme) {
|
||||
var builder = new VKUIActionPopup(context, anchorView, true, R.color.colorAccent)
|
||||
.setItem("Редактировать название",
|
||||
() -> showEditThemeNameDialog(context, theme))
|
||||
.setItem("Изменить цвета",
|
||||
() -> ThemesEditorBottomSheetDialog.create((Activity) context, theme, isCurrentTheme))
|
||||
.setItem("Поделиться темой", () -> {
|
||||
try {
|
||||
mManager.share(context, theme);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a("Не удалось поделиться темой");
|
||||
}})
|
||||
.setItem("Удалить тему", () -> {
|
||||
mManager.delete(theme);
|
||||
if (isCurrentTheme)
|
||||
LifecycleUtils.restartApplication();
|
||||
else
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
builder.create().d();
|
||||
}
|
||||
|
||||
private void showEditThemeNameDialog(Context context, ThemeModel theme) {
|
||||
EditTextDialog.create(context, "Редактирование названия темы", "Название темы", theme.name, (dialog, which, editText) -> {
|
||||
var newName = editText.getText().toString();
|
||||
if (TextUtils.isEmpty(newName)) {
|
||||
ToastUtils.a("Название не может быть пустым");
|
||||
return;
|
||||
}
|
||||
if (newName.equals(theme.name)) {
|
||||
ToastUtils.a("Вы не изменили название");
|
||||
return;
|
||||
}
|
||||
theme.setName(newName);
|
||||
try {
|
||||
mManager.save(theme);
|
||||
notifyDataSetChanged();
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a("Не удалось изменить название темы");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private int getAccentColorFromCustomTheme(ThemeModel theme) {
|
||||
if (!"default".equals(theme.id)) {
|
||||
int color = theme.getColor(R.attr.accent);
|
||||
if (color != -1)
|
||||
return color;
|
||||
color = theme.getColor(R.attr.colorAccent);
|
||||
if (color != -1)
|
||||
return color;
|
||||
color = theme.getColor(R.attr.vk_accent);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return VKThemeHelper.d((R.attr.accent));
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.milkshake;
|
||||
import static ru.vtosters.lite.utils.Preferences.superapp;
|
||||
import static ru.vtosters.lite.utils.Preferences.useNewSettings;
|
||||
import static ru.vtosters.lite.utils.Preferences.videonewcatalog;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme_notifs;
|
||||
@@ -42,7 +43,6 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ru.vtosters.lite.ui.fragments.VTSettings;
|
||||
import ru.vtosters.lite.ui.items.DockBarTab;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
@@ -261,7 +261,7 @@ public class DockBarEditorManager {
|
||||
R.drawable.ic_settings_outline_28,
|
||||
R.string.menu_settings,
|
||||
R.id.menu_settings,
|
||||
VTSettings.class);
|
||||
useNewSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import static ru.vtosters.lite.themes.VTLColors.getTextSecondaryColor;
|
||||
import static ru.vtosters.lite.themes.VTLColors.getTextPrimaryColor;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
|
||||
import ru.vtosters.lite.ui.vkui.VKUIEditText;
|
||||
import ru.vtosters.lite.ui.vkui.VKUITextView;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class EditTextDialog {
|
||||
public static void create(Context context, String title, String hint, String text, OnClickListener clickListener) {
|
||||
var container = new LinearLayout(context);
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
container.setPadding(
|
||||
dp2px(8), dp2px(12), dp2px(8), dp2px(12)
|
||||
);
|
||||
|
||||
if (!TextUtils.isEmpty(hint)) {
|
||||
var hitText = new VKUITextView(context, VKUITextView.STYLE_SUBHEAD_1);
|
||||
hitText.setText(hint);
|
||||
hitText.setPadding(dp2px(8), 0, 0, dp2px(8));
|
||||
container.addView(hitText, LayoutUtils.createLinear(-2, -2));
|
||||
}
|
||||
|
||||
var editText = new VKUIEditText(context);
|
||||
if (!TextUtils.isEmpty(text))
|
||||
editText.setText(text);
|
||||
editText.setTextColor(getTextPrimaryColor());
|
||||
editText.setHintTextColor(getTextSecondaryColor());
|
||||
editText.setPadding(dp2px(8), 0, dp2px(8), 0);
|
||||
|
||||
var editTextParams = LayoutUtils.createLinear(-1, dp2px(44));
|
||||
container.addView(editText, editTextParams);
|
||||
|
||||
VkAlertDialog.Builder builder = new VkAlertDialog.Builder(context);
|
||||
if (!TextUtils.isEmpty(title))
|
||||
builder.setTitle(title);
|
||||
builder.setPositiveButton("OK", (dialog, which) -> clickListener.onClick(dialog, which, editText));
|
||||
builder.setNegativeButton("Отмена", (dialog, which) -> dialog.cancel());
|
||||
|
||||
var alert = builder.create();
|
||||
alert.setView(container);
|
||||
alert.show();
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick(DialogInterface dialog, int which, EditText editText);
|
||||
}
|
||||
}
|
||||
@@ -29,13 +29,13 @@ public class OTADialog implements OTAUtils.OTAListener {
|
||||
public void onUpdateApplied() {
|
||||
mActivity.runOnUiThread(() -> {
|
||||
// Toast.makeText(mActivity, "Обновления найдены", Toast.LENGTH_SHORT).show();
|
||||
// new ModalBottomSheetWrapper(mActivity)
|
||||
// .setTitle(getString("newversion") + " " + mHelper.getNewVersionName())
|
||||
// // .setUpdateInfoView(mHelper.getUpdateDescription())
|
||||
// .setPositiveButton(getString("updateanddownload"), () -> {
|
||||
// OTADownloader.downloadBuild(mHelper.getDownloadUrl());
|
||||
// })
|
||||
// .show();
|
||||
new ModalBottomSheetWrapper(mActivity)
|
||||
.setTitle(getString("newversion") + " " + mHelper.getNewVersionName())
|
||||
.setUpdateInfoView(mHelper.getUpdateDescription())
|
||||
.setPositiveButton(getString("updateanddownload"), () -> {
|
||||
OTADownloader.downloadBuild(mHelper.getDownloadUrl());
|
||||
})
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
|
||||
import com.vk.core.util.ToastUtils;
|
||||
|
||||
import ru.vtosters.lite.ui.adapters.ColorPickerAdapter;
|
||||
import ru.vtosters.lite.themes.models.PaletteModel;
|
||||
|
||||
public class PalettesBottomSheetDialog {
|
||||
|
||||
private static final String TAG = "palettes_copy_color";
|
||||
|
||||
public static void create(Activity activity, PaletteModel palette) {
|
||||
var instance = new VTColorPickerBottomSheetDialog(activity);
|
||||
var colorPickerAdapter = new ColorPickerAdapter(palette.colors, (adapter, color) -> {
|
||||
var manager = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
manager.setPrimaryClip(ClipData.newPlainText("color", Integer.toHexString(color.color).toUpperCase()));
|
||||
ToastUtils.a("Скопировано в буфер обмена");
|
||||
instance.dismiss();
|
||||
});
|
||||
instance.setTitle(palette.name)
|
||||
.setAdapter(colorPickerAdapter, true)
|
||||
.show(TAG, true);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
@@ -9,6 +8,7 @@ import android.content.Context;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
@@ -97,18 +97,18 @@ public class ServerDialog {
|
||||
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(() -> {
|
||||
// VkAlertDialog.Builder builder = new VkAlertDialog.Builder(activity);
|
||||
// builder.setTitle(title);
|
||||
// builder.setMessage(message);
|
||||
// builder.setCancelable(cancelable);
|
||||
// builder.setPositiveButton(positiveButton, (dialogInterface, i) -> edit().putBoolean(key, false).apply());
|
||||
// builder.setNeutralButton(neutralButton, (dialogInterface, i) -> {
|
||||
// edit().putBoolean(key, false).apply();
|
||||
// activity.startActivity(new Intent("android.intent.action.VIEW").setData(Uri.parse(link)));
|
||||
// });
|
||||
// if (getBoolValue(key, true) && showForNotVerified() && showAlert) {
|
||||
// builder.show();
|
||||
// }
|
||||
VkAlertDialog.Builder builder = new VkAlertDialog.Builder(activity);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(message);
|
||||
builder.setCancelable(cancelable);
|
||||
builder.setPositiveButton(positiveButton, (dialogInterface, i) -> edit().putBoolean(key, false).apply());
|
||||
builder.setNeutralButton(neutralButton, (dialogInterface, i) -> {
|
||||
edit().putBoolean(key, false).apply();
|
||||
activity.startActivity(new Intent("android.intent.action.VIEW").setData(Uri.parse(link)));
|
||||
});
|
||||
if (getBoolValue(key, true) && showForNotVerified() && showAlert) {
|
||||
builder.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.Gravity;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ru.vtosters.lite.themes.VTLColors;
|
||||
import ru.vtosters.lite.themes.managers.PalettesManager;
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.themes.models.ColorModel;
|
||||
import ru.vtosters.lite.ui.adapters.ColorPickerAdapter;
|
||||
import ru.vtosters.lite.themes.models.PaletteModel;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.ui.views.flask.builder.ColorPickerDialogBuilder;
|
||||
import ru.vtosters.lite.ui.views.rarepebble.ColorPickerView;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
public class ThemesEditorBottomSheetDialog {
|
||||
|
||||
private static final String THEME_EDITOR_TAG = "theme_editor";
|
||||
private static final String PALETTES_EDITOR_TAG = "palettes_editor";
|
||||
private static final String[] COLOR_PICKERS = {
|
||||
"Wheel Color Picker by QuadFlask",
|
||||
"Palettes",
|
||||
"Advanced Color Picker by Martin Stone"
|
||||
};
|
||||
|
||||
public static void create(Activity activity, ThemeModel theme, boolean currentTheme) {
|
||||
var newTheme = theme.clone();
|
||||
var colorPickerAdapter = new ColorPickerAdapter(newTheme.colors, (adapter, color) -> {
|
||||
new VkAlertDialog.Builder(activity)
|
||||
.setItems(COLOR_PICKERS, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
showQuadFlashWheelColorPicker(activity, adapter, color);
|
||||
} else if (which == 1) {
|
||||
showPaletteChoiceDialog(activity, adapter, color);
|
||||
} else if (which == 2) {
|
||||
showMartinStoneColorPicker(activity, adapter, color);
|
||||
}
|
||||
})
|
||||
.create()
|
||||
.show();
|
||||
});
|
||||
var instance = new VTColorPickerBottomSheetDialog(activity);
|
||||
addSwitches(instance.getContainer(), newTheme, colorPickerAdapter);
|
||||
instance.setAdapter(colorPickerAdapter, false)
|
||||
.setTitle("Редактирование " + theme.name)
|
||||
.setPositiveButton("Применить", () -> {
|
||||
String message;
|
||||
try {
|
||||
ThemesManager.getInstance().save(newTheme);
|
||||
message = "Тема изменена";
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
message = "Ошибка при изменении темы";
|
||||
}
|
||||
if (currentTheme) {
|
||||
LifecycleUtils.restartApplication();
|
||||
return;
|
||||
}
|
||||
ToastUtils.a(message);
|
||||
instance.dismiss();
|
||||
})
|
||||
.show(THEME_EDITOR_TAG, true);
|
||||
}
|
||||
|
||||
private static void addSwitches(LinearLayout container, ThemeModel theme, ColorPickerAdapter adapter) {
|
||||
var context = container.getContext();
|
||||
|
||||
var switchesContainer = new LinearLayout(context);
|
||||
switchesContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||
switchesContainer.setPadding(0, dp2px(5), 0, dp2px(5));
|
||||
container.addView(switchesContainer, LayoutUtils.createLinear(-1, -2));
|
||||
|
||||
var amoledTheme = new SwitchCompat(context);
|
||||
amoledTheme.setTextColor(VTLColors.getTextPrimaryColor());
|
||||
amoledTheme.setTextSize(16.0f);
|
||||
amoledTheme.setText("AMOLED-тема");
|
||||
amoledTheme.setEnabled(theme.isDarkMode);
|
||||
amoledTheme.setGravity(Gravity.CENTER);
|
||||
amoledTheme.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
theme.isDarkMode = isChecked;
|
||||
if (isChecked) {
|
||||
replaceToAmoled(theme, adapter);
|
||||
} else {
|
||||
replaceToLight(theme, adapter);
|
||||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
});
|
||||
|
||||
var darkTheme = new SwitchCompat(context);
|
||||
darkTheme.setChecked(theme.isDarkMode);
|
||||
darkTheme.setTextColor(VTLColors.getTextPrimaryColor());
|
||||
darkTheme.setGravity(Gravity.CENTER);
|
||||
darkTheme.setTextSize(16.0f);
|
||||
darkTheme.setText("Темная тема");
|
||||
darkTheme.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
theme.isDarkMode = isChecked;
|
||||
if (isChecked) {
|
||||
amoledTheme.setEnabled(true);
|
||||
replaceToDark(theme, adapter);
|
||||
} else {
|
||||
amoledTheme.setChecked(false);
|
||||
amoledTheme.setEnabled(false);
|
||||
replaceToLight(theme, adapter);
|
||||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
});
|
||||
var darkThemeParams = LayoutUtils.createLinear(-1, -2);
|
||||
darkThemeParams.weight = 1.0f;
|
||||
switchesContainer.addView(darkTheme, darkThemeParams);
|
||||
var amoledThemeParams = LayoutUtils.createLinear(-1, -2);
|
||||
amoledThemeParams.weight = 1.0f;
|
||||
switchesContainer.addView(amoledTheme, amoledThemeParams);
|
||||
}
|
||||
|
||||
private static void replaceToLight(ThemeModel theme, ColorPickerAdapter adapter) {
|
||||
|
||||
}
|
||||
|
||||
private static void replaceToDark(ThemeModel theme, ColorPickerAdapter adapter) {
|
||||
|
||||
}
|
||||
|
||||
private static void replaceToAmoled(ThemeModel theme, ColorPickerAdapter adapter) {
|
||||
|
||||
}
|
||||
|
||||
private static void showMartinStoneColorPicker(
|
||||
Activity activity,
|
||||
ColorPickerAdapter adapter,
|
||||
ColorModel dest) {
|
||||
var colorPickerView = new ColorPickerView(activity);
|
||||
colorPickerView.setColor(dest.color);
|
||||
var alertDialog = new VkAlertDialog.Builder(activity)
|
||||
.setTitle("Выберите цвет")
|
||||
.setPositiveButton("Выбрать", (dialog, which) -> {
|
||||
dest.color = colorPickerView.getColor();
|
||||
adapter.notifyDataSetChanged();
|
||||
dialog.dismiss();
|
||||
})
|
||||
.create();
|
||||
alertDialog.setView(colorPickerView);
|
||||
alertDialog.show();
|
||||
}
|
||||
|
||||
private static void showQuadFlashWheelColorPicker(
|
||||
Activity activity,
|
||||
ColorPickerAdapter adapter,
|
||||
ColorModel dest) {
|
||||
ColorPickerDialogBuilder
|
||||
.with(activity)
|
||||
.setTitle("Выберите цвет")
|
||||
.showBorder(true)
|
||||
.setOnColorSelectedListener((dialog, selectedColor) -> {
|
||||
dest.color = selectedColor;
|
||||
adapter.notifyDataSetChanged();
|
||||
dialog.cancel();
|
||||
})
|
||||
.build()
|
||||
.show();
|
||||
}
|
||||
|
||||
private static void showPaletteChoiceDialog(
|
||||
Activity activity,
|
||||
ColorPickerAdapter adapter,
|
||||
ColorModel dest
|
||||
) {
|
||||
var palettesManager = PalettesManager.getInstance();
|
||||
var titles = new String[palettesManager.getPalettesCount()];
|
||||
for (int i = 0; i < titles.length; i++)
|
||||
titles[i] = palettesManager.getPalette(i).name;
|
||||
new VkAlertDialog.Builder(activity)
|
||||
.setItems(titles, (dialog, which) -> createPaletteColorPicker(
|
||||
activity,
|
||||
adapter,
|
||||
dest,
|
||||
palettesManager.getPalette(which)))
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
private static void createPaletteColorPicker(
|
||||
Activity activity,
|
||||
ColorPickerAdapter themeEditAdapter,
|
||||
ColorModel dest,
|
||||
PaletteModel palette
|
||||
) {
|
||||
var instance = new VTColorPickerBottomSheetDialog(activity);
|
||||
var colorPickerAdapter = new ColorPickerAdapter(palette.colors, (adapter, color) -> {
|
||||
dest.color = color.color;
|
||||
ToastUtils.a("Цвет был изменён");
|
||||
themeEditAdapter.notifyDataSetChanged();
|
||||
instance.dismiss();
|
||||
});
|
||||
instance.setTitle(palette.name)
|
||||
.setAdapter(colorPickerAdapter, true)
|
||||
.show(PALETTES_EDITOR_TAG, true);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import static ru.vtosters.lite.themes.VTLColors.getTextPrimaryColor;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import ru.vtosters.lite.downloaders.OTADownloader;
|
||||
import ru.vtosters.lite.ui.vkui.ModalBottomSheetWrapper;
|
||||
import ru.vtosters.lite.utils.OTAUtils;
|
||||
|
||||
public class UpdateBottomSheetDialog extends ModalBottomSheetWrapper<UpdateBottomSheetDialog> {
|
||||
|
||||
private static final String TAG = "ota";
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
public UpdateBottomSheetDialog(Activity activity) {
|
||||
super(activity);
|
||||
this.mActivity = activity;
|
||||
}
|
||||
|
||||
public UpdateBottomSheetDialog setUpdateDescriptionText(String changelog) {
|
||||
var container = new LinearLayout(mActivity);
|
||||
var changelogView = new TextView(mActivity);
|
||||
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
changelogView.setPadding(0, dp2px(8), 0, 0);
|
||||
changelogView.setText(getString("changelog") + ": \n" + changelog);
|
||||
changelogView.setTextColor(getTextPrimaryColor());
|
||||
container.addView(changelogView, new LinearLayout.LayoutParams(-1, -2));
|
||||
|
||||
return setView(container);
|
||||
}
|
||||
|
||||
public static void create(Activity activity, OTAUtils helper) {
|
||||
new UpdateBottomSheetDialog(activity)
|
||||
.setTitle(getString("newversion") + " " + helper.getNewVersionName())
|
||||
.setUpdateDescriptionText(helper.getUpdateDescription())
|
||||
.setPositiveButton(getString("updateanddownload"), () -> {
|
||||
OTADownloader.downloadBuild(helper.getDownloadUrl());
|
||||
})
|
||||
.show(TAG);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import ru.vtosters.lite.ui.adapters.ColorPickerAdapter;
|
||||
import ru.vtosters.lite.ui.vkui.ModalBottomSheetWrapper;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class VTColorPickerBottomSheetDialog extends ModalBottomSheetWrapper<VTColorPickerBottomSheetDialog> {
|
||||
|
||||
private Activity mActivity;
|
||||
private LinearLayout mContainer;
|
||||
|
||||
public VTColorPickerBottomSheetDialog(Activity activity) {
|
||||
super(activity);
|
||||
this.mActivity = activity;
|
||||
mContainer = new LinearLayout(mActivity);
|
||||
mContainer.setLayoutParams(LayoutUtils.createLinear(-1, -1));
|
||||
mContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
}
|
||||
|
||||
public VTColorPickerBottomSheetDialog setAdapter(ColorPickerAdapter adapter, boolean searchMode) {
|
||||
var recyclerView = new RecyclerView(mActivity);
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
|
||||
var recyclerViewParams = LayoutUtils.createLinear(-1, -1);
|
||||
mContainer.addView(recyclerView, recyclerViewParams);
|
||||
|
||||
mBuilder.a(mContainer);
|
||||
return setView(mContainer);
|
||||
}
|
||||
|
||||
public LinearLayout getContainer() {
|
||||
return mContainer;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.copyright_post;
|
||||
import static ru.vtosters.lite.utils.Preferences.offline;
|
||||
|
||||
@@ -25,6 +26,21 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment {
|
||||
private void prefs() {
|
||||
findPreference("officialnewssett").setOnPreferenceClickListener(new openofficialsett());
|
||||
findPreference("cringecopyright").setEnabled(!copyright_post());
|
||||
|
||||
findPreference("spamfilters").setSummary(count(getPrefsValue("spamfilters")));
|
||||
findPreference("sourcenamefilter").setSummary(count(getPrefsValue("sourcenamefilter")));
|
||||
findPreference("linkfilter").setSummary(count(getPrefsValue("linkfilter")));
|
||||
}
|
||||
|
||||
private String count(String text) {
|
||||
// count comma separated words in string
|
||||
var count = text.split(", ").length;
|
||||
|
||||
if (count < 1 || text.isEmpty()) {
|
||||
return "Нет добавленных элементов";
|
||||
} else {
|
||||
return "Добавлено " + count + " элементов";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer;
|
||||
|
||||
import android.os.Bundle;
|
||||
@@ -9,6 +10,8 @@ import androidx.preference.Preference;
|
||||
|
||||
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
|
||||
|
||||
import ru.vtosters.lite.ui.dialogs.RoundingSeekbarDialog;
|
||||
|
||||
public class InterfaceFragment extends MaterialPreferenceToolbarFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
@@ -21,6 +24,17 @@ public class InterfaceFragment extends MaterialPreferenceToolbarFragment {
|
||||
findPreference("stories").setOnPreferenceClickListener(new restart());
|
||||
findPreference("swipe").setOnPreferenceClickListener(new restart());
|
||||
findPreference("is_likes_on_right").setOnPreferenceClickListener(new restart());
|
||||
|
||||
findPreference("customrounding").setOnPreferenceClickListener(preference -> {
|
||||
RoundingSeekbarDialog.dialog(getContext());
|
||||
return true;
|
||||
});
|
||||
|
||||
if (getPreferences().getInt("pic_rounding", 0) == 0) {
|
||||
findPreference("customrounding").setSummary("Отключено");
|
||||
} else {
|
||||
findPreference("customrounding").setSummary("Размер закругления: " + getPreferences().getInt("pic_rounding", 0) + "dp");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean restart(Preference preference) {
|
||||
|
||||
@@ -13,8 +13,10 @@ import static ru.vtosters.lite.utils.ThemesUtils.getAlertStyle;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@@ -40,40 +42,148 @@ import okhttp3.Request;
|
||||
import ru.vtosters.lite.downloaders.VideoDownloader;
|
||||
import ru.vtosters.lite.music.Scrobbler;
|
||||
import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter;
|
||||
import ru.vtosters.lite.utils.FileUriUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
public static void download(Context ctx) {
|
||||
AlertDialog.Builder alertDialog = new AlertDialog.Builder(ctx, getAlertStyle());
|
||||
alertDialog.setTitle("Введите ссылку на видео");
|
||||
private final int REQUEST_CODE_SET_DOWNLOAD_DIRECTORY = 665;
|
||||
private final int REQUEST_CODE_SET_MUSIC_DIRECTORY = 666;
|
||||
private final int REQUEST_CODE_SET_PHOTOS_DIRECTORY = 667;
|
||||
private final int REQUEST_CODE_SET_VIDEOS_DIRECTORY = 668;
|
||||
|
||||
final EditText input = new EditText(ctx);
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
input.setLayoutParams(lp);
|
||||
input.setTextColor(getTextAttr());
|
||||
input.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
alertDialog.setView(input);
|
||||
alertDialog.setPositiveButton("Скачать", (dialog, which) -> VideoDownloader.parseVideoLink(input.getText().toString(), ctx));
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(getIdentifier("preferences_media", "xml"));
|
||||
prefs();
|
||||
}
|
||||
|
||||
private void logout(Context ctx) {
|
||||
VkAlertDialog.Builder alertDialog = new VkAlertDialog.Builder(ctx);
|
||||
alertDialog.setTitle("Вы уверены?");
|
||||
alertDialog.setMessage("Вы действительно хотите выйти из аккаунта?");
|
||||
alertDialog.setPositiveButton("Да", (dialog, which) -> {
|
||||
Scrobbler.logout();
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
var path = data.getData();
|
||||
if (path != null) {
|
||||
var prefs = getPreferences();
|
||||
var editor = prefs.edit();
|
||||
var actualPath = FileUriUtils.getFullPathFromTreeUri(path, getContext());
|
||||
Log.d("MediaFragment", "onActivityResult: " + actualPath);
|
||||
Log.d("MediaFragment", "onActivityResult: " + requestCode);
|
||||
switch (requestCode) {
|
||||
case REQUEST_CODE_SET_DOWNLOAD_DIRECTORY:
|
||||
editor.putString("downloads_directory", actualPath);
|
||||
break;
|
||||
case REQUEST_CODE_SET_MUSIC_DIRECTORY:
|
||||
editor.putString("music_directory", actualPath);
|
||||
break;
|
||||
case REQUEST_CODE_SET_PHOTOS_DIRECTORY:
|
||||
editor.putString("photos_directory", actualPath);
|
||||
break;
|
||||
case REQUEST_CODE_SET_VIDEOS_DIRECTORY:
|
||||
editor.putString("videos_directory", actualPath);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
prefs();
|
||||
}
|
||||
|
||||
private void prefs() {
|
||||
findPreference("download_video").setOnPreferenceClickListener(new MediaFragment.download());
|
||||
findPreference("clearvideohistory").setOnPreferenceClickListener(preference -> {
|
||||
deleteVideoHistory();
|
||||
return true;
|
||||
});
|
||||
alertDialog.setNeutralButton("Нет", (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
findPreference("dateformat").setOnPreferenceChangeListener(new MediaFragment.restart());
|
||||
findPreference("lastfm_auth").setOnPreferenceClickListener(preference -> {
|
||||
if (isLoggedIn()) {
|
||||
logout(getContext());
|
||||
} else {
|
||||
lastfmAuth(getContext());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("downloads_directory").setSummary(
|
||||
"Текущая папка: " + Preferences.getDownloadsDir()
|
||||
);
|
||||
|
||||
findPreference("photos_directory").setSummary(
|
||||
"Текущая папка: " + Preferences.getPhotosDir()
|
||||
);
|
||||
|
||||
findPreference("videos_directory").setSummary(
|
||||
"Текущая папка: " + Preferences.getVideosDir()
|
||||
);
|
||||
|
||||
findPreference("music_directory").setSummary(
|
||||
"Текущая папка: " + Preferences.getMusicDir()
|
||||
);
|
||||
|
||||
findPreference("downloads_directory").setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_DOWNLOAD_DIRECTORY);
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("photos_directory").setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_PHOTOS_DIRECTORY);
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("videos_directory").setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_VIDEOS_DIRECTORY);
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("music_directory").setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_MUSIC_DIRECTORY);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary("Вы авторизованы как " + Scrobbler.getUserName());
|
||||
} else {
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
|
||||
findPreference("select_photo_search_engine").setOnPreferenceClickListener(preference -> {
|
||||
var items = Arrays.asList(
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("yandex", "drawable"), "Yandex"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("google", "drawable"), "Google"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("microsoft", "drawable"), "Bing")
|
||||
);
|
||||
|
||||
var alert = new VkAlertDialog.Builder(getActivity())
|
||||
.create();
|
||||
|
||||
var listView = (ListView) LayoutInflater.from(getContext()).inflate(com.vtosters.lite.R.layout.abc_select_dialog_material, null, false);
|
||||
var adapter = new ImagineArrayAdapter(getContext(), items, i -> {
|
||||
getPreferences().edit().putInt("search_engine", i).apply();
|
||||
alert.dismiss();
|
||||
});
|
||||
adapter.setSelected(getPreferences().getInt("search_engine", 0));
|
||||
listView.setAdapter(adapter);
|
||||
alert.setView(listView);
|
||||
alert.show();
|
||||
|
||||
return true;
|
||||
});
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
alert.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(getResources().getColor(com.vtosters.lite.R.color.red));
|
||||
}
|
||||
|
||||
private void lastfmAuth(Context ctx) {
|
||||
@@ -115,6 +225,22 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
}
|
||||
|
||||
private void logout(Context ctx) {
|
||||
VkAlertDialog.Builder alertDialog = new VkAlertDialog.Builder(ctx);
|
||||
alertDialog.setTitle("Вы уверены?");
|
||||
alertDialog.setMessage("Вы действительно хотите выйти из аккаунта?");
|
||||
alertDialog.setPositiveButton("Да", (dialog, which) -> {
|
||||
Scrobbler.logout();
|
||||
});
|
||||
alertDialog.setNeutralButton("Нет", (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
});
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
alert.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(getResources().getColor(com.vtosters.lite.R.color.red));
|
||||
}
|
||||
|
||||
public static void deleteVideoHistory() {
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
@@ -139,57 +265,22 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
sendToast("История просмотра видео очищена");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(getIdentifier("preferences_media", "xml"));
|
||||
prefs();
|
||||
}
|
||||
public static void download(Context ctx) {
|
||||
AlertDialog.Builder alertDialog = new AlertDialog.Builder(ctx, getAlertStyle());
|
||||
alertDialog.setTitle("Введите ссылку на видео");
|
||||
|
||||
private void prefs() {
|
||||
findPreference("download_video").setOnPreferenceClickListener(new MediaFragment.download());
|
||||
findPreference("clearvideohistory").setOnPreferenceClickListener(preference -> {
|
||||
deleteVideoHistory();
|
||||
return true;
|
||||
});
|
||||
findPreference("dateformat").setOnPreferenceChangeListener(new MediaFragment.restart());
|
||||
findPreference("lastfm_auth").setOnPreferenceClickListener(preference -> {
|
||||
if (isLoggedIn()) {
|
||||
logout(getContext());
|
||||
} else {
|
||||
lastfmAuth(getContext());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary("Вы авторизованы как " + Scrobbler.getUserName());
|
||||
} else {
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
|
||||
findPreference("select_photo_search_engine").setOnPreferenceClickListener(preference -> {
|
||||
var items = Arrays.asList(
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("yandex", "drawable"), "Yandex"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("google", "drawable"), "Google"),
|
||||
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("microsoft", "drawable"), "Bing")
|
||||
);
|
||||
|
||||
var alert = new VkAlertDialog.Builder(getActivity())
|
||||
.create();
|
||||
|
||||
var listView = (ListView) LayoutInflater.from(getContext()).inflate(com.vtosters.lite.R.layout.abc_select_dialog_material, null, false);
|
||||
var adapter = new ImagineArrayAdapter(getContext(), items, i -> {
|
||||
getPreferences().edit().putInt("search_engine", i).apply();
|
||||
alert.dismiss();
|
||||
});
|
||||
adapter.setSelected(getPreferences().getInt("search_engine", 0));
|
||||
listView.setAdapter(adapter);
|
||||
alert.setView(listView);
|
||||
alert.show();
|
||||
|
||||
return true;
|
||||
});
|
||||
final EditText input = new EditText(ctx);
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
input.setLayoutParams(lp);
|
||||
input.setTextColor(getTextAttr());
|
||||
input.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
alertDialog.setView(input);
|
||||
alertDialog.setPositiveButton("Скачать", (dialog, which) -> VideoDownloader.parseVideoLink(input.getText().toString(), ctx));
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
}
|
||||
|
||||
private class download implements Preference.OnPreferenceClickListener {
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.PalettesManager;
|
||||
import ru.vtosters.lite.ui.adapters.PalettesAdapter;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class PalettesManagerFragment extends BaseToolbarFragment {
|
||||
|
||||
private final PalettesManager mManager = PalettesManager.getInstance();
|
||||
|
||||
private PalettesAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
public View onCreateContent(@NonNull LayoutInflater inflater, @Nullable Bundle bundle) {
|
||||
setTitle("Палитры");
|
||||
|
||||
var container = new FrameLayout(getContext());
|
||||
|
||||
mAdapter = new PalettesAdapter();
|
||||
|
||||
var recyclerView = new RecyclerView(getContext());
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
container.addView(recyclerView, LayoutUtils.createFrame(-1, -1));
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@ import androidx.preference.Preference;
|
||||
import com.vk.navigation.Navigator;
|
||||
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
|
||||
public class ThemesFragment extends MaterialPreferenceToolbarFragment {
|
||||
|
||||
@Override
|
||||
@@ -27,17 +27,6 @@ public class ThemesFragment extends MaterialPreferenceToolbarFragment {
|
||||
}
|
||||
|
||||
private void prefs() {
|
||||
var themesPreference = findPreference("themes");
|
||||
var themesManager = ThemesManager.getInstance();
|
||||
// if (themesManager.getThemesCount() > 0)
|
||||
// themesPreference.setSummary(themesManager.getCurrentTheme().name);
|
||||
themesPreference.setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Navigator(ThemesManagerFragment.class).b(getContext());
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getContext().startActivity(intent);
|
||||
return false;
|
||||
});
|
||||
|
||||
findPreference("navbar").setOnPreferenceClickListener(new restart());
|
||||
findPreference("milkshake").setOnPreferenceClickListener(new restart());
|
||||
findPreference("darktheme").setOnPreferenceChangeListener(new restartdark());
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.themes.VTLColors.getAccentColor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.navigation.Navigator;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.ui.adapters.ThemesAdapter;
|
||||
import ru.vtosters.lite.ui.dialogs.EditTextDialog;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class ThemesManagerFragment extends BaseToolbarFragment {
|
||||
|
||||
private static final int IMPORT_REQUEST_CODE = 0x1;
|
||||
|
||||
private ThemesAdapter mAdapter;
|
||||
private ThemesManager mManager = ThemesManager.getInstance();
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
switch (requestCode) {
|
||||
case IMPORT_REQUEST_CODE:
|
||||
if (resultCode != Activity.RESULT_OK)
|
||||
return;
|
||||
try {
|
||||
var data = intent.getData();
|
||||
if (data != null) {
|
||||
mManager.copy(getContext().getContentResolver(), data);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
} else {
|
||||
throw new IOException("Error while getting file path");
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a("Не удалось импортировать тему");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateContent(@NonNull LayoutInflater inflater, @Nullable Bundle bundle) {
|
||||
setTitle("Темы");
|
||||
|
||||
var container = new FrameLayout(getContext());
|
||||
|
||||
mAdapter = new ThemesAdapter();
|
||||
|
||||
var recyclerView = new RecyclerView(getContext());
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
container.addView(recyclerView, LayoutUtils.createFrame(-1, -1));
|
||||
|
||||
var buttonsContainer = new LinearLayout(getContext());
|
||||
buttonsContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
var params = LayoutUtils.createFrame(-2, -2);
|
||||
params.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
||||
params.setMargins(0, 0, 0, dp2px(12f));
|
||||
container.addView(buttonsContainer, params);
|
||||
|
||||
var addNewTheme = new FloatingActionButton(getContext());
|
||||
addNewTheme.setImageResource(getIdentifier("ic_add_24", "drawable"));
|
||||
addNewTheme.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
addNewTheme.setOnClickListener(v -> {
|
||||
EditTextDialog.create(v.getContext(), "Новая тема", "Название новой темы", null, (dialog, which, editText) -> {
|
||||
var name = editText.getText().toString();
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
ToastUtils.a("Название не может быть пустым");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mManager.create(requireActivity(), name);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a("Не удалось изменить название темы");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
buttonsContainer.addView(addNewTheme, LayoutUtils.createLinear(-2, -2));
|
||||
|
||||
buttonsContainer.addView(new View(getContext()), LayoutUtils.createLinear(dp2px(5), 0));
|
||||
|
||||
var importTheme = new FloatingActionButton(getContext());
|
||||
importTheme.setImageResource(getIdentifier("ic_import", "drawable"));
|
||||
importTheme.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
importTheme.setImageTintList(ColorStateList.valueOf(Color.WHITE));
|
||||
importTheme.setOnClickListener(v -> {
|
||||
var intent = new Intent(Intent.ACTION_GET_CONTENT)
|
||||
.setType("*/*")
|
||||
.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
startActivityForResult(Intent.createChooser(intent, "Выберите тему (.vtlt, .svt)"), IMPORT_REQUEST_CODE);
|
||||
ToastUtils.a("Возможен импорт тем из сторонней модификации ВК Sova V RE");
|
||||
});
|
||||
buttonsContainer.addView(importTheme, LayoutUtils.createLinear(-2, -2));
|
||||
|
||||
buttonsContainer.addView(new View(getContext()), LayoutUtils.createLinear(dp2px(5), 0));
|
||||
|
||||
var openPalettes = new FloatingActionButton(getContext());
|
||||
openPalettes.setImageResource(R.drawable.ic_palette_outline_28);
|
||||
openPalettes.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
|
||||
openPalettes.setOnClickListener(v -> {
|
||||
var intent = new Navigator(PalettesManagerFragment.class, new Bundle()).b(getContext());
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getContext().startActivity(intent);
|
||||
});
|
||||
buttonsContainer.addView(openPalettes, LayoutUtils.createLinear(-2, -2));
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -65,8 +65,6 @@ import ru.vtosters.lite.utils.CacheUtils;
|
||||
import ru.vtosters.lite.utils.SSFSUtils;
|
||||
|
||||
public class VTSettings extends MaterialPreferenceToolbarFragment {
|
||||
public int hideitems = 0;
|
||||
|
||||
public static String getValAsString(String stringid, Boolean value) {
|
||||
if (disableSettingsSumms()) return null;
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatRadioButton;
|
||||
|
||||
public class NoTouchRadioButton extends AppCompatRadioButton {
|
||||
public NoTouchRadioButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public NoTouchRadioButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public NoTouchRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.Checkable;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatImageButton;
|
||||
|
||||
public class VTLCheckableButton extends AppCompatImageButton implements Checkable {
|
||||
|
||||
private boolean mIsChecked;
|
||||
|
||||
public VTLCheckableButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public VTLCheckableButton(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
}
|
||||
|
||||
public VTLCheckableButton(Context context, AttributeSet attributeSet, int i) {
|
||||
super(context, attributeSet, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
var state = new CustomState(super.onSaveInstanceState());
|
||||
state.setChecked(mIsChecked);
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof CustomState) {
|
||||
var customState = ((CustomState) state);
|
||||
super.onRestoreInstanceState(customState.getSuperState());
|
||||
mIsChecked = customState.isChecked();
|
||||
return;
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return this.mIsChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
mIsChecked = checked;
|
||||
refreshDrawableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] onCreateDrawableState(int extraSpace) {
|
||||
return mIsChecked
|
||||
? View.mergeDrawableStates(super.onCreateDrawableState(extraSpace + 1), new int[] { android.R.attr.state_checked })
|
||||
: super.onCreateDrawableState(extraSpace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggle() {
|
||||
setChecked(!mIsChecked);
|
||||
}
|
||||
|
||||
static class CustomState extends View.BaseSavedState {
|
||||
private boolean checked;
|
||||
|
||||
public CustomState(Parcelable source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public CustomState(Parcel source) {
|
||||
super(source);
|
||||
checked = source.readInt() != 0;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeInt(checked ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
public class ColorCircle {
|
||||
private float x, y;
|
||||
private float[] hsv = new float[3];
|
||||
private float[] hsvClone;
|
||||
private int color;
|
||||
|
||||
public ColorCircle(float x, float y, float[] hsv) {
|
||||
set(x, y, hsv);
|
||||
}
|
||||
|
||||
public double sqDist(float x, float y) {
|
||||
double dx = this.x - x;
|
||||
double dy = this.y - y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public float[] getHsv() {
|
||||
return hsv;
|
||||
}
|
||||
|
||||
public float[] getHsvWithLightness(float lightness) {
|
||||
if (hsvClone == null)
|
||||
hsvClone = hsv.clone();
|
||||
hsvClone[0] = hsv[0];
|
||||
hsvClone[1] = hsv[1];
|
||||
hsvClone[2] = lightness;
|
||||
return hsvClone;
|
||||
}
|
||||
|
||||
public void set(float x, float y, float[] hsv) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.hsv[0] = hsv[0];
|
||||
this.hsv[1] = hsv[1];
|
||||
this.hsv[2] = hsv[2];
|
||||
this.color = Color.HSVToColor(this.hsv);
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
|
||||
import ru.vtosters.lite.ui.views.flask.builder.PaintBuilder;
|
||||
|
||||
public class ColorCircleDrawable extends ColorDrawable {
|
||||
private float strokeWidth;
|
||||
private Paint strokePaint = PaintBuilder.newPaint().style(Paint.Style.STROKE).stroke(strokeWidth).color(0xff9e9e9e).build();
|
||||
private Paint fillPaint = PaintBuilder.newPaint().style(Paint.Style.FILL).color(0).build();
|
||||
private Paint fillBackPaint = PaintBuilder.newPaint().shader(PaintBuilder.createAlphaPatternShader(26)).build();
|
||||
|
||||
public ColorCircleDrawable(int color) {
|
||||
super(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
canvas.drawColor(0);
|
||||
|
||||
int width = canvas.getWidth();
|
||||
float radius = width / 2f;
|
||||
strokeWidth = radius / 8f;
|
||||
|
||||
this.strokePaint.setStrokeWidth(strokeWidth);
|
||||
this.fillPaint.setColor(getColor());
|
||||
canvas.drawCircle(radius, radius, radius - strokeWidth, fillBackPaint);
|
||||
canvas.drawCircle(radius, radius, radius - strokeWidth, fillPaint);
|
||||
canvas.drawCircle(radius, radius, radius - strokeWidth, strokePaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(int color) {
|
||||
super.setColor(color);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
@@ -1,433 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.ui.views.flask.builder.PaintBuilder;
|
||||
import ru.vtosters.lite.ui.views.flask.render.ColorWheelRenderOption;
|
||||
import ru.vtosters.lite.ui.views.flask.render.ColorWheelRenderer;
|
||||
import ru.vtosters.lite.ui.views.flask.render.SimpleColorWheelRenderer;
|
||||
|
||||
public class ColorPickerView extends View {
|
||||
private static final float STROKE_RATIO = 1.5f;
|
||||
|
||||
private AlertDialog dialog;
|
||||
private Bitmap colorWheel;
|
||||
private Canvas colorWheelCanvas;
|
||||
private Bitmap currentColor;
|
||||
private Canvas currentColorCanvas;
|
||||
private boolean showBorder;
|
||||
private int density = 8;
|
||||
|
||||
private float lightness = 1;
|
||||
private float alpha = 1;
|
||||
private int backgroundColor = 0x00000000;
|
||||
|
||||
private Integer initialColors[] = new Integer[]{null, null, null, null, null};
|
||||
private int colorSelection = 0;
|
||||
private Integer initialColor;
|
||||
private Paint colorWheelFill = PaintBuilder.newPaint().color(0).build();
|
||||
private Paint selectorStroke = PaintBuilder.newPaint().color(0).build();
|
||||
private Paint alphaPatternPaint = PaintBuilder.newPaint().build();
|
||||
private ColorCircle currentColorCircle;
|
||||
|
||||
private ArrayList<OnColorChangedListener> colorChangedListeners = new ArrayList<>();
|
||||
private ArrayList<OnColorSelectedListener> listeners = new ArrayList<>();
|
||||
|
||||
|
||||
private LinearLayout colorPreview;
|
||||
|
||||
private ColorWheelRenderer renderer;
|
||||
|
||||
public ColorPickerView(Context context) {
|
||||
super(context);
|
||||
initWith();
|
||||
}
|
||||
|
||||
private void initWith() {
|
||||
density = 10;
|
||||
initialColor = 0xffffffff;
|
||||
|
||||
renderer = new SimpleColorWheelRenderer();
|
||||
|
||||
setDensity(density);
|
||||
setInitialColor(initialColor, true);
|
||||
}
|
||||
|
||||
public void setDialog(AlertDialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||
super.onWindowFocusChanged(hasWindowFocus);
|
||||
updateColorWheel();
|
||||
currentColorCircle = findNearestByColor(initialColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
updateColorWheel();
|
||||
currentColorCircle = findNearestByColor(initialColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
updateColorWheel();
|
||||
}
|
||||
|
||||
private void updateColorWheel() {
|
||||
int width = getMeasuredWidth();
|
||||
int height = getMeasuredHeight();
|
||||
|
||||
if (height < width)
|
||||
width = height;
|
||||
if (width <= 0)
|
||||
return;
|
||||
if (colorWheel == null || colorWheel.getWidth() != width) {
|
||||
colorWheel = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
|
||||
colorWheelCanvas = new Canvas(colorWheel);
|
||||
alphaPatternPaint.setShader(PaintBuilder.createAlphaPatternShader(26));
|
||||
}
|
||||
if (currentColor == null || currentColor.getWidth() != width) {
|
||||
currentColor = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
|
||||
currentColorCanvas = new Canvas(currentColor);
|
||||
}
|
||||
drawColorWheel();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void drawColorWheel() {
|
||||
colorWheelCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
currentColorCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
|
||||
if (renderer == null) return;
|
||||
|
||||
float half = colorWheelCanvas.getWidth() / 2f;
|
||||
float strokeWidth = STROKE_RATIO * (1f + ColorWheelRenderer.GAP_PERCENTAGE);
|
||||
float maxRadius = half - strokeWidth - half / density;
|
||||
float cSize = maxRadius / (density - 1) / 2;
|
||||
|
||||
ColorWheelRenderOption colorWheelRenderOption = renderer.getRenderOption();
|
||||
colorWheelRenderOption.density = this.density;
|
||||
colorWheelRenderOption.maxRadius = maxRadius;
|
||||
colorWheelRenderOption.cSize = cSize;
|
||||
colorWheelRenderOption.strokeWidth = strokeWidth;
|
||||
colorWheelRenderOption.alpha = alpha;
|
||||
colorWheelRenderOption.lightness = lightness;
|
||||
colorWheelRenderOption.targetCanvas = colorWheelCanvas;
|
||||
|
||||
renderer.initWith(colorWheelRenderOption);
|
||||
renderer.draw();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int width = 0;
|
||||
if (widthMode == MeasureSpec.UNSPECIFIED)
|
||||
width = widthMeasureSpec;
|
||||
else if (widthMode == MeasureSpec.AT_MOST)
|
||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
else if (widthMode == MeasureSpec.EXACTLY)
|
||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int height = 0;
|
||||
if (heightMode == MeasureSpec.UNSPECIFIED)
|
||||
height = heightMeasureSpec;
|
||||
else if (heightMode == MeasureSpec.AT_MOST)
|
||||
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
else if (heightMode == MeasureSpec.EXACTLY)
|
||||
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
int squareDimen = width;
|
||||
if (height < width)
|
||||
squareDimen = height;
|
||||
setMeasuredDimension(squareDimen, squareDimen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
int lastSelectedColor = getSelectedColor();
|
||||
currentColorCircle = findNearestByPosition(event.getX(), event.getY());
|
||||
int selectedColor = getSelectedColor();
|
||||
|
||||
callOnColorChangedListeners(lastSelectedColor, selectedColor);
|
||||
|
||||
initialColor = selectedColor;
|
||||
updateColorWheel();
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_UP: {
|
||||
int selectedColor = getSelectedColor();
|
||||
if (listeners != null) {
|
||||
for (OnColorSelectedListener listener : listeners) {
|
||||
try {
|
||||
listener.onColorSelected(dialog, selectedColor);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
setColorPreviewColor(selectedColor);
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void callOnColorChangedListeners(int oldColor, int newColor) {
|
||||
if (colorChangedListeners != null && oldColor != newColor) {
|
||||
for (OnColorChangedListener listener : colorChangedListeners) {
|
||||
try {
|
||||
listener.onColorChanged(newColor);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawColor(backgroundColor);
|
||||
|
||||
float maxRadius = canvas.getWidth() / (1f + ColorWheelRenderer.GAP_PERCENTAGE);
|
||||
float size = maxRadius / density / 2;
|
||||
if (colorWheel != null && currentColorCircle != null) {
|
||||
colorWheelFill.setColor(Color.HSVToColor(currentColorCircle.getHsvWithLightness(this.lightness)));
|
||||
colorWheelFill.setAlpha((int) (alpha * 0xff));
|
||||
|
||||
// a separate canvas is used to erase an issue with the alpha pattern around the edges
|
||||
// draw circle slightly larger than it needs to be, then erase edges to proper dimensions
|
||||
currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + 4, alphaPatternPaint);
|
||||
currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + 4, colorWheelFill);
|
||||
|
||||
selectorStroke = PaintBuilder.newPaint().color(0xffffffff).style(Paint.Style.STROKE).stroke(size * (STROKE_RATIO - 1)).xPerMode(PorterDuff.Mode.CLEAR).build();
|
||||
|
||||
if (showBorder) colorWheelCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + (selectorStroke.getStrokeWidth() / 2f), selectorStroke);
|
||||
canvas.drawBitmap(colorWheel, 0, 0, null);
|
||||
|
||||
currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + (selectorStroke.getStrokeWidth() / 2f), selectorStroke);
|
||||
canvas.drawBitmap(currentColor, 0, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
private ColorCircle findNearestByPosition(float x, float y) {
|
||||
ColorCircle near = null;
|
||||
double minDist = Double.MAX_VALUE;
|
||||
|
||||
for (ColorCircle colorCircle : renderer.getColorCircleList()) {
|
||||
double dist = colorCircle.sqDist(x, y);
|
||||
if (minDist > dist) {
|
||||
minDist = dist;
|
||||
near = colorCircle;
|
||||
}
|
||||
}
|
||||
|
||||
return near;
|
||||
}
|
||||
|
||||
private ColorCircle findNearestByColor(int color) {
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(color, hsv);
|
||||
ColorCircle near = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
double x = hsv[1] * Math.cos(hsv[0] * Math.PI / 180);
|
||||
double y = hsv[1] * Math.sin(hsv[0] * Math.PI / 180);
|
||||
|
||||
for (ColorCircle colorCircle : renderer.getColorCircleList()) {
|
||||
float[] hsv1 = colorCircle.getHsv();
|
||||
double x1 = hsv1[1] * Math.cos(hsv1[0] * Math.PI / 180);
|
||||
double y1 = hsv1[1] * Math.sin(hsv1[0] * Math.PI / 180);
|
||||
double dx = x - x1;
|
||||
double dy = y - y1;
|
||||
double dist = dx * dx + dy * dy;
|
||||
if (dist < minDiff) {
|
||||
minDiff = dist;
|
||||
near = colorCircle;
|
||||
}
|
||||
}
|
||||
|
||||
return near;
|
||||
}
|
||||
|
||||
public int getSelectedColor() {
|
||||
int color = 0;
|
||||
if (currentColorCircle != null)
|
||||
color = Utils.colorAtLightness(currentColorCircle.getColor(), this.lightness);
|
||||
return Utils.adjustAlpha(this.alpha, color);
|
||||
}
|
||||
|
||||
public Integer[] getAllColors() {
|
||||
return initialColors;
|
||||
}
|
||||
|
||||
public void setInitialColors(Integer[] colors, int selectedColor) {
|
||||
this.initialColors = colors;
|
||||
this.colorSelection = selectedColor;
|
||||
Integer initialColor = this.initialColors[this.colorSelection];
|
||||
if (initialColor == null) initialColor = 0xffffffff;
|
||||
setInitialColor(initialColor, true);
|
||||
}
|
||||
|
||||
public void setInitialColor(int color, boolean updateText) {
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(color, hsv);
|
||||
|
||||
this.alpha = Utils.getAlphaPercent(color);
|
||||
this.lightness = hsv[2];
|
||||
this.initialColors[this.colorSelection] = color;
|
||||
this.initialColor = color;
|
||||
setColorPreviewColor(color);
|
||||
currentColorCircle = findNearestByColor(color);
|
||||
}
|
||||
|
||||
public void setLightness(float lightness) {
|
||||
int lastSelectedColor = getSelectedColor();
|
||||
|
||||
this.lightness = lightness;
|
||||
if (currentColorCircle != null) {
|
||||
this.initialColor = Color.HSVToColor(Utils.alphaValueAsInt(this.alpha), currentColorCircle.getHsvWithLightness(lightness));
|
||||
|
||||
callOnColorChangedListeners(lastSelectedColor, this.initialColor);
|
||||
|
||||
updateColorWheel();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor(int color, boolean updateText) {
|
||||
setInitialColor(color, updateText);
|
||||
updateColorWheel();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setAlphaValue(float alpha) {
|
||||
int lastSelectedColor = getSelectedColor();
|
||||
|
||||
this.alpha = alpha;
|
||||
this.initialColor = Color.HSVToColor(Utils.alphaValueAsInt(this.alpha), currentColorCircle.getHsvWithLightness(this.lightness));
|
||||
|
||||
callOnColorChangedListeners(lastSelectedColor, this.initialColor);
|
||||
|
||||
updateColorWheel();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void addOnColorChangedListener(OnColorChangedListener listener) {
|
||||
this.colorChangedListeners.add(listener);
|
||||
}
|
||||
|
||||
public void addOnColorSelectedListener(OnColorSelectedListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void setDensity(int density) {
|
||||
this.density = Math.max(2, density);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setColorPreview(LinearLayout colorPreview, Integer selectedColor) {
|
||||
if (colorPreview == null)
|
||||
return;
|
||||
this.colorPreview = colorPreview;
|
||||
if (selectedColor == null)
|
||||
selectedColor = 0;
|
||||
int children = colorPreview.getChildCount();
|
||||
if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < children; i++) {
|
||||
View childView = colorPreview.getChildAt(i);
|
||||
if (!(childView instanceof LinearLayout))
|
||||
continue;
|
||||
LinearLayout childLayout = (LinearLayout) childView;
|
||||
if (i == selectedColor) {
|
||||
childLayout.setBackgroundColor(Color.WHITE);
|
||||
}
|
||||
ImageView childImage = childLayout.findViewWithTag("image_preview");
|
||||
childImage.setClickable(true);
|
||||
childImage.setTag(i);
|
||||
childImage.setOnClickListener(v -> {
|
||||
if (v == null)
|
||||
return;
|
||||
Object tag = v.getTag();
|
||||
if (tag == null || !(tag instanceof Integer))
|
||||
return;
|
||||
setSelectedColor((int) tag);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedColor(int previewNumber) {
|
||||
if (initialColors == null || initialColors.length < previewNumber)
|
||||
return;
|
||||
this.colorSelection = previewNumber;
|
||||
setHighlightedColor(previewNumber);
|
||||
Integer color = initialColors[previewNumber];
|
||||
if (color == null)
|
||||
return;
|
||||
setColor(color, true);
|
||||
}
|
||||
|
||||
public void setShowBorder(boolean showBorder) {
|
||||
this.showBorder = showBorder;
|
||||
}
|
||||
|
||||
private void setHighlightedColor(int previewNumber) {
|
||||
int children = colorPreview.getChildCount();
|
||||
if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < children; i++) {
|
||||
View childView = colorPreview.getChildAt(i);
|
||||
if (!(childView instanceof LinearLayout))
|
||||
continue;
|
||||
LinearLayout childLayout = (LinearLayout) childView;
|
||||
if (i == previewNumber) {
|
||||
childLayout.setBackgroundColor(Color.WHITE);
|
||||
} else {
|
||||
childLayout.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setColorPreviewColor(int newColor) {
|
||||
if (colorPreview == null || initialColors == null || colorSelection > initialColors.length || initialColors[colorSelection] == null)
|
||||
return;
|
||||
|
||||
int children = colorPreview.getChildCount();
|
||||
if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
|
||||
return;
|
||||
|
||||
View childView = colorPreview.getChildAt(colorSelection);
|
||||
if (!(childView instanceof LinearLayout))
|
||||
return;
|
||||
LinearLayout childLayout = (LinearLayout) childView;
|
||||
ImageView childImage = childLayout.findViewWithTag("image_preview");
|
||||
childImage.setImageDrawable(new ColorCircleDrawable(newColor));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask;
|
||||
|
||||
public interface OnColorChangedListener {
|
||||
void onColorChanged(int selectedColor);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public interface OnColorSelectedListener {
|
||||
void onColorSelected(AlertDialog dialog, int selectedColor);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
/**
|
||||
* Created by Charles Andersons on 4/17/15.
|
||||
*/
|
||||
public class Utils {
|
||||
public static float getAlphaPercent(int argb) {
|
||||
return Color.alpha(argb) / 255f;
|
||||
}
|
||||
|
||||
public static int alphaValueAsInt(float alpha) {
|
||||
return Math.round(alpha * 255);
|
||||
}
|
||||
|
||||
public static int adjustAlpha(float alpha, int color) {
|
||||
return alphaValueAsInt(alpha) << 24 | (0x00ffffff & color);
|
||||
}
|
||||
|
||||
public static int colorAtLightness(int color, float lightness) {
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(color, hsv);
|
||||
hsv[2] = lightness;
|
||||
return Color.HSVToColor(hsv);
|
||||
}
|
||||
|
||||
public static float lightnessOfColor(int color) {
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(color, hsv);
|
||||
return hsv[2];
|
||||
}
|
||||
|
||||
public static String getHexString(int color, boolean showAlpha) {
|
||||
int base = showAlpha ? 0xFFFFFFFF : 0xFFFFFF;
|
||||
String format = showAlpha ? "#%08X" : "#%06X";
|
||||
return String.format(format, (base & color)).toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask.builder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
|
||||
import ru.vtosters.lite.ui.views.flask.ColorPickerView;
|
||||
import ru.vtosters.lite.ui.views.flask.OnColorChangedListener;
|
||||
import ru.vtosters.lite.ui.views.flask.OnColorSelectedListener;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class ColorPickerDialogBuilder {
|
||||
private Context context;
|
||||
private VkAlertDialog.Builder builder;
|
||||
private LinearLayout pickerContainer;
|
||||
private ColorPickerView colorPickerView;
|
||||
private LinearLayout colorPreview;
|
||||
|
||||
private boolean isBorderEnabled = true;
|
||||
private Integer[] initialColor = new Integer[]{null, null, null, null, null};
|
||||
|
||||
private ColorPickerDialogBuilder(Context context) {
|
||||
this.context = context;
|
||||
builder = new VkAlertDialog.Builder(context);
|
||||
pickerContainer = new LinearLayout(context);
|
||||
pickerContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
pickerContainer.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
|
||||
LinearLayout.LayoutParams layoutParamsForColorPickerView = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
|
||||
layoutParamsForColorPickerView.weight = 1;
|
||||
colorPickerView = new ColorPickerView(context);
|
||||
|
||||
pickerContainer.addView(colorPickerView, layoutParamsForColorPickerView);
|
||||
}
|
||||
|
||||
public static ColorPickerDialogBuilder with(Context context) {
|
||||
return new ColorPickerDialogBuilder(context);
|
||||
}
|
||||
|
||||
public ColorPickerDialogBuilder setTitle(String title) {
|
||||
builder.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorPickerDialogBuilder setTitle(int titleId) {
|
||||
builder.setTitle(titleId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorPickerDialogBuilder density(int density) {
|
||||
colorPickerView.setDensity(density);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorPickerDialogBuilder setOnColorChangedListener(OnColorChangedListener onColorChangedListener) {
|
||||
colorPickerView.addOnColorChangedListener(onColorChangedListener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorPickerDialogBuilder setOnColorSelectedListener(OnColorSelectedListener onColorSelectedListener) {
|
||||
colorPickerView.addOnColorSelectedListener(onColorSelectedListener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorPickerDialogBuilder showBorder(boolean showBorder) {
|
||||
isBorderEnabled = showBorder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertDialog build() {
|
||||
colorPickerView.setInitialColors(initialColor, getStartOffset(initialColor));
|
||||
colorPickerView.setShowBorder(isBorderEnabled);
|
||||
|
||||
colorPreview = new LinearLayout(context);
|
||||
colorPreview.setLayoutParams(LayoutUtils.createLinear(-2, AndroidUtils.dp2px(40)));
|
||||
colorPreview.setOrientation(LinearLayout.HORIZONTAL);
|
||||
colorPreview.setGravity(Gravity.CENTER);
|
||||
pickerContainer.addView(colorPreview);
|
||||
|
||||
colorPickerView.setColorPreview(colorPreview, getStartOffset(initialColor));
|
||||
|
||||
var dialog = builder.create();
|
||||
dialog.setView(pickerContainer);
|
||||
colorPickerView.setDialog(dialog);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private Integer getStartOffset(Integer[] colors) {
|
||||
Integer start = 0;
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
if (colors[i] == null) {
|
||||
return start;
|
||||
}
|
||||
start = (i + 1) / 2;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask.builder;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Shader;
|
||||
|
||||
public class PaintBuilder {
|
||||
public static PaintHolder newPaint() {
|
||||
return new PaintHolder();
|
||||
}
|
||||
|
||||
public static class PaintHolder {
|
||||
private Paint paint;
|
||||
|
||||
private PaintHolder() {
|
||||
this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
|
||||
public PaintHolder color(int color) {
|
||||
this.paint.setColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaintHolder antiAlias(boolean flag) {
|
||||
this.paint.setAntiAlias(flag);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaintHolder style(Paint.Style style) {
|
||||
this.paint.setStyle(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaintHolder mode(PorterDuff.Mode mode) {
|
||||
this.paint.setXfermode(new PorterDuffXfermode(mode));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaintHolder stroke(float width) {
|
||||
this.paint.setStrokeWidth(width);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaintHolder xPerMode(PorterDuff.Mode mode) {
|
||||
this.paint.setXfermode(new PorterDuffXfermode(mode));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaintHolder shader(Shader shader) {
|
||||
this.paint.setShader(shader);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Paint build() {
|
||||
return this.paint;
|
||||
}
|
||||
}
|
||||
|
||||
public static Shader createAlphaPatternShader(int size) {
|
||||
size /= 2;
|
||||
size = Math.max(8, size * 2);
|
||||
return new BitmapShader(createAlphaBackgroundPattern(size), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
||||
}
|
||||
|
||||
private static Bitmap createAlphaBackgroundPattern(int size) {
|
||||
Paint alphaPatternPaint = PaintBuilder.newPaint().build();
|
||||
Bitmap bm = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bm);
|
||||
int s = Math.round(size / 2f);
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if ((i + j) % 2 == 0) alphaPatternPaint.setColor(0xffffffff);
|
||||
else alphaPatternPaint.setColor(0xffd0d0d0);
|
||||
c.drawRect(i * s, j * s, (i + 1) * s, (j + 1) * s, alphaPatternPaint);
|
||||
}
|
||||
return bm;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.ui.views.flask.ColorCircle;
|
||||
|
||||
public abstract class AbsColorWheelRenderer implements ColorWheelRenderer {
|
||||
protected ColorWheelRenderOption colorWheelRenderOption;
|
||||
protected List<ColorCircle> colorCircleList = new ArrayList<>();
|
||||
|
||||
public void initWith(ColorWheelRenderOption colorWheelRenderOption) {
|
||||
this.colorWheelRenderOption = colorWheelRenderOption;
|
||||
this.colorCircleList.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorWheelRenderOption getRenderOption() {
|
||||
if (colorWheelRenderOption == null) colorWheelRenderOption = new ColorWheelRenderOption();
|
||||
return colorWheelRenderOption;
|
||||
}
|
||||
|
||||
public List<ColorCircle> getColorCircleList() {
|
||||
return colorCircleList;
|
||||
}
|
||||
|
||||
protected int getAlphaValueAsInt() {
|
||||
return Math.round(colorWheelRenderOption.alpha * 255);
|
||||
}
|
||||
|
||||
protected int calcTotalCount(float radius, float size) {
|
||||
return Math.max(1, (int) ((1f - GAP_PERCENTAGE) * Math.PI / (Math.asin(size / radius)) + 0.5f));
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask.render;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
|
||||
public class ColorWheelRenderOption {
|
||||
public int density;
|
||||
public float maxRadius;
|
||||
public float cSize, strokeWidth, alpha, lightness;
|
||||
public Canvas targetCanvas;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask.render;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.ui.views.flask.ColorCircle;
|
||||
|
||||
public interface ColorWheelRenderer {
|
||||
float GAP_PERCENTAGE = 0.025f;
|
||||
|
||||
void draw();
|
||||
|
||||
ColorWheelRenderOption getRenderOption();
|
||||
|
||||
void initWith(ColorWheelRenderOption colorWheelRenderOption);
|
||||
|
||||
List<ColorCircle> getColorCircleList();
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.flask.render;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import ru.vtosters.lite.ui.views.flask.ColorCircle;
|
||||
import ru.vtosters.lite.ui.views.flask.builder.PaintBuilder;
|
||||
|
||||
public class SimpleColorWheelRenderer extends AbsColorWheelRenderer {
|
||||
private Paint selectorFill = PaintBuilder.newPaint().build();
|
||||
private float[] hsv = new float[3];
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
final int setSize = colorCircleList.size();
|
||||
int currentCount = 0;
|
||||
float half = colorWheelRenderOption.targetCanvas.getWidth() / 2f;
|
||||
int density = colorWheelRenderOption.density;
|
||||
float maxRadius = colorWheelRenderOption.maxRadius;
|
||||
|
||||
for (int i = 0; i < density; i++) {
|
||||
float p = (float) i / (density - 1); // 0~1
|
||||
float radius = maxRadius * p;
|
||||
float size = colorWheelRenderOption.cSize;
|
||||
int total = calcTotalCount(radius, size);
|
||||
|
||||
for (int j = 0; j < total; j++) {
|
||||
double angle = Math.PI * 2 * j / total + (Math.PI / total) * ((i + 1) % 2);
|
||||
float x = half + (float) (radius * Math.cos(angle));
|
||||
float y = half + (float) (radius * Math.sin(angle));
|
||||
hsv[0] = (float) (angle * 180 / Math.PI);
|
||||
hsv[1] = radius / maxRadius;
|
||||
hsv[2] = colorWheelRenderOption.lightness;
|
||||
selectorFill.setColor(Color.HSVToColor(hsv));
|
||||
selectorFill.setAlpha(getAlphaValueAsInt());
|
||||
|
||||
colorWheelRenderOption.targetCanvas.drawCircle(x, y, size - colorWheelRenderOption.strokeWidth, selectorFill);
|
||||
|
||||
if (currentCount >= setSize)
|
||||
colorCircleList.add(new ColorCircle(x, y, hsv));
|
||||
else colorCircleList.get(currentCount).set(x, y, hsv);
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class AlphaView extends SliderViewBase implements ColorObserver {
|
||||
|
||||
private ObservableColor observableColor = new ObservableColor(0);
|
||||
|
||||
public AlphaView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void observeColor(ObservableColor observableColor) {
|
||||
this.observableColor = observableColor;
|
||||
observableColor.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateColor(ObservableColor observableColor) {
|
||||
setPos((float)observableColor.getAlpha()/0xff);
|
||||
updateBitmap();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener(float currentPos) {
|
||||
observableColor.updateAlpha((int)(currentPos * 0xff), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPointerColor(float currentPos) {
|
||||
float solidColorLightness = observableColor.getLightness();
|
||||
float posLightness = 1 + currentPos * (solidColorLightness - 1);
|
||||
return posLightness > 0.5f ? 0xff000000 : 0xffffffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap makeBitmap(int w, int h) {
|
||||
final boolean isWide = w > h;
|
||||
final int n = Math.max(w, h);
|
||||
int color = observableColor.getColor();
|
||||
int[] colors = new int[n];
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float alpha = isWide ? (float)i / n : 1 - (float)i / n;
|
||||
colors[i] = color & 0xffffff | (int)(alpha * 0xff) << 24;
|
||||
}
|
||||
final int bmpWidth = isWide ? w : 1;
|
||||
final int bmpHeight = isWide ? 1 : h;
|
||||
return Bitmap.createBitmap(colors, bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
public interface ColorObserver {
|
||||
|
||||
void updateColor(ObservableColor observableColor);
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.text.method.DigitsKeyListener;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class ColorPickerView extends FrameLayout {
|
||||
|
||||
private AlphaView alphaView;
|
||||
private EditText hexEdit;
|
||||
private ObservableColor observableColor = new ObservableColor(0);
|
||||
private SwatchView swatchView;
|
||||
|
||||
public ColorPickerView(Context context) {
|
||||
super(context);
|
||||
|
||||
var container = new LinearLayout(context);
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
container.setPadding(dp2px(16), dp2px(16), dp2px(16), dp2px(16));
|
||||
container.setGravity(Gravity.CENTER);
|
||||
this.addView(container, LayoutUtils.createFrame(-2, -2));
|
||||
|
||||
var colorPickerFrame = new FrameLayout(context);
|
||||
var colorPickerFrameParams = LayoutUtils.createLinear(-2, -2);
|
||||
colorPickerFrameParams.weight = 1.0f;
|
||||
container.addView(colorPickerFrame, colorPickerFrameParams);
|
||||
|
||||
swatchView = new SwatchView(context);
|
||||
colorPickerFrame.addView(swatchView, LayoutUtils.createFrame(-2, -2));
|
||||
|
||||
HueSatView hueSatView = new HueSatView(context);
|
||||
colorPickerFrame.addView(hueSatView, LayoutUtils.createFrame(-2, -2));
|
||||
|
||||
ValueView valueView = new ValueView(context);
|
||||
var valueViewParams = LayoutUtils.createLinear(-1, dp2px(36));
|
||||
valueViewParams.topMargin = dp2px(16);
|
||||
container.addView(valueView, valueViewParams);
|
||||
|
||||
alphaView = new AlphaView(context);
|
||||
var alphaViewParams = LayoutUtils.createLinear(-1, dp2px(36));
|
||||
valueViewParams.topMargin = dp2px(16);
|
||||
container.addView(alphaView, alphaViewParams);
|
||||
|
||||
hexEdit = new EditText(context);
|
||||
hexEdit.setText("00000000");
|
||||
hexEdit.setKeyListener(DigitsKeyListener.getInstance("0123456789ABCDEFabcdef"));
|
||||
hexEdit.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
hexEdit.setFilters(new InputFilter[]{ new InputFilter.LengthFilter(4) });
|
||||
hexEdit.setBackground(null);
|
||||
hexEdit.setTypeface(Typeface.MONOSPACE);
|
||||
hexEdit.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
hexEdit.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
container.addView(hexEdit, LayoutUtils.createLinear(-1, -2));
|
||||
|
||||
swatchView.observeColor(observableColor);
|
||||
hueSatView.observeColor(observableColor);
|
||||
valueView.observeColor(observableColor);
|
||||
alphaView.observeColor(observableColor);
|
||||
HexEdit.setUpListeners(hexEdit, observableColor);
|
||||
|
||||
showAlpha(true);
|
||||
showHex(true);
|
||||
showPreview(true);
|
||||
|
||||
// We get all our state saved and restored for free,
|
||||
// thanks to the EditText and its listeners!
|
||||
}
|
||||
|
||||
/** Returns the color selected by the user */
|
||||
public int getColor() {
|
||||
return observableColor.getColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the original color swatch and the current color to the specified value.<br>
|
||||
* Using dark colors may lead to a loss of color information caused by the ARGB color space.
|
||||
* Use {@link #setColor(int, float, float, float)} instead to avoid this.
|
||||
*/
|
||||
public void setColor(int color) {
|
||||
setOriginalColor(color);
|
||||
setCurrentColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the original color swatch and the current color to the specified value.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Alpha [0...255]</li>
|
||||
* <li>Hue [0...360)</li>
|
||||
* <li>Saturation [0...1]</li>
|
||||
* <li>Brightness [0...1]</li>
|
||||
* </ul>
|
||||
*/ public void setColor(int alpha, float hue, float sat, float bri) {
|
||||
setOriginalColor(alpha, hue, sat, bri);
|
||||
setCurrentColor(alpha, hue, sat, bri);
|
||||
}
|
||||
|
||||
/** Sets the original color swatch without changing the current color. */
|
||||
public void setOriginalColor(int color) {
|
||||
swatchView.setOriginalColor(color);
|
||||
}
|
||||
|
||||
/** Sets the original color swatch without changing the current color. */
|
||||
public void setOriginalColor(int alpha, float hue, float sat, float bri) {
|
||||
int color = Color.HSVToColor(alpha, new float[]{hue, sat, bri});
|
||||
swatchView.setOriginalColor(color);
|
||||
}
|
||||
|
||||
/** Updates the current color without changing the original color swatch. */
|
||||
public void setCurrentColor(int color) {
|
||||
observableColor.updateColor(color, null);
|
||||
}
|
||||
|
||||
/** Updates the current color without changing the original color swatch. */
|
||||
public void setCurrentColor(int alpha, float hue, float sat, float bri) {
|
||||
observableColor.updateColor(alpha, hue, sat, bri, null);
|
||||
}
|
||||
|
||||
public void showAlpha(boolean showAlpha) {
|
||||
alphaView.setVisibility(showAlpha ? View.VISIBLE : View.GONE);
|
||||
HexEdit.setShowAlphaDigits(hexEdit, showAlpha);
|
||||
}
|
||||
|
||||
public void addColorObserver(ColorObserver observer) {
|
||||
observableColor.addObserver(observer);
|
||||
}
|
||||
|
||||
public void showHex(boolean showHex) {
|
||||
hexEdit.setVisibility(showHex ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
public void showPreview(boolean showPreview) {
|
||||
swatchView.setVisibility(showPreview ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.EditText;
|
||||
|
||||
class HexEdit {
|
||||
|
||||
private static InputFilter[] withoutAlphaDigits = {new ColorPasteLengthFilter()};
|
||||
private static InputFilter[] withAlphaDigits = {new InputFilter.LengthFilter(8)};
|
||||
|
||||
public static void setUpListeners(final EditText hexEdit, final ObservableColor observableColor) {
|
||||
|
||||
class MultiObserver implements ColorObserver, TextWatcher {
|
||||
|
||||
@Override
|
||||
public void updateColor(ObservableColor observableColor) {
|
||||
final String colorString = formatColor(observableColor.getColor());
|
||||
// Prevent onTextChanged getting called when we update text programmatically
|
||||
hexEdit.removeTextChangedListener(this);
|
||||
hexEdit.setText(colorString);
|
||||
hexEdit.addTextChangedListener(this);
|
||||
}
|
||||
|
||||
private String formatColor(int color) {
|
||||
return shouldTrimAlphaDigits()
|
||||
? String.format("%06x", color & 0x00ffffff)
|
||||
: String.format("%08x", color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
int color = parseHexColor(s);
|
||||
if (shouldTrimAlphaDigits()) color = color | 0xff000000;
|
||||
observableColor.updateColor(color, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
|
||||
private boolean shouldTrimAlphaDigits() {
|
||||
return hexEdit.getFilters() == withoutAlphaDigits;
|
||||
}
|
||||
}
|
||||
|
||||
final MultiObserver multiObserver = new MultiObserver();
|
||||
hexEdit.addTextChangedListener(multiObserver);
|
||||
observableColor.addObserver(multiObserver);
|
||||
setShowAlphaDigits(hexEdit, true);
|
||||
}
|
||||
|
||||
private static int parseHexColor(CharSequence s) {
|
||||
try {
|
||||
return (int)(Long.parseLong(s.toString(), 16) & 0xffffffffL);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return Color.GRAY;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setShowAlphaDigits(final EditText hexEdit, boolean showAlphaDigits) {
|
||||
hexEdit.setFilters(showAlphaDigits ? withAlphaDigits : withoutAlphaDigits);
|
||||
hexEdit.setText(hexEdit.getText()); // trigger a reformat of text
|
||||
}
|
||||
|
||||
|
||||
private static class ColorPasteLengthFilter implements InputFilter {
|
||||
|
||||
private static final int MAX_LENGTH = 6;
|
||||
private static final int PASTED_LEN = 8;
|
||||
private final InputFilter sixDigitFilter = new InputFilter.LengthFilter(MAX_LENGTH);
|
||||
|
||||
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
|
||||
// If 8 digits have been pasted, replacing all source, trim alpha digits.
|
||||
// Otherwise standard LengthFilter behavior.
|
||||
final int srcLength = end - start;
|
||||
final int dstSelLength = dend - dstart;
|
||||
if (srcLength == PASTED_LEN && dstSelLength == dest.length()) {
|
||||
// Discard alpha digits:
|
||||
return source.subSequence(PASTED_LEN - MAX_LENGTH, PASTED_LEN);
|
||||
}
|
||||
else {
|
||||
return sixDigitFilter.filter(source, start, end, dest, dstart, dend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class HueSatView extends SquareView implements ColorObserver {
|
||||
|
||||
private Paint borderPaint;
|
||||
private Paint pointerPaint;
|
||||
private Path pointerPath;
|
||||
private Path borderPath;
|
||||
private Rect viewRect = new Rect();
|
||||
private int w;
|
||||
private int h;
|
||||
|
||||
// Bitmap is generated once and shared across instances.
|
||||
private static Bitmap bitmap;
|
||||
|
||||
private final PointF pointer = new PointF();
|
||||
private ObservableColor observableColor = new ObservableColor(0);
|
||||
|
||||
public HueSatView(Context context) {
|
||||
super(context);
|
||||
|
||||
borderPaint = Resources.makeLinePaint();
|
||||
pointerPaint = Resources.makeLinePaint();
|
||||
pointerPaint.setColor(0xff000000);
|
||||
pointerPath = Resources.makePointerPath();
|
||||
borderPath = new Path();
|
||||
if (bitmap == null) {
|
||||
bitmap = makeBitmap(optimalBitmapSize());
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
// Need clipPath() and setLayerType()...
|
||||
throw new UnsupportedOperationException("Android API 10 and below is not supported.");
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
// clipPath() is only supported on a software layer.
|
||||
setLayerType(LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
}
|
||||
|
||||
private int optimalBitmapSize() {
|
||||
final int scale = 2;
|
||||
final int maxBitmapSize = 128;
|
||||
final DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
return Math.min(maxBitmapSize, Math.min(dm.widthPixels, dm.heightPixels) / scale);
|
||||
}
|
||||
|
||||
public void observeColor(ObservableColor observableColor) {
|
||||
this.observableColor = observableColor;
|
||||
observableColor.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateColor(ObservableColor observableColor) {
|
||||
setPointer(pointer, observableColor.getHue(), observableColor.getSat(), w);
|
||||
optimisePointerColor();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
viewRect.set(0, 0, w, h);
|
||||
|
||||
float inset = borderPaint.getStrokeWidth() / 2;
|
||||
makeBorderPath(borderPath, w, h, inset);
|
||||
|
||||
// Sets pointer position
|
||||
updateColor(observableColor);
|
||||
}
|
||||
|
||||
private static void makeBorderPath(Path borderPath, int w, int h, float inset) {
|
||||
w -= inset;
|
||||
h -= inset;
|
||||
borderPath.reset();
|
||||
borderPath.moveTo(w, inset);
|
||||
borderPath.lineTo(w, h);
|
||||
borderPath.lineTo(inset, h);
|
||||
borderPath.addArc(new RectF(inset, inset, 2 * w, 2 * h), 180, 270);
|
||||
borderPath.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
int action = event.getActionMasked();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
boolean withinPicker = clamp(pointer, event.getX(), event.getY(), true);
|
||||
if (withinPicker) update();
|
||||
return withinPicker;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
clamp(pointer, event.getX(), event.getY(), false);
|
||||
update();
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
return true;
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
observableColor.updateHueSat(
|
||||
hueForPos(pointer.x, pointer.y, w),
|
||||
satForPos(pointer.x, pointer.y, w),
|
||||
this);
|
||||
optimisePointerColor();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private boolean clamp(PointF pointer, float x, float y, boolean rejectOutside) {
|
||||
x = Math.min(x, w);
|
||||
y = Math.min(y, h);
|
||||
final float dx = w - x;
|
||||
final float dy = h - y;
|
||||
final float r = (float)Math.sqrt(dx * dx + dy * dy);
|
||||
boolean outside = r > w;
|
||||
if (!outside || !rejectOutside) {
|
||||
if (outside) {
|
||||
x = w - dx * w / r;
|
||||
y = w - dy * w / r;
|
||||
}
|
||||
pointer.set(x, y);
|
||||
}
|
||||
return !outside;
|
||||
}
|
||||
|
||||
private void optimisePointerColor() {
|
||||
pointerPaint.setColor(
|
||||
observableColor.getLightnessWithValue(1) > 0.5
|
||||
? 0xff000000 : 0xffffffff);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
canvas.save();
|
||||
|
||||
canvas.clipPath(borderPath);
|
||||
canvas.drawBitmap(bitmap, null, viewRect, null);
|
||||
canvas.translate(pointer.x, pointer.y);
|
||||
canvas.drawPath(pointerPath, pointerPaint);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
canvas.drawPath(borderPath, borderPaint);
|
||||
}
|
||||
|
||||
private static Bitmap makeBitmap(int radiusPx) {
|
||||
int[] colors = new int[radiusPx * radiusPx];
|
||||
float[] hsv = new float[]{0f, 0f, 1f};
|
||||
for (int y = 0; y < radiusPx; ++y) {
|
||||
for (int x = 0; x < radiusPx; ++x) {
|
||||
final int i = x + y * radiusPx;
|
||||
final float sat = satForPos(x, y, radiusPx);
|
||||
final float arcBleed = 2f / radiusPx; // extend curved edge pixels just outside clip area.
|
||||
if (sat <= 1 + arcBleed) {
|
||||
hsv[0] = hueForPos(x, y, radiusPx);
|
||||
hsv[1] = sat;
|
||||
colors[i] = Color.HSVToColor(0xff, hsv);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Bitmap.createBitmap(colors, radiusPx, radiusPx, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
private static float hueForPos(float x, float y, float radiusPx) {
|
||||
final double r = radiusPx - 1; // gives values 0...1 inclusive
|
||||
final double dx = (r - x) / r;
|
||||
final double dy = (r - y) / r;
|
||||
final double angle = Math.atan2(dy, dx);
|
||||
final double hue = 360 * angle / (Math.PI / 2);
|
||||
return (float)hue;
|
||||
}
|
||||
|
||||
private static float satForPos(float x, float y, float radiusPx) {
|
||||
final double r = radiusPx - 1; // gives values 0...1 inclusive
|
||||
final double dx = (r - x) / r;
|
||||
final double dy = (r - y) / r;
|
||||
final double sat = dx * dx + dy * dy; // leave it squared -- exaggerates pale colors
|
||||
return (float)sat;
|
||||
}
|
||||
|
||||
private static void setPointer(PointF pointer, float hue, float sat, float radiusPx) {
|
||||
final float r = radiusPx - 1; // for values 0...1 inclusive
|
||||
final double distance = r * Math.sqrt(sat);
|
||||
final double angle = hue / 360 * Math.PI / 2;
|
||||
final double dx = distance * Math.cos(angle);
|
||||
final double dy = distance * Math.sin(angle);
|
||||
pointer.set(r - (float)dx, r - (float)dy);
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ObservableColor {
|
||||
|
||||
// Store as HSV & A, otherwise round-trip to int causes color drift.
|
||||
private final float[] hsv = {0, 0, 0};
|
||||
private int alpha;
|
||||
private final List<ColorObserver> observers = new ArrayList<ColorObserver>();
|
||||
|
||||
public ObservableColor(int color) {
|
||||
Color.colorToHSV(color, hsv);
|
||||
alpha = Color.alpha(color);
|
||||
}
|
||||
|
||||
public void getHsv(float hsvOut[]) {
|
||||
hsvOut[0] = hsv[0];
|
||||
hsvOut[1] = hsv[1];
|
||||
hsvOut[2] = hsv[2];
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return Color.HSVToColor(alpha, hsv);
|
||||
}
|
||||
|
||||
public float getHue() {
|
||||
return hsv[0];
|
||||
}
|
||||
|
||||
public float getSat() {
|
||||
return hsv[1];
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return hsv[2];
|
||||
}
|
||||
|
||||
public int getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public float getLightness() {
|
||||
return getLightnessWithValue(hsv[2]);
|
||||
}
|
||||
|
||||
public float getLightnessWithValue(float value) {
|
||||
float[] hsV = {hsv[0], hsv[1], value};
|
||||
final int color = Color.HSVToColor(hsV);
|
||||
return (Color.red(color) * 0.2126f + Color.green(color) * 0.7152f + Color.blue(color) * 0.0722f)/0xff;
|
||||
}
|
||||
|
||||
public void addObserver(ColorObserver observer) {
|
||||
observers.add(observer);
|
||||
}
|
||||
|
||||
public void updateHueSat(float hue, float sat, ColorObserver sender) {
|
||||
hsv[0] = hue;
|
||||
hsv[1] = sat;
|
||||
notifyOtherObservers(sender);
|
||||
}
|
||||
|
||||
public void updateValue(float value, ColorObserver sender) {
|
||||
hsv[2] = value;
|
||||
notifyOtherObservers(sender);
|
||||
}
|
||||
|
||||
public void updateAlpha(int alpha, ColorObserver sender) {
|
||||
this.alpha = alpha;
|
||||
notifyOtherObservers(sender);
|
||||
}
|
||||
|
||||
public void updateColor(int color, ColorObserver sender) {
|
||||
Color.colorToHSV(color, hsv);
|
||||
alpha = Color.alpha(color);
|
||||
notifyOtherObservers(sender);
|
||||
}
|
||||
|
||||
public void updateColor(int alpha, float hue, float sat, float bri, ColorObserver sender) {
|
||||
this.alpha = alpha;
|
||||
hsv[0] = hue;
|
||||
hsv[1] = sat;
|
||||
hsv[2] = bri;
|
||||
notifyOtherObservers(sender);
|
||||
}
|
||||
|
||||
private void notifyOtherObservers(ColorObserver sender) {
|
||||
for (ColorObserver observer : observers) {
|
||||
if (observer != sender) {
|
||||
observer.updateColor(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Shader;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
class Resources {
|
||||
|
||||
private static final float LINE_WIDTH_DIP = 1.5f;
|
||||
private static final float POINTER_RADIUS_DIP = 7;
|
||||
private static final int VIEW_OUTLINE_COLOR = 0xff808080;
|
||||
|
||||
public static Paint makeLinePaint() {
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(VIEW_OUTLINE_COLOR);
|
||||
paint.setStrokeWidth(dp2px(LINE_WIDTH_DIP));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setAntiAlias(true);
|
||||
return paint;
|
||||
}
|
||||
|
||||
public static Paint makeCheckerPaint(Context context) {
|
||||
Paint paint = new Paint();
|
||||
final Bitmap checkerBmp = BitmapFactory.decodeResource(context.getResources(), AndroidUtils.getIdentifier("checker_background", "drawable"));
|
||||
paint.setShader(new BitmapShader(checkerBmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
|
||||
paint.setStrokeWidth(dp2px(LINE_WIDTH_DIP));
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
paint.setAntiAlias(true);
|
||||
return paint;
|
||||
}
|
||||
|
||||
public static Path makePointerPath() {
|
||||
Path pointerPath = new Path();
|
||||
final float radiusPx = dp2px(POINTER_RADIUS_DIP);
|
||||
pointerPath.addCircle(0, 0, radiusPx, Path.Direction.CW);
|
||||
return pointerPath;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
public abstract class SliderViewBase extends View {
|
||||
|
||||
private final Paint borderPaint;
|
||||
private final Paint checkerPaint;
|
||||
private final Rect viewRect = new Rect();
|
||||
private int w;
|
||||
private int h;
|
||||
private final Path borderPath;
|
||||
private Bitmap bitmap;
|
||||
private final Path pointerPath;
|
||||
private final Paint pointerPaint;
|
||||
|
||||
private float currentPos;
|
||||
|
||||
public SliderViewBase(Context context) {
|
||||
super(context);
|
||||
checkerPaint = Resources.makeCheckerPaint(context);
|
||||
borderPaint = Resources.makeLinePaint();
|
||||
pointerPaint = Resources.makeLinePaint();
|
||||
pointerPath = Resources.makePointerPath();
|
||||
borderPath = new Path();
|
||||
}
|
||||
|
||||
protected abstract void notifyListener(float currentPos);
|
||||
|
||||
protected abstract Bitmap makeBitmap(int w, int h);
|
||||
|
||||
protected abstract int getPointerColor(float currentPos);
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
viewRect.set(0, 0, w, h);
|
||||
float inset = borderPaint.getStrokeWidth() / 2;
|
||||
borderPath.reset();
|
||||
borderPath.addRect(new RectF(inset, inset, w - inset, h - inset), Path.Direction.CW);
|
||||
updateBitmap();
|
||||
}
|
||||
|
||||
protected void setPos(float pos) {
|
||||
currentPos = pos;
|
||||
optimisePointerColor();
|
||||
}
|
||||
|
||||
protected void updateBitmap() {
|
||||
if (w > 0 && h > 0) {
|
||||
bitmap = makeBitmap(w, h);
|
||||
optimisePointerColor();
|
||||
}
|
||||
// else not ready yet
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
int action = event.getActionMasked();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
currentPos = valueForTouchPos(event.getX(), event.getY());
|
||||
optimisePointerColor();
|
||||
notifyListener(currentPos);
|
||||
invalidate();
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
return true;
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawPath(borderPath, checkerPaint);
|
||||
canvas.drawBitmap(bitmap, null, viewRect, null);
|
||||
canvas.drawPath(borderPath, borderPaint);
|
||||
|
||||
canvas.save();
|
||||
if (isWide()) {
|
||||
canvas.translate(w * currentPos, h / 2);
|
||||
}
|
||||
else {
|
||||
canvas.translate(w / 2, h * (1 - currentPos));
|
||||
}
|
||||
canvas.drawPath(pointerPath, pointerPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
private boolean isWide() {
|
||||
return w > h;
|
||||
}
|
||||
|
||||
private float valueForTouchPos(float x, float y) {
|
||||
final float val = isWide() ? x / w : 1 - y / h;
|
||||
return Math.max(0, Math.min(1, val));
|
||||
}
|
||||
|
||||
private void optimisePointerColor() {
|
||||
pointerPaint.setColor(getPointerColor(currentPos));
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
class SquareView extends View {
|
||||
private static final int MIN_SIZE_DIP = 200;
|
||||
|
||||
private final int minSizePx;
|
||||
|
||||
public SquareView(Context context) {
|
||||
super(context);
|
||||
minSizePx = dp2px(MIN_SIZE_DIP);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// Constrain to square
|
||||
final int w = MeasureSpec.getSize(widthMeasureSpec);
|
||||
final int h = MeasureSpec.getSize(heightMeasureSpec);
|
||||
final int modeW = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final int modeH = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int size = minSizePx;
|
||||
if (modeW == MeasureSpec.UNSPECIFIED) {
|
||||
size = h;
|
||||
}
|
||||
else if (modeH == MeasureSpec.UNSPECIFIED) {
|
||||
size = w;
|
||||
}
|
||||
else {
|
||||
size = Math.min(w, h);
|
||||
}
|
||||
size = Math.max(size, minSizePx);
|
||||
setMeasuredDimension(size, size);
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class SwatchView extends SquareView implements ColorObserver {
|
||||
|
||||
private final Paint borderPaint;
|
||||
private final Path borderPath;
|
||||
private final Paint checkerPaint;
|
||||
private final Path oldFillPath;
|
||||
private final Path newFillPath;
|
||||
private final Paint oldFillPaint;
|
||||
private final Paint newFillPaint;
|
||||
private final float radialMarginPx;
|
||||
|
||||
public SwatchView(Context context) {
|
||||
super(context);
|
||||
|
||||
radialMarginPx = AndroidUtils.dp2px(16);
|
||||
|
||||
borderPaint = Resources.makeLinePaint();
|
||||
checkerPaint = Resources.makeCheckerPaint(context);
|
||||
oldFillPaint = new Paint();
|
||||
newFillPaint = new Paint();
|
||||
|
||||
borderPath = new Path();
|
||||
oldFillPath = new Path();
|
||||
newFillPath = new Path();
|
||||
}
|
||||
|
||||
void setOriginalColor(int color) {
|
||||
oldFillPaint.setColor(color);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void observeColor(ObservableColor observableColor) {
|
||||
observableColor.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateColor(ObservableColor observableColor) {
|
||||
newFillPaint.setColor(observableColor.getColor());
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
// We expect to be stacked behind a square HueSatView and fill the top left corner.
|
||||
|
||||
final float inset = borderPaint.getStrokeWidth() / 2;
|
||||
final float r = Math.min(w, h);
|
||||
|
||||
// Trim the corners of the swatch is where it is radialMarginPx thick.
|
||||
// find how long the outeredges are:
|
||||
final float margin = radialMarginPx;
|
||||
final float diagonal = r + 2 * margin;
|
||||
final float opp = (float)Math.sqrt(diagonal * diagonal - r * r);
|
||||
final float edgeLen = r - opp;
|
||||
|
||||
// Arc angles for drawing CCW
|
||||
final float outerAngle = (float)Math.toDegrees(Math.atan2(opp, r));
|
||||
final float startAngle = 270 - outerAngle;
|
||||
// Sweep angle for each half of the swatch:
|
||||
final float sweepAngle = outerAngle - 45;
|
||||
// Sweep angle for the smooth corners:
|
||||
final float cornerSweepAngle = 90 - outerAngle;
|
||||
|
||||
// Outer border:
|
||||
beginBorder(borderPath, inset, edgeLen, margin, cornerSweepAngle);
|
||||
mainArc(borderPath, r, margin, startAngle, 2 * sweepAngle);
|
||||
endBorder(borderPath, inset, edgeLen, margin, cornerSweepAngle);
|
||||
|
||||
// Old fill shape:
|
||||
oldFillPath.reset();
|
||||
oldFillPath.moveTo(inset, inset);
|
||||
mainArc(oldFillPath, r, margin, 225, sweepAngle);
|
||||
endBorder(oldFillPath, inset, edgeLen, margin, cornerSweepAngle);
|
||||
|
||||
// New fill shape:
|
||||
beginBorder(newFillPath, inset, edgeLen, margin, cornerSweepAngle);
|
||||
mainArc(newFillPath, r, margin, startAngle, sweepAngle);
|
||||
newFillPath.lineTo(inset, inset);
|
||||
newFillPath.close();
|
||||
}
|
||||
|
||||
private static void beginBorder(Path path, float inset, float edgeLen, float cornerRadius, float cornerSweepAngle) {
|
||||
path.reset();
|
||||
path.moveTo(inset, inset);
|
||||
cornerArc(path, edgeLen, inset, cornerRadius-inset, 0, cornerSweepAngle);
|
||||
}
|
||||
|
||||
private static void endBorder(Path path, float inset, float edgeLen, float cornerRadius, float cornerSweepAngle) {
|
||||
cornerArc(path, inset, edgeLen, cornerRadius - inset, 90 - cornerSweepAngle, cornerSweepAngle);
|
||||
path.lineTo(inset, inset);
|
||||
path.close();
|
||||
}
|
||||
|
||||
private static void cornerArc(Path path, float cx, float cy, float r, float startAngle, float sweepAngle) {
|
||||
final RectF ovalRect = new RectF(-r, -r, r, r);
|
||||
ovalRect.offset(cx, cy);
|
||||
path.arcTo(ovalRect, startAngle, sweepAngle);
|
||||
}
|
||||
|
||||
private static void mainArc(Path path, float viewSize, float margin, float startAngle, float sweepAngle) {
|
||||
float r = viewSize + margin;
|
||||
final RectF ovalRect = new RectF(-r, -r, r, r);
|
||||
ovalRect.offset(viewSize, viewSize);
|
||||
path.arcTo(ovalRect, startAngle, sweepAngle);
|
||||
}
|
||||
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawPath(borderPath, checkerPaint);
|
||||
canvas.drawPath(oldFillPath, oldFillPaint);
|
||||
canvas.drawPath(newFillPath, newFillPaint);
|
||||
canvas.drawPath(borderPath, borderPaint);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package ru.vtosters.lite.ui.views.rarepebble;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
|
||||
public class ValueView extends SliderViewBase implements ColorObserver {
|
||||
|
||||
private ObservableColor observableColor = new ObservableColor(0);
|
||||
|
||||
public ValueView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void observeColor(ObservableColor observableColor) {
|
||||
this.observableColor = observableColor;
|
||||
observableColor.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateColor(ObservableColor observableColor) {
|
||||
setPos(this.observableColor.getValue());
|
||||
updateBitmap();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener(float currentPos) {
|
||||
observableColor.updateValue(currentPos, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPointerColor(float currentPos) {
|
||||
float brightColorLightness = observableColor.getLightness();
|
||||
float posLightness = currentPos * brightColorLightness;
|
||||
return posLightness > 0.5f ? 0xff000000 : 0xffffffff;
|
||||
}
|
||||
|
||||
protected Bitmap makeBitmap(int w, int h) {
|
||||
final boolean isWide = w > h;
|
||||
final int n = Math.max(w, h);
|
||||
int[] colors = new int[n];
|
||||
|
||||
float[] hsv = new float[]{0, 0, 0};
|
||||
observableColor.getHsv(hsv);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
hsv[2] = isWide ? (float)i / n : 1 - (float)i / n;
|
||||
colors[i] = Color.HSVToColor(hsv);
|
||||
}
|
||||
final int bmpWidth = isWide ? w : 1;
|
||||
final int bmpHeight = isWide ? 1 : h;
|
||||
return Bitmap.createBitmap(colors, bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +1,76 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.vk.core.dialogs.bottomsheet.ModalBottomSheet;
|
||||
|
||||
public class ModalBottomSheetWrapper<T> {
|
||||
public final ModalBottomSheet.a mBuilder;
|
||||
public ModalBottomSheet mBottomSheet;
|
||||
public class ModalBottomSheetWrapper {
|
||||
public final ModalBottomSheet.a builder;
|
||||
|
||||
public ModalBottomSheetWrapper(Activity activity) {
|
||||
mBuilder = new ModalBottomSheet.a(activity);
|
||||
builder = new ModalBottomSheet.a(activity);
|
||||
}
|
||||
|
||||
public T setTitle(String title) {
|
||||
mBuilder.d(title);
|
||||
return (T) this;
|
||||
public ModalBottomSheetWrapper setTitle(String title) {
|
||||
builder.d(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
public T setClickableMessage(
|
||||
@SuppressLint("SetTextI18n")
|
||||
public ModalBottomSheetWrapper setUpdateInfoView(String changelog) {
|
||||
var context = getGlobalContext();
|
||||
var container = new LinearLayout(context);
|
||||
var changelogView = new TextView(context);
|
||||
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
changelogView.setPadding(0, dp2px(8), 0, 0);
|
||||
changelogView.setText(getString("changelog") + ": \n" + changelog);
|
||||
changelogView.setTextColor(getTextAttr());
|
||||
container.addView(changelogView, new LinearLayout.LayoutParams(-1, -2));
|
||||
|
||||
builder.a(container);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModalBottomSheetWrapper setClickableMessage(
|
||||
String text,
|
||||
Runnable callback
|
||||
) {
|
||||
mBuilder.a(text, listener -> callback.run());
|
||||
return (T) this;
|
||||
builder.a(text, listener -> callback.run());
|
||||
return this;
|
||||
}
|
||||
|
||||
public T setPositiveButton(
|
||||
public ModalBottomSheetWrapper setPositiveButton(
|
||||
String text,
|
||||
Runnable callback
|
||||
) {
|
||||
mBuilder.a(text, kostil -> callback.run());
|
||||
return (T) this;
|
||||
builder.a(text, kostil -> callback.run());
|
||||
return this;
|
||||
}
|
||||
|
||||
public T setView(View view) {
|
||||
mBuilder.a(view);
|
||||
return (T) this;
|
||||
public ModalBottomSheetWrapper setView(View view) {
|
||||
builder.a(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModalBottomSheet show(String tag) {
|
||||
return mBuilder.a(tag);
|
||||
public ModalBottomSheet show() {
|
||||
return builder.a("");
|
||||
}
|
||||
|
||||
public ModalBottomSheet show(String tag, boolean isCancellable) {
|
||||
mBottomSheet = mBuilder.a(tag);
|
||||
mBottomSheet.setCancelable(isCancellable);
|
||||
return mBottomSheet;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
mBottomSheet.dismiss();
|
||||
public ModalBottomSheet show(boolean isCancellable) {
|
||||
var sheet = builder.a("");
|
||||
sheet.setCancelable(isCancellable);
|
||||
return sheet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class VBottomSheetBuilder {
|
||||
public static void show(Activity activity, VBSContent content, String tag) {
|
||||
public static void show(Activity activity, VBSContent content) {
|
||||
ModalBottomSheetWrapper builder = new ModalBottomSheetWrapper(activity);
|
||||
|
||||
builder.setView(content.view);
|
||||
@@ -20,7 +20,7 @@ public class VBottomSheetBuilder {
|
||||
new Handler(Looper.getMainLooper()).post(content.button.action);
|
||||
}); // Positive
|
||||
|
||||
builder.show(tag); // Build+Show
|
||||
builder.show(); // Build+Show
|
||||
}
|
||||
|
||||
public static class VBSContent {
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vk.core.dialogs.actionspopup.ActionsPopup;
|
||||
import com.vk.core.dialogs.adapter.ModalAdapter;
|
||||
|
||||
public class VKUIActionPopup {
|
||||
|
||||
private final ActionsPopup.b mLocalBuilder;
|
||||
|
||||
public VKUIActionPopup(Context context, View anchorView, boolean anchor, @ColorRes int color) {
|
||||
this.mLocalBuilder = new ActionsPopup.b(anchorView, anchor, color).a(context);
|
||||
}
|
||||
|
||||
public VKUIActionPopup setItem(String title, @Nullable Drawable icon, boolean z, onClickListener clickListener) {
|
||||
mLocalBuilder.a(title, icon, z, () -> {
|
||||
clickListener.onClick();
|
||||
return null;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUIActionPopup setItem(String title, @Nullable Drawable icon, onClickListener clickListener) {
|
||||
return setItem(title, icon, false, clickListener);
|
||||
}
|
||||
|
||||
public VKUIActionPopup setItem(String title, onClickListener clickListener) {
|
||||
return setItem(title, null, false, clickListener);
|
||||
}
|
||||
|
||||
public VKUIActionPopup setActionCheckIcon(Drawable actionCheckItem) {
|
||||
mLocalBuilder.a(actionCheckItem);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUIActionPopup setMaxWidth(@Px int maxWidth) {
|
||||
mLocalBuilder.a(Integer.valueOf(maxWidth));
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUIActionPopup setAdapter(ModalAdapter adapter) {
|
||||
mLocalBuilder.a((ModalAdapter<Object>) adapter);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUIActionPopup setAdapter(RecyclerView.Adapter adapter) {
|
||||
mLocalBuilder.a(adapter);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActionsPopup create() {
|
||||
return mLocalBuilder.a();
|
||||
}
|
||||
|
||||
public ActionsPopup create(boolean cancel) {
|
||||
return mLocalBuilder.a(cancel);
|
||||
}
|
||||
|
||||
public interface onClickListener {
|
||||
void onClick();
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
public class VKUIButton extends TextView /*Yes, yes, it's TextView*/ {
|
||||
|
||||
public static final int STYLE_PRIMARY = R.style.VKUIButton_Primary;
|
||||
public static final int STYLE_PRIMARY_ROUNDED = R.style.VKUIButton_Primary_Rounded;
|
||||
public static final int STYLE_PRIMARY_SMALL = R.style.VKUIButton_Primary_Small;
|
||||
public static final int STYLE_PRIMARY_SMALL_FLAT = R.style.VKUIButton_Primary_Small_Flat;
|
||||
public static final int STYLE_PRIMARY_MEDIUM = R.style.VKUIButton_Primary_Medium;
|
||||
public static final int STYLE_PRIMARY_BIG = R.style.VKUIButton_Primary_Big;
|
||||
public static final int STYLE_SECONDARY = R.style.VKUIButton_Secondary;
|
||||
public static final int STYLE_SECONDARY_ROUNDED = R.style.VKUIButton_Secondary_Rounded;
|
||||
public static final int STYLE_SECONDARY_SMALL = R.style.VKUIButton_Secondary_Small;
|
||||
public static final int STYLE_SECONDARY_SMALL_FLAT = R.style.VKUIButton_Secondary_Small_Flat;
|
||||
public static final int STYLE_SECONDARY_MEDIUM = R.style.VKUIButton_Secondary_Medium;
|
||||
public static final int STYLE_SECONDARY_BIG = R.style.VKUIButton_Secondary_Big;
|
||||
public static final int STYLE_MUTED = R.style.VKUIButton_Muted;
|
||||
public static final int STYLE_MUTED_ROUNDED = R.style.VKUIButton_Muted_Rounded;
|
||||
public static final int STYLE_TERTIARY = R.style.VKUIButton_Tertiary;
|
||||
public static final int STYLE_TERTIARY_ROUNDED = R.style.VKUIButton_Tertiary_Rounded;
|
||||
public static final int STYLE_OUTLINE = R.style.VKUIButton_Outline;
|
||||
public static final int STYLE_OUTLINE_WHITE = R.style.VKUIButton_Outline_White;
|
||||
public static final int STYLE_GREEN = R.style.VKUIButton_Green;
|
||||
public static final int STYLE_COMMERCE = STYLE_GREEN;
|
||||
public static final int STYLE_FLAT = R.style.VKUIButton_Flat;
|
||||
public static final int STYLE_WHITE = R.style.VKUIButton_White;
|
||||
public static final int STYLE_MEDIA_OVERLAY = R.style.VKUIButton_MediaOverlay;
|
||||
public static final int STYLE_SELECTABLE = R.style.VKUIButton_Selectable;
|
||||
public static final int STYLE_SELECTABLE_FLAT = R.style.VKUIButton_Selectable_Flat;
|
||||
|
||||
public VKUIButton(Context context) {
|
||||
this(context, STYLE_PRIMARY);
|
||||
}
|
||||
|
||||
public VKUIButton(Context context, int style) {
|
||||
super(new ContextThemeWrapper(context, style));
|
||||
}
|
||||
|
||||
public VKUIButton(Context context, @Nullable AttributeSet attrs) {
|
||||
super(new ContextThemeWrapper(context, STYLE_PRIMARY), attrs);
|
||||
}
|
||||
|
||||
public VKUIButton(Context context, @Nullable AttributeSet attrs, int style) {
|
||||
super(new ContextThemeWrapper(context, style), attrs);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
public class VKUICheckBox extends CheckBox {
|
||||
|
||||
public VKUICheckBox(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public VKUICheckBox(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public VKUICheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public VKUICheckBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.vk.core.drawable.VkUiDrawableHelper;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import ru.vtosters.lite.themes.VTLColors;
|
||||
|
||||
public class VKUIEditText extends EditText {
|
||||
|
||||
public VKUIEditText(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public VKUIEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public VKUIEditText(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
public VKUIEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
var fieldBackground = VKThemeHelper.d(R.attr.field_background);
|
||||
var drawable = VkUiDrawableHelper.c.a(getContext(), fieldBackground, fieldBackground, VTLColors.getAccentColor(), fieldBackground);
|
||||
setBackground(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBackground(Drawable background) {
|
||||
super.setBackground(background);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBackgroundColor(int color) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBackgroundResource(int resid) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorVisible(boolean visible) {
|
||||
super.setCursorVisible(visible);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Drawable getTextCursorDrawable() {
|
||||
return super.getTextCursorDrawable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextCursorDrawable(int textCursorDrawable) {
|
||||
super.setTextCursorDrawable(textCursorDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextCursorDrawable(@Nullable Drawable textCursorDrawable) {
|
||||
super.setTextCursorDrawable(textCursorDrawable);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatRadioButton;
|
||||
|
||||
public class VKUIRadioCheckbox extends AppCompatRadioButton {
|
||||
|
||||
public VKUIRadioCheckbox(Context context) {
|
||||
super(new ContextThemeWrapper(context, android.R.style.Widget_CompoundButton_RadioButton));
|
||||
}
|
||||
|
||||
public VKUIRadioCheckbox(Context context, AttributeSet attributeSet) {
|
||||
super(new ContextThemeWrapper(context, android.R.style.Widget_CompoundButton_RadioButton), attributeSet);
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.vk.core.dialogs.snackbar.VkSnackbar;
|
||||
|
||||
public class VKUISnackbar {
|
||||
private VkSnackbar.a mLocalBuilder;
|
||||
|
||||
public VKUISnackbar(Context context, boolean darkMode) {
|
||||
this.mLocalBuilder = new VkSnackbar.a(context, darkMode);
|
||||
}
|
||||
|
||||
public VKUISnackbar setIcon(Drawable icon) {
|
||||
mLocalBuilder.a(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setIcon(@DrawableRes int iconId) {
|
||||
mLocalBuilder.b(iconId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setMessage(String message) {
|
||||
mLocalBuilder.a((CharSequence) message);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setMessage(@StringRes int resId) {
|
||||
mLocalBuilder.a(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setShowTime(long time) {
|
||||
mLocalBuilder.a(time);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setView(View anchorView) {
|
||||
mLocalBuilder.a(anchorView);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setFragment(Fragment fragment) {
|
||||
mLocalBuilder.a(fragment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setActionButton(String text, OnClickListener clickListener) {
|
||||
mLocalBuilder.a(text, vkSnackbar -> {
|
||||
clickListener.onClick(vkSnackbar);
|
||||
return null;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public VKUISnackbar setActionButton(@StringRes int textId, OnClickListener clickListener) {
|
||||
mLocalBuilder.a(textId, vkSnackbar -> {
|
||||
clickListener.onClick(vkSnackbar);
|
||||
return null;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public VkSnackbar create() {
|
||||
return mLocalBuilder.d();
|
||||
}
|
||||
|
||||
public VkSnackbar create(Window window) {
|
||||
return mLocalBuilder.a(window);
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick(VkSnackbar snackbar);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
public class VKUITextView extends TextView {
|
||||
|
||||
public static final int STYLE_TITLE_1 = R.style.VKUIText_Title1;
|
||||
public static final int STYLE_TITLE_2 = R.style.VKUIText_Title2;
|
||||
public static final int STYLE_HEADLINE = R.style.VKUIText_Headline;
|
||||
public static final int STYLE_DEFAULT = R.style.VKUIText_Text;
|
||||
public static final int STYLE_SUBHEAD_1 = R.style.VKUIText_Subhead1;
|
||||
public static final int STYLE_SUBHEAD_2 = R.style.VKUIText_Subhead2;
|
||||
public static final int STYLE_CAPTION_1 = R.style.VKUIText_Caption1;
|
||||
public static final int STYLE_CAPTION_2 = R.style.VKUIText_Caption2;
|
||||
|
||||
public VKUITextView(Context context) {
|
||||
this(context, STYLE_DEFAULT);
|
||||
}
|
||||
|
||||
public VKUITextView(Context context, int style) {
|
||||
super(new ContextThemeWrapper(context, style));
|
||||
}
|
||||
|
||||
public VKUITextView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(new ContextThemeWrapper(context, STYLE_DEFAULT), attrs);
|
||||
}
|
||||
|
||||
public VKUITextView(Context context, @Nullable AttributeSet attrs, int style) {
|
||||
super(new ContextThemeWrapper(context, style), attrs);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package ru.vtosters.lite.ui.vkui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class VKUiSwitch extends SwitchCompat {
|
||||
|
||||
public VKUiSwitch(Context context) {
|
||||
super(context);
|
||||
setEllipsize(TextUtils.TruncateAt.END);
|
||||
setPadding(AndroidUtils.dp2px(8), AndroidUtils.dp2px(8), AndroidUtils.dp2px(8), AndroidUtils.dp2px(8));
|
||||
setTextSize(16.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setEllipsize(TextUtils.TruncateAt where) {
|
||||
super.setEllipsize(where);
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public class AndroidUtils {
|
||||
@NonNull
|
||||
public static Context getGlobalContext() {
|
||||
try {
|
||||
return (Context) ReflectionUtils.invokeStaticMethod("android.app.AppGlobals", "getInitialApplication");
|
||||
return ReflectionUtils.invokeStaticMethod("android.app.AppGlobals", "getInitialApplication");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.vk.im.engine.ImEnvironment;
|
||||
import com.vk.im.engine.events.OnMsgUpdateEvent;
|
||||
import com.vk.im.engine.internal.longpoll.tasks.MsgDeleteLpTask;
|
||||
import com.vk.im.engine.internal.storage.StorageEnvironment;
|
||||
@@ -79,32 +77,27 @@ public class DeletedMessagesHandler {
|
||||
}
|
||||
|
||||
public static void updateDialog(MsgDeleteLpTask msgDeleteLpTask) throws NoSuchFieldException, IllegalAccessException {
|
||||
Cursor c = getMessageFromDatabaseById(ReflectionUtils.getObjectField(msgDeleteLpTask.getClass(), "d", msgDeleteLpTask));
|
||||
if (c == null) return;
|
||||
var cursor = getMessageFromDatabaseById(msgDeleteLpTask.d);
|
||||
if (cursor == null) return;
|
||||
|
||||
@SuppressLint("Range")
|
||||
int localId = c.getInt(c.getColumnIndex("local_id"));
|
||||
int localId = cursor.getInt(cursor.getColumnIndex("local_id"));
|
||||
|
||||
String str = DeletedMessagesHandler.class.getSimpleName();
|
||||
var imEnvironment = (ImEnvironment) ReflectionUtils.getObjectField(msgDeleteLpTask.getClass(), "b", msgDeleteLpTask);
|
||||
var cint = (int) ReflectionUtils.getObjectField(msgDeleteLpTask.getClass(), "c", msgDeleteLpTask);
|
||||
imEnvironment.a(str, new OnMsgUpdateEvent(str, cint, localId));
|
||||
var className = DeletedMessagesHandler.class.getSimpleName();
|
||||
var imEnvironment = msgDeleteLpTask.b;
|
||||
var cint = msgDeleteLpTask.c;
|
||||
imEnvironment.a(className, new OnMsgUpdateEvent(className, cint, localId));
|
||||
}
|
||||
|
||||
public static void hookDeletedMessageId(MsgDeleteLpTask msgDeleteLpTask) throws NoSuchFieldException, IllegalAccessException {
|
||||
public static void hookDeletedMessageId(MsgDeleteLpTask msgDeleteLpTask) {
|
||||
if (!hook()) return;
|
||||
|
||||
var field = msgDeleteLpTask.getClass().getDeclaredField("c");
|
||||
field.setAccessible(true);
|
||||
var messageId = (int) field.get(msgDeleteLpTask);
|
||||
var messageId = msgDeleteLpTask.d;
|
||||
|
||||
Cursor c = getMessageFromDatabaseById(messageId);
|
||||
if (c == null) return;
|
||||
|
||||
if (sBodyIndex == -1) sBodyIndex = c.getColumnIndex("body");
|
||||
if (TextUtils.isEmpty(c.getString(sBodyIndex))) {
|
||||
deleteMessageFromDB(messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
sDeletedMessagesList.add(messageId);
|
||||
sVTDatabase.saveDeletedMessage(messageId);
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageVolume;
|
||||
import android.provider.DocumentsContract;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
// https://stackoverflow.com/questions/34927748/android-5-0-documentfile-from-tree-uri/36162691#36162691
|
||||
|
||||
public final class FileUriUtils {
|
||||
|
||||
private static final String PRIMARY_VOLUME_NAME = "primary";
|
||||
|
||||
@Nullable
|
||||
public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) {
|
||||
if (treeUri == null) return null;
|
||||
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),con);
|
||||
if (volumePath == null) return File.separator;
|
||||
if (volumePath.endsWith(File.separator))
|
||||
volumePath = volumePath.substring(0, volumePath.length() - 1);
|
||||
|
||||
String documentPath = getDocumentPathFromTreeUri(treeUri);
|
||||
if (documentPath.endsWith(File.separator))
|
||||
documentPath = documentPath.substring(0, documentPath.length() - 1);
|
||||
|
||||
if (documentPath.length() > 0) {
|
||||
if (documentPath.startsWith(File.separator))
|
||||
return volumePath + documentPath;
|
||||
else
|
||||
return volumePath + File.separator + documentPath;
|
||||
}
|
||||
else return volumePath;
|
||||
}
|
||||
|
||||
|
||||
private static String getVolumePath(final String volumeId, Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||
return getVolumePathForAndroid11AndAbove(volumeId, context);
|
||||
else
|
||||
return getVolumePathBeforeAndroid11(volumeId, context);
|
||||
}
|
||||
|
||||
|
||||
private static String getVolumePathBeforeAndroid11(final String volumeId, Context context){
|
||||
try {
|
||||
StorageManager mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||
Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
|
||||
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
|
||||
Method getUuid = storageVolumeClazz.getMethod("getUuid");
|
||||
Method getPath = storageVolumeClazz.getMethod("getPath");
|
||||
Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
|
||||
Object result = getVolumeList.invoke(mStorageManager);
|
||||
|
||||
final int length = Array.getLength(result);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object storageVolumeElement = Array.get(result, i);
|
||||
String uuid = (String) getUuid.invoke(storageVolumeElement);
|
||||
Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);
|
||||
|
||||
if (primary && PRIMARY_VOLUME_NAME.equals(volumeId)) // primary volume?
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
|
||||
if (uuid != null && uuid.equals(volumeId)) // other volumes?
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
}
|
||||
// not found.
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
private static String getVolumePathForAndroid11AndAbove(final String volumeId, Context context) {
|
||||
try {
|
||||
StorageManager mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||
List<StorageVolume> storageVolumes = mStorageManager.getStorageVolumes();
|
||||
for (StorageVolume storageVolume : storageVolumes) {
|
||||
// primary volume?
|
||||
if (storageVolume.isPrimary() && PRIMARY_VOLUME_NAME.equals(volumeId))
|
||||
return storageVolume.getDirectory().getPath();
|
||||
|
||||
// other volumes?
|
||||
String uuid = storageVolume.getUuid();
|
||||
if (uuid != null && uuid.equals(volumeId))
|
||||
return storageVolume.getDirectory().getPath();
|
||||
|
||||
}
|
||||
// not found.
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private static String getVolumeIdFromTreeUri(final Uri treeUri) {
|
||||
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||
final String[] split = docId.split(":");
|
||||
if (split.length > 0) return split[0];
|
||||
else return null;
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private static String getDocumentPathFromTreeUri(final Uri treeUri) {
|
||||
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||
final String[] split = docId.split(":");
|
||||
if ((split.length >= 2) && (split[1] != null)) return split[1];
|
||||
else return File.separator;
|
||||
}
|
||||
}
|
||||
@@ -71,34 +71,10 @@ public class IOUtils {
|
||||
}
|
||||
|
||||
public static void writeToFile(File file, byte[] content) throws IOException {
|
||||
if (!file.exists())
|
||||
file.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(content);
|
||||
}
|
||||
|
||||
public static void copyFileToDirectory(File dest, File targetDir) throws IOException {
|
||||
if (!targetDir.exists())
|
||||
targetDir.mkdirs();
|
||||
var path = dest.getAbsolutePath();
|
||||
var target = new File(targetDir, path.substring(path.lastIndexOf("/")));
|
||||
copyFile(dest, target);
|
||||
}
|
||||
|
||||
public static void copyFile(File dest, File target) throws IOException {
|
||||
var parent = target.getParentFile();
|
||||
if (!parent.exists())
|
||||
parent.getParentFile().mkdirs();
|
||||
writeToFile(target, readAllBytes(dest));
|
||||
}
|
||||
|
||||
public static void copyFile(InputStream is, File target) throws IOException {
|
||||
var parent = target.getParentFile();
|
||||
if (!parent.exists())
|
||||
parent.getParentFile().mkdirs();
|
||||
writeToFile(target, readAllBytes(is));
|
||||
}
|
||||
|
||||
public static void deleteRecursive(File f) {
|
||||
deleteRecursive(f, true);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package ru.vtosters.lite.utils;
|
||||
import static android.graphics.Bitmap.createBitmap;
|
||||
import static android.graphics.Bitmap.createScaledBitmap;
|
||||
import static androidx.core.content.ContextCompat.getDrawable;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.RectF;
|
||||
@@ -27,7 +29,7 @@ import okhttp3.Response;
|
||||
|
||||
public class ImageUtils {
|
||||
|
||||
private static OkHttpClient client = new OkHttpClient();
|
||||
private static final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
public static Bitmap bmp = null;
|
||||
|
||||
@@ -105,15 +107,21 @@ public class ImageUtils {
|
||||
final int width = bitmap.getWidth();
|
||||
final int height = bitmap.getHeight();
|
||||
final Bitmap outputBitmap = createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
int pref = preferences.getInt("pic_rounding", 0);
|
||||
final Canvas canvas = new Canvas(outputBitmap);
|
||||
|
||||
final Path path = new Path();
|
||||
path.addCircle(
|
||||
(float) (width / 2),
|
||||
(float) (height / 2),
|
||||
(float) Math.min(width, (height / 2)),
|
||||
Path.Direction.CCW);
|
||||
|
||||
final Canvas canvas = new Canvas(outputBitmap);
|
||||
if (pref > 0) {
|
||||
path.addRoundRect(new RectF(0, 0, width, height), pref, pref, Path.Direction.CCW);
|
||||
} else {
|
||||
path.addCircle(
|
||||
(float) (width / 2),
|
||||
(float) (height / 2),
|
||||
(float) Math.min(width, (height / 2)),
|
||||
Path.Direction.CCW);
|
||||
}
|
||||
|
||||
canvas.clipPath(path);
|
||||
canvas.drawBitmap(bitmap, 0, 0, null);
|
||||
return outputBitmap;
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
public class LayoutUtils {
|
||||
|
||||
public static int MATCH_PARENT = -1;
|
||||
@@ -24,12 +21,4 @@ public class LayoutUtils {
|
||||
public static FrameLayout.LayoutParams createFrame(int w, int h) {
|
||||
return new FrameLayout.LayoutParams(w, h);
|
||||
}
|
||||
|
||||
public static ViewGroup.LayoutParams createViewGroup(int w, int h) {
|
||||
return new ViewGroup.LayoutParams(w, h);
|
||||
}
|
||||
|
||||
public static ConstraintLayout.LayoutParams createConstraint(int w, int h) {
|
||||
return new ConstraintLayout.LayoutParams(w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
||||
import com.vk.navigation.Navigator;
|
||||
import com.vtosters.lite.VKActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,12 +17,40 @@ import java.util.List;
|
||||
public class LifecycleUtils {
|
||||
private static final List<Activity> activities = new ArrayList<>();
|
||||
|
||||
public static void addActivity(Activity activity) {
|
||||
activities.add(activity);
|
||||
}
|
||||
public static void registerActivities(Application application) {
|
||||
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityPaused(Activity activity) {
|
||||
}
|
||||
|
||||
public static void removeActivity(Activity activity) {
|
||||
activities.remove(activity);
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityResumed(Activity activity) {
|
||||
}
|
||||
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
|
||||
}
|
||||
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityStarted(Activity activity) {
|
||||
}
|
||||
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityStopped(Activity activity) {
|
||||
}
|
||||
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityCreated(Activity activity, Bundle bundle) {
|
||||
if (activity instanceof VKActivity) {
|
||||
activities.add(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
activities.remove(activity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Activity getCurrentActivity() {
|
||||
|
||||
@@ -27,10 +27,12 @@ import ru.vtosters.lite.hooks.JsonInjectors;
|
||||
|
||||
public class NewsFeedFiltersUtils {
|
||||
public static List<String> mFilters;
|
||||
public static List<String> mFiltersNames;
|
||||
public static List<String> mFiltersLinks;
|
||||
|
||||
public static void setupFilters() {
|
||||
mFilters = new ArrayList<>();
|
||||
mFiltersNames = new ArrayList<>();
|
||||
mFiltersLinks = new ArrayList<>();
|
||||
|
||||
getFilter("refsfilter", "Referals.txt", mFilters);
|
||||
@@ -41,12 +43,17 @@ public class NewsFeedFiltersUtils {
|
||||
|
||||
var customFilters = getPrefsValue("spamfilters");
|
||||
if (!customFilters.isEmpty()) {
|
||||
mFilters.addAll(Arrays.asList(customFilters.split(", ")));
|
||||
mFilters.addAll(Arrays.asList(customFilters.toLowerCase().split(", ")));
|
||||
}
|
||||
|
||||
var sourceNameFilter = getPrefsValue("sourcenamefilter");
|
||||
if (!sourceNameFilter.isEmpty()) {
|
||||
mFiltersNames.addAll(Arrays.asList(sourceNameFilter.toLowerCase().split(", ")));
|
||||
}
|
||||
|
||||
var linkFilter = getPrefsValue("linkfilter");
|
||||
if (!linkFilter.isEmpty()) {
|
||||
mFiltersLinks.addAll(Arrays.asList(linkFilter.split(", ")));
|
||||
mFiltersLinks.addAll(Arrays.asList(linkFilter.toLowerCase().split(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,11 +106,15 @@ public class NewsFeedFiltersUtils {
|
||||
if (copyright_post()) return true;
|
||||
|
||||
var copyright = json.optJSONObject("copyright");
|
||||
var copyrightName = copyright.getString("name").toLowerCase();
|
||||
var copyrightLink = copyright.getString("link").toLowerCase();
|
||||
|
||||
for (String filter : mFiltersNames) {
|
||||
if (copyrightName.contains(filter)) return true;
|
||||
}
|
||||
|
||||
for (String filter : mFiltersLinks) {
|
||||
if (copyrightLink.contains(filter)) {
|
||||
return true;
|
||||
}
|
||||
if (copyrightLink.contains(filter)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user