Compare commits
1283 Commits
1.1.4+fork
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32da4f8e09 | ||
|
|
1098c855c4 | ||
|
|
ee8ca09e0e | ||
|
|
ed75a62228 | ||
|
|
c3c76126a3 | ||
|
|
4da6016e06 | ||
|
|
e4f4ca5392 | ||
|
|
9d690e7670 | ||
|
|
e1acfef1bf | ||
|
|
29267dacb4 | ||
|
|
7c8698521d | ||
|
|
fb02689c30 | ||
|
|
74f2bb4707 | ||
|
|
76a85af0d7 | ||
|
|
5d7363585a | ||
|
|
46398f7bad | ||
|
|
7c6087c1f5 | ||
|
|
ed7bcdb761 | ||
|
|
50f9ebe4f7 | ||
|
|
2daf94f91e | ||
|
|
d3b7a60f18 | ||
|
|
1d5bf452ab | ||
|
|
51063b65ae | ||
|
|
198dfc067e | ||
|
|
ab0eed88c4 | ||
|
|
7a036a52ae | ||
|
|
aa5404842b | ||
|
|
a33009a297 | ||
|
|
8b27e6de33 | ||
|
|
4c698cf217 | ||
|
|
05217b7712 | ||
|
|
64e681c227 | ||
|
|
a4515ea360 | ||
|
|
2cea6a9df5 | ||
|
|
d6d6155f2c | ||
|
|
88f498409f | ||
|
|
f39690b7e5 | ||
|
|
0a1c42f90b | ||
|
|
a59587eb62 | ||
|
|
7615723d4f | ||
|
|
804129271b | ||
|
|
ef1b1e5d1f | ||
|
|
fe21a95766 | ||
|
|
6f3cb14dc9 | ||
|
|
1698a32d75 | ||
|
|
1e54b21842 | ||
|
|
99ca3b7acb | ||
|
|
828617f7d7 | ||
|
|
c4d8baf8a2 | ||
|
|
118a073961 | ||
|
|
4b39011497 | ||
|
|
470a693a1f | ||
|
|
1f4970c0d2 | ||
|
|
e9833baaa4 | ||
|
|
325d962bbb | ||
|
|
0aa432bf6e | ||
|
|
1ed891ced8 | ||
|
|
2ebf52d156 | ||
|
|
9d45fc1c84 | ||
|
|
a436573f25 | ||
|
|
76980244ec | ||
|
|
0e6a3ccd72 | ||
|
|
b8869e6460 | ||
|
|
6ec43a6f86 | ||
|
|
df93a1a845 | ||
|
|
41a70a353c | ||
|
|
8d69bcfd4b | ||
|
|
0ef30f82a7 | ||
|
|
be60e78ea6 | ||
|
|
5434325fa8 | ||
|
|
0a04c9357c | ||
|
|
21c4cef397 | ||
|
|
4b2fcd760a | ||
|
|
39ea51c317 | ||
|
|
cd668e1bba | ||
|
|
916bd68a16 | ||
|
|
4aa7ff6f9c | ||
|
|
38fb05a38b | ||
|
|
aa919867c8 | ||
|
|
9824b5fb56 | ||
|
|
78fcf31e34 | ||
|
|
eadb62d3a8 | ||
|
|
f6279fcc0c | ||
|
|
7a350c2685 | ||
|
|
7da2c06670 | ||
|
|
dd4bad706b | ||
|
|
5d253a39b2 | ||
|
|
e84a92fedc | ||
|
|
6bc6aca17e | ||
|
|
a7261bec47 | ||
|
|
6f52e5de76 | ||
|
|
f329f7a241 | ||
|
|
3eaff4cb4c | ||
|
|
9bcae3f893 | ||
|
|
6d094af6d5 | ||
|
|
cf0b1cf035 | ||
|
|
7c11a12e9a | ||
|
|
e244f63949 | ||
|
|
c4a390820d | ||
|
|
1c0b62ac30 | ||
|
|
eacaf214e8 | ||
|
|
1369756e1e | ||
|
|
20803df255 | ||
|
|
80931b8948 | ||
|
|
167597bc9f | ||
|
|
93dcc12f8d | ||
|
|
1287dff879 | ||
|
|
6bf6e38384 | ||
|
|
a1f8cdd76b | ||
|
|
de48c48b49 | ||
|
|
27f0af4f0b | ||
|
|
4226f776c1 | ||
|
|
f1e4eae858 | ||
|
|
4647fd6ee7 | ||
|
|
3a965500e8 | ||
|
|
7a9bb807f0 | ||
|
|
694f0044cc | ||
|
|
27696e4f0f | ||
|
|
7ec3d4d50b | ||
|
|
803b1cd21a | ||
|
|
125d39b019 | ||
|
|
63d1d9f49a | ||
|
|
6832cc8de2 | ||
|
|
f97effb042 | ||
|
|
3e233d1f72 | ||
|
|
f07f1bf0e2 | ||
|
|
8eb66a049e | ||
|
|
9578b139a9 | ||
|
|
4299e15ad2 | ||
|
|
1dceb02e09 | ||
|
|
32bfdd231a | ||
|
|
05b2d603f1 | ||
|
|
e7967eadc5 | ||
|
|
001873998a | ||
|
|
3d834a0c44 | ||
|
|
35dcc44fe8 | ||
|
|
81f4934282 | ||
|
|
f2335ff2d3 | ||
|
|
75161fc694 | ||
|
|
14775aeb67 | ||
|
|
5979341fb9 | ||
|
|
d86509233f | ||
|
|
d6d45cd9a5 | ||
|
|
21e940c94d | ||
|
|
f3ad600c94 | ||
|
|
72e0a9c32e | ||
|
|
c791833fbe | ||
|
|
bcac023d33 | ||
|
|
7459181fa9 | ||
|
|
ef19a1ad09 | ||
|
|
41446cde38 | ||
|
|
44509bb274 | ||
|
|
54d9c315e5 | ||
|
|
9f8f7adb26 | ||
|
|
c2341070f5 | ||
|
|
20af9eb6f4 | ||
|
|
36bb1ea8af | ||
|
|
7d43105925 | ||
|
|
ebb3f3c5ae | ||
|
|
271815fa53 | ||
|
|
8570bdb4c0 | ||
|
|
092a089580 | ||
|
|
f2af2cd9af | ||
|
|
2a8e4231b4 | ||
|
|
c3cb082de8 | ||
|
|
20b6d15c2e | ||
|
|
5ec762ac0d | ||
|
|
7f44c48c12 | ||
|
|
2a071bc5de | ||
|
|
ded9b70483 | ||
|
|
0019f2183a | ||
|
|
68f77a6c8a | ||
|
|
a4d07d4307 | ||
|
|
903e844aad | ||
|
|
a6b299b029 | ||
|
|
05f9ae8d76 | ||
|
|
314afed9de | ||
|
|
ebdd1a0b03 | ||
|
|
6c44575f7a | ||
|
|
8be832239a | ||
|
|
c7be202430 | ||
|
|
244c5dc6b4 | ||
|
|
6bbb9a638e | ||
|
|
44041b136a | ||
|
|
7e17c30ce2 | ||
|
|
c4d3d1b409 | ||
|
|
03de63754b | ||
|
|
0e506f0b1a | ||
|
|
a2ab752870 | ||
|
|
eaa032828a | ||
|
|
cceb0b4c6c | ||
|
|
a58640a718 | ||
|
|
920384b26c | ||
|
|
880c34c3f0 | ||
|
|
6d7bf34f51 | ||
|
|
bc10a9fcf5 | ||
|
|
193a2c4f70 | ||
|
|
793dec98b2 | ||
|
|
11ddf8015d | ||
|
|
b6d969bc7b | ||
|
|
b799b54c9e | ||
|
|
5389f05ea8 | ||
|
|
b4bf4a5bf5 | ||
|
|
6d9c87c9bc | ||
|
|
1753bdbd8b | ||
|
|
d6e563486b | ||
|
|
e8abc0bbd2 | ||
|
|
0112bfa9c4 | ||
|
|
5951611fb0 | ||
|
|
0589612df9 | ||
|
|
af2d951b50 | ||
|
|
132b672441 | ||
|
|
ffb7cc5c18 | ||
|
|
5a9a3eb140 | ||
|
|
5395855775 | ||
|
|
9d60924512 | ||
|
|
1680c635dc | ||
|
|
898fbcc52b | ||
|
|
d0e4578af0 | ||
|
|
2d31b726ac | ||
|
|
d2f295ef88 | ||
|
|
d1b53554ce | ||
|
|
ec5db122d0 | ||
|
|
0216e22fcc | ||
|
|
5734b19d8c | ||
|
|
cc8c818e13 | ||
|
|
e58aeec097 | ||
|
|
58b000927a | ||
|
|
797642b972 | ||
|
|
2e1f273d78 | ||
|
|
35d6800877 | ||
|
|
781856b822 | ||
|
|
ff272179e7 | ||
|
|
bec47f40f7 | ||
|
|
f9607a434a | ||
|
|
b650ca85bc | ||
|
|
4ceacae954 | ||
|
|
56e5877040 | ||
|
|
91e154bbee | ||
|
|
f4365ed163 | ||
|
|
0c02b0cb68 | ||
|
|
b0aaa58fa7 | ||
|
|
054ab774d5 | ||
|
|
8ca33b552d | ||
|
|
6734c2b9f7 | ||
|
|
c484477d6a | ||
|
|
d9b5223749 | ||
|
|
55856450b3 | ||
|
|
bb28a3bf83 | ||
|
|
c0484de506 | ||
|
|
addb1b27bb | ||
|
|
96ecdcd33c | ||
|
|
e3f445cbed | ||
|
|
8ccb505165 | ||
|
|
98c193ac51 | ||
|
|
b966d5626b | ||
|
|
9c01f7a522 | ||
|
|
f3c9f52d37 | ||
|
|
1df61780a3 | ||
|
|
2be3bca70e | ||
|
|
18ec63b9b4 | ||
|
|
6781fb6e25 | ||
|
|
852bc6ba24 | ||
|
|
223aa7043b | ||
|
|
3178b5f41c | ||
|
|
14665c9a24 | ||
|
|
ea823ef0cf | ||
|
|
62d5c7a492 | ||
|
|
287e75e54a | ||
|
|
02af385853 | ||
|
|
ede2a3e0b5 | ||
|
|
66dab9194a | ||
|
|
6e5fa34be6 | ||
|
|
8ce782b578 | ||
|
|
05168b9826 | ||
|
|
5208195f72 | ||
|
|
5e4e56bd2c | ||
|
|
82fac1d4e7 | ||
|
|
1dc90f930a | ||
|
|
aa56d160e6 | ||
|
|
452eac6fd7 | ||
|
|
d37a2b9db7 | ||
|
|
14e2747599 | ||
|
|
bf9afba590 | ||
|
|
b667afc7cd | ||
|
|
21b0736842 | ||
|
|
8bd3c7cc28 | ||
|
|
4db90b87f4 | ||
|
|
46fd0be0eb | ||
|
|
05a966869b | ||
|
|
6fef51fcbb | ||
|
|
ae7b2f3fc7 | ||
|
|
d5b6c02b22 | ||
|
|
6cd722dbef | ||
|
|
8dfc1ecae8 | ||
|
|
fdca799a5f | ||
|
|
def79e591b | ||
|
|
093a27970d | ||
|
|
9a1e33a776 | ||
|
|
a4a206eae6 | ||
|
|
21ee5fc2bf | ||
|
|
7df72e6bc6 | ||
|
|
9ceea8de99 | ||
|
|
79d48a12a9 | ||
|
|
473d3a5196 | ||
|
|
43717634f6 | ||
|
|
6ba8555adf | ||
|
|
722ad8c53e | ||
|
|
b0b497ed46 | ||
|
|
6c881eccd2 | ||
|
|
94b92bd7c1 | ||
|
|
676b195aee | ||
|
|
4591731cdc | ||
|
|
fc5eeae9e7 | ||
|
|
aaa88c45f7 | ||
|
|
5d91e8030c | ||
|
|
c9be188d19 | ||
|
|
ecc8daa8f1 | ||
|
|
5bbe11bf45 | ||
|
|
e52170abea | ||
|
|
0f87fc7924 | ||
|
|
cc7c4fc95f | ||
|
|
4a2dcdf701 | ||
|
|
ede47af962 | ||
|
|
70e4cb2286 | ||
|
|
f4007dba90 | ||
|
|
c5e8460516 | ||
|
|
f852dac1e5 | ||
|
|
374626cb32 | ||
|
|
aefa0b89ae | ||
|
|
9cc8b2668c | ||
|
|
94b862a3ff | ||
|
|
f71bb6b78c | ||
|
|
499ac8f727 | ||
|
|
938ae97cac | ||
|
|
e2193e8e3c | ||
|
|
d687abcdc1 | ||
|
|
16f907c91f | ||
|
|
584700225c | ||
|
|
bad72985cb | ||
|
|
56b24420d1 | ||
|
|
92beac8dff | ||
|
|
ed1fdba9a5 | ||
|
|
5e194e3079 | ||
|
|
27c2791d6c | ||
|
|
d6bcc9c156 | ||
|
|
4c85fd4387 | ||
|
|
80d529d503 | ||
|
|
c5a19a2334 | ||
|
|
16857bebd9 | ||
|
|
1c340b7c66 | ||
|
|
7d9d8f0aae | ||
|
|
21fc35230c | ||
|
|
fc67c82040 | ||
|
|
a9b828001c | ||
|
|
be050abf7e | ||
|
|
2d071ca252 | ||
|
|
abf94e1e70 | ||
|
|
2991c7421c | ||
|
|
834f84f995 | ||
|
|
6bf713c96c | ||
|
|
72b16be297 | ||
|
|
0c7f27b3ac | ||
|
|
6fa930aa9f | ||
|
|
736ec4dbf9 | ||
|
|
04ed9e76f2 | ||
|
|
811304c0c7 | ||
|
|
ca101748eb | ||
|
|
3584c123d6 | ||
|
|
9a991b8f33 | ||
|
|
a2fd4be339 | ||
|
|
656364db60 | ||
|
|
884347da12 | ||
|
|
675c49a922 | ||
|
|
4d04741fe0 | ||
|
|
5c7fe9dcb5 | ||
|
|
a3146d6cdd | ||
|
|
d769f757ed | ||
|
|
b28b70c6b8 | ||
|
|
c2c5b08659 | ||
|
|
7460b24fb0 | ||
|
|
2531015094 | ||
|
|
2efdf09333 | ||
|
|
30582bf8e3 | ||
|
|
654e3eb36b | ||
|
|
67e3244655 | ||
|
|
f793bbc711 | ||
|
|
94634781c4 | ||
|
|
0fbbdb6621 | ||
|
|
d3f2049c7d | ||
|
|
134b1edb19 | ||
|
|
2489b57e42 | ||
|
|
ee56ad07e9 | ||
|
|
e1853cb1f0 | ||
|
|
ee79916104 | ||
|
|
f62ba685d1 | ||
|
|
c3aa3af650 | ||
|
|
fb44015402 | ||
|
|
8cc5678b38 | ||
|
|
592eb2d589 | ||
|
|
84713eb3b7 | ||
|
|
d95b395cfc | ||
|
|
b41b2c8f3c | ||
|
|
289dc4bf86 | ||
|
|
c34e1e5f32 | ||
|
|
729680df8c | ||
|
|
b85b578ddd | ||
|
|
8a7d2df7b8 | ||
|
|
3ff3eb819a | ||
|
|
1ea24b5ff6 | ||
|
|
79d0ab311b | ||
|
|
79f7df089e | ||
|
|
32464f8552 | ||
|
|
7ce96a2311 | ||
|
|
a009ea212f | ||
|
|
8848b75325 | ||
|
|
2eb04a3835 | ||
|
|
b61ce8399e | ||
|
|
52392c9ed9 | ||
|
|
4b35ac6ad8 | ||
|
|
a56b603c5c | ||
|
|
48bd277769 | ||
|
|
04101eb31b | ||
|
|
34c6a76a53 | ||
|
|
3f20c6104a | ||
|
|
b5f82261b0 | ||
|
|
b9a5db7ea4 | ||
|
|
64cb6e52a8 | ||
|
|
6e96e8929f | ||
|
|
bdd48f0001 | ||
|
|
4bf19adc8e | ||
|
|
bb9ff3c33f | ||
|
|
ae11e78d78 | ||
|
|
222c3a2526 | ||
|
|
08aa64a666 | ||
|
|
f10c157598 | ||
|
|
5059d8fc4f | ||
|
|
4152179dea | ||
|
|
3619be71ab | ||
|
|
0bf31de1f1 | ||
|
|
7fd32cab3d | ||
|
|
4a695b2a83 | ||
|
|
a8ba50e762 | ||
|
|
f79fc66578 | ||
|
|
810e9eeb11 | ||
|
|
25cff94665 | ||
|
|
0c63b99e6c | ||
|
|
5881f5fa05 | ||
|
|
0e08209f4c | ||
|
|
db0b4fb615 | ||
|
|
672cfe58d6 | ||
|
|
338e164143 | ||
|
|
e964b76302 | ||
|
|
8dedc77ff8 | ||
|
|
5e8ede6ab8 | ||
|
|
1124bab96b | ||
|
|
cbcdf09bfe | ||
|
|
3b762c14a1 | ||
|
|
59941fc867 | ||
|
|
50601853f5 | ||
|
|
3137f3c1e4 | ||
|
|
575ca6251c | ||
|
|
bfaa732544 | ||
|
|
9c83a5aaeb | ||
|
|
bc3e46eae1 | ||
|
|
1b7a257a48 | ||
|
|
4d40fad10d | ||
|
|
49015f3e3e | ||
|
|
77b5819c65 | ||
|
|
ac5615497b | ||
|
|
4ecd525f13 | ||
|
|
6756b36e87 | ||
|
|
36808e4e8e | ||
|
|
1c38570609 | ||
|
|
2dc6deb93a | ||
|
|
0b58d19811 | ||
|
|
50362d630b | ||
|
|
bfcd67cbaf | ||
|
|
ea190c0597 | ||
|
|
e68160800d | ||
|
|
73481f4a1f | ||
|
|
0303e59fc1 | ||
|
|
0c0d36da62 | ||
|
|
e7e0b8841c | ||
|
|
e7cd1cfda2 | ||
|
|
17afa8e6f5 | ||
|
|
8385fb9586 | ||
|
|
ba44aa57d7 | ||
|
|
a70647da44 | ||
|
|
f97aafe374 | ||
|
|
b38a460a02 | ||
|
|
bddf024ba0 | ||
|
|
be7a7acadd | ||
|
|
d05c90ca7f | ||
|
|
79d9abe7f7 | ||
|
|
684fbc0050 | ||
|
|
03973d41be | ||
|
|
06c533bf5a | ||
|
|
cc64a20e53 | ||
|
|
4187da9168 | ||
|
|
a051e636e6 | ||
|
|
4144639b75 | ||
|
|
360cd7b5df | ||
|
|
55d2ca4a93 | ||
|
|
c7f61291ed | ||
|
|
f836361644 | ||
|
|
f404895b5c | ||
|
|
94ed0c3f49 | ||
|
|
00ffe9c41e | ||
|
|
529c1e2b07 | ||
|
|
f2e04e6769 | ||
|
|
f1a7603bdf | ||
|
|
280434b01f | ||
|
|
023a6c3a49 | ||
|
|
ed301cafe0 | ||
|
|
5e97adcd3b | ||
|
|
487deae044 | ||
|
|
a28daa3d75 | ||
|
|
d633b6f1d4 | ||
|
|
75f311b8a7 | ||
|
|
7b68baef0d | ||
|
|
fb5ef921f7 | ||
|
|
5d11bee59d | ||
|
|
da44e50679 | ||
|
|
cd027f1220 | ||
|
|
93d89f93b2 | ||
|
|
cce64f9a76 | ||
|
|
1d55354be2 | ||
|
|
3143f28e04 | ||
|
|
d381205bbf | ||
|
|
6b6852e134 | ||
|
|
f7a41906e4 | ||
|
|
70ddea2e81 | ||
|
|
92a806462d | ||
|
|
8111ea04b9 | ||
|
|
afb396acd8 | ||
|
|
371f97fa5a | ||
|
|
f7def3ab01 | ||
|
|
1cefc8aaf2 | ||
|
|
a72849bae1 | ||
|
|
5e6b56a738 | ||
|
|
58c754ea2d | ||
|
|
c22374b712 | ||
|
|
7820926e1a | ||
|
|
fcf5887359 | ||
|
|
aade898681 | ||
|
|
d6653b5f78 | ||
|
|
89514dbf14 | ||
|
|
456fbb6fc9 | ||
|
|
f2d29366bd | ||
|
|
ea7c366981 | ||
|
|
fe7362bb28 | ||
|
|
a4d739a9a9 | ||
|
|
d4cf12a0d9 | ||
|
|
69af790e22 | ||
|
|
2936ec81af | ||
|
|
d8cd151c7e | ||
|
|
1ada4c9f46 | ||
|
|
b5844a5f8c | ||
|
|
6f37eb9625 | ||
|
|
6404d9cf9a | ||
|
|
1837e5204b | ||
|
|
9ae0f49bff | ||
|
|
269794bfc3 | ||
|
|
0943908173 | ||
|
|
ef1965a41b | ||
|
|
b018788cd1 | ||
|
|
4a315e73eb | ||
|
|
a445baf3f0 | ||
|
|
08a3ec99ce | ||
|
|
68f88c29d3 | ||
|
|
c2d14c64cb | ||
|
|
aa554d91f7 | ||
|
|
cc3845d6f4 | ||
|
|
2571b2d4f7 | ||
|
|
ac7cdb885d | ||
|
|
7b5d95f7ee | ||
|
|
ccf311312e | ||
|
|
42222cd327 | ||
|
|
60961020c8 | ||
|
|
2a7bba24de | ||
|
|
fdbe3fcb13 | ||
|
|
9e9ff07eaf | ||
|
|
f377dca63c | ||
|
|
3074100432 | ||
|
|
ce67fb30bf | ||
|
|
da5f3a9094 | ||
|
|
e12d19d0d6 | ||
|
|
f6a35e92c7 | ||
|
|
d0a9ba041d | ||
|
|
1e2dd3dec6 | ||
|
|
7ea42c8403 | ||
|
|
af9b527f35 | ||
|
|
df58cdd86e | ||
|
|
507fcea646 | ||
|
|
5cd1e88da9 | ||
|
|
e2293899f0 | ||
|
|
1c743ee3a6 | ||
|
|
daf4c69df4 | ||
|
|
14d3add7b3 | ||
|
|
7e3193a708 | ||
|
|
545aa16cd3 | ||
|
|
4dcf32d13a | ||
|
|
e0aba23e80 | ||
|
|
b19ae9bb10 | ||
|
|
d20f8669e8 | ||
|
|
1567e5aba4 | ||
|
|
b01ef6d5a7 | ||
|
|
604e581139 | ||
|
|
082f697b40 | ||
|
|
3d7683cb67 | ||
|
|
73a564abfd | ||
|
|
672caefbb9 | ||
|
|
1b8a9ed577 | ||
|
|
d4a377e75f | ||
|
|
6b9b6710cf | ||
|
|
d07d714641 | ||
|
|
b07858a66d | ||
|
|
c05d0b600e | ||
|
|
2b7f325332 | ||
|
|
611a89e7b6 | ||
|
|
3d4192b679 | ||
|
|
0a8d73dc0b | ||
|
|
fd99f3caa1 | ||
|
|
794c4e5227 | ||
|
|
f5df8225d1 | ||
|
|
42c6446125 | ||
|
|
e3486ebf7c | ||
|
|
c0115f068c | ||
|
|
41682d1147 | ||
|
|
45357c6932 | ||
|
|
d2f0c3f7e5 | ||
|
|
6b52ba22cb | ||
|
|
baf12371e7 | ||
|
|
5aa4cf3dd9 | ||
|
|
25156c2f08 | ||
|
|
6aa44a5aef | ||
|
|
0d10c63c44 | ||
|
|
6d7f945e65 | ||
|
|
b36ad322c5 | ||
|
|
282e04b839 | ||
|
|
8c61660cfc | ||
|
|
d6933be3cd | ||
|
|
953fd48fe2 | ||
|
|
82fdf3d067 | ||
|
|
fcb9a10475 | ||
|
|
3edb8f7a23 | ||
|
|
32ae1d095d | ||
|
|
ca6cfd2b91 | ||
|
|
70c10b3df3 | ||
|
|
20960bdd57 | ||
|
|
dd582c4bee | ||
|
|
3a0d314af0 | ||
|
|
33b62cf9aa | ||
|
|
5534e5909b | ||
|
|
3eee865620 | ||
|
|
9d447f6256 | ||
|
|
22c5aac283 | ||
|
|
312437fb5c | ||
|
|
04952a0bee | ||
|
|
002edc8890 | ||
|
|
a00ca599c1 | ||
|
|
263b5b10b6 | ||
|
|
1068fa3120 | ||
|
|
569f288c00 | ||
|
|
dfd94511a5 | ||
|
|
2271f336b0 | ||
|
|
4486feee76 | ||
|
|
baaff2573c | ||
|
|
b9c3b23757 | ||
|
|
0c1fd22253 | ||
|
|
466c489b4d | ||
|
|
625f715e26 | ||
|
|
61caec4060 | ||
|
|
df233eb1e2 | ||
|
|
78225c482f | ||
|
|
c55703f0ba | ||
|
|
3b26dd44a0 | ||
|
|
2a1386a87a | ||
|
|
fb32430f96 | ||
|
|
2288c53adc | ||
|
|
84b7b67045 | ||
|
|
d233f039a3 | ||
|
|
8b01955a18 | ||
|
|
427aa1722d | ||
|
|
2a7eb09998 | ||
|
|
f2f48fce79 | ||
|
|
634408b8cb | ||
|
|
f050e3f22d | ||
|
|
8e9531b718 | ||
|
|
00457c1edb | ||
|
|
aa14986fcc | ||
|
|
1493cd9034 | ||
|
|
b2b295ee5b | ||
|
|
58847f80fd | ||
|
|
ed9db7b5fd | ||
|
|
433a7c6b7a | ||
|
|
7692f587ef | ||
|
|
67583150b2 | ||
|
|
ed49422f76 | ||
|
|
63078aaa3e | ||
|
|
9246c43ffe | ||
|
|
15f02863c0 | ||
|
|
be1921879d | ||
|
|
61b43e0112 | ||
|
|
b25b482630 | ||
|
|
1d44875a65 | ||
|
|
0dc5004898 | ||
|
|
0df86e315b | ||
|
|
31d3fa77de | ||
|
|
ec74b18c1a | ||
|
|
de36c31f45 | ||
|
|
43bcf0008e | ||
|
|
ac64087018 | ||
|
|
af77865a46 | ||
|
|
51a4a41147 | ||
|
|
987474462d | ||
|
|
c34ab79c6c | ||
|
|
8bac664a34 | ||
|
|
d77647c354 | ||
|
|
e8ef6ef2c7 | ||
|
|
a87cf640dd | ||
|
|
bcb69f1f47 | ||
|
|
0bdcc9057b | ||
|
|
f92977fddf | ||
|
|
230a59266d | ||
|
|
d97f3ed5c8 | ||
|
|
aae2cd2b65 | ||
|
|
8b8763bffc | ||
|
|
35758e720d | ||
|
|
fa48c80ab1 | ||
|
|
1621dbc67a | ||
|
|
4ece7b883f | ||
|
|
66a5b749fe | ||
|
|
49a80767a7 | ||
|
|
7683b464f3 | ||
|
|
3a9d187727 | ||
|
|
affd69c577 | ||
|
|
deaca28fe8 | ||
|
|
37432ef21c | ||
|
|
79f500098b | ||
|
|
b5acaaf369 | ||
|
|
6aeca9ba26 | ||
|
|
95b28d30f7 | ||
|
|
5b4be77ded | ||
|
|
462457cf09 | ||
|
|
cc9012516a | ||
|
|
d716891453 | ||
|
|
71ffaad660 | ||
|
|
210349523f | ||
|
|
b883ed1e40 | ||
|
|
f4431fb00f | ||
|
|
b877488aa9 | ||
|
|
a4e3774739 | ||
|
|
64fbbb2f07 | ||
|
|
c8580979e8 | ||
|
|
9003f690d1 | ||
|
|
0aac29545f | ||
|
|
94a3d994fd | ||
|
|
043526f883 | ||
|
|
1a1f9e5cb1 | ||
|
|
3f2dd91749 | ||
|
|
ac1e000645 | ||
|
|
acdd203c26 | ||
|
|
caf07a60ea | ||
|
|
8ffaca61bd | ||
|
|
a26c835134 | ||
|
|
363ceed2ad | ||
|
|
f6c3b10c2b | ||
|
|
46c9bd9807 | ||
|
|
4d23daf461 | ||
|
|
31b50d705f | ||
|
|
66932ccd4c | ||
|
|
d0cddff330 | ||
|
|
94a5807619 | ||
|
|
2c1be165f4 | ||
|
|
ddc4a8c46d | ||
|
|
c255fb5e58 | ||
|
|
d6705ba991 | ||
|
|
c3c9af872b | ||
|
|
4f3e2f69d6 | ||
|
|
ec01da10f5 | ||
|
|
3015fa9b97 | ||
|
|
0ca2c4acb2 | ||
|
|
1180ac2d9f | ||
|
|
bc8fce60ec | ||
|
|
41f0679102 | ||
|
|
2a0d0d0811 | ||
|
|
6f234fddf7 | ||
|
|
83c850b782 | ||
|
|
2780363dab | ||
|
|
7273040c4d | ||
|
|
f7de52dfe7 | ||
|
|
fffa86d1b3 | ||
|
|
cae456278a | ||
|
|
d2808e9599 | ||
|
|
07f35723b6 | ||
|
|
5739b26eb2 | ||
|
|
9da7d899a6 | ||
|
|
b6a7649b94 | ||
|
|
8e2270d720 | ||
|
|
f92dcac291 | ||
|
|
e5cf8e3511 | ||
|
|
38b0cc3320 | ||
|
|
5fdd476277 | ||
|
|
c05f1d45fb | ||
|
|
01135937cc | ||
|
|
1e4cc8edb1 | ||
|
|
aa7beef17a | ||
|
|
f8e117fff1 | ||
|
|
494fab52fa | ||
|
|
d68a3a6ef5 | ||
|
|
4475bd039a | ||
|
|
98dc7d0524 | ||
|
|
65948030a6 | ||
|
|
89edfaaa6d | ||
|
|
10372804e4 | ||
|
|
d1dd7d203b | ||
|
|
c6aed0b52e | ||
|
|
5f902d25a9 | ||
|
|
c43bed665d | ||
|
|
d70a2ae5b3 | ||
|
|
1fdf36b4d8 | ||
|
|
5d1cd0f4f6 | ||
|
|
3505460372 | ||
|
|
eeb91e867e | ||
|
|
c87062ee31 | ||
|
|
fb66fa1c6f | ||
|
|
f80af9f5bf | ||
|
|
85157ffe25 | ||
|
|
59f95159b7 | ||
|
|
703dbd4c8a | ||
|
|
1e75f9f1c2 | ||
|
|
d0860333a9 | ||
|
|
64b3951c25 | ||
|
|
e89e6cc3f5 | ||
|
|
3c2985fa6e | ||
|
|
bee01429f2 | ||
|
|
a96431cc00 | ||
|
|
bf9e6f54cf | ||
|
|
63084857a3 | ||
|
|
d8b7038972 | ||
|
|
976e71db25 | ||
|
|
2b59c2c080 | ||
|
|
5929b0c6b9 | ||
|
|
e160a05411 | ||
|
|
78d8f075a9 | ||
|
|
3784873cad | ||
|
|
528f8aaead | ||
|
|
4ba9f1ecaf | ||
|
|
697a666545 | ||
|
|
0ee6798424 | ||
|
|
9a95deb346 | ||
|
|
0155ef2675 | ||
|
|
858195f813 | ||
|
|
b681c7dfeb | ||
|
|
b89f931ffd | ||
|
|
1658e56729 | ||
|
|
2b7d8292ed | ||
|
|
494abdfeee | ||
|
|
426f3fe95b | ||
|
|
b7a96778b8 | ||
|
|
125cd525bf | ||
|
|
ed281a4619 | ||
|
|
f418a5a2c4 | ||
|
|
6d8971df64 | ||
|
|
8dd3343906 | ||
|
|
f65fc9299a | ||
|
|
ac00889001 | ||
|
|
7af0a3f351 | ||
|
|
2734f88206 | ||
|
|
c6cd8ca14b | ||
|
|
2fd61f738f | ||
|
|
d3575b60fe | ||
|
|
dce8808d62 | ||
|
|
db97dadb25 | ||
|
|
34116d9914 | ||
|
|
bc676e6eb3 | ||
|
|
ef2cb31b6c | ||
|
|
c45dc96316 | ||
|
|
f9b34b53c1 | ||
|
|
e128e144b1 | ||
|
|
c68ed6088f | ||
|
|
b66ad0e6f5 | ||
|
|
02a470bd7d | ||
|
|
9407bd9e86 | ||
|
|
825adda664 | ||
|
|
0a22c14eec | ||
|
|
5452da6a65 | ||
|
|
ffb321e36f | ||
|
|
eaecff52c9 | ||
|
|
e7e3d94add | ||
|
|
b141a9ac74 | ||
|
|
a890f21ace | ||
|
|
4e72e5c234 | ||
|
|
1def56057a | ||
|
|
d99f6c7167 | ||
|
|
0d5d169e5f | ||
|
|
90e55c1043 | ||
|
|
780c5c345c | ||
|
|
c2bc0a4055 | ||
|
|
8032de4595 | ||
|
|
bd3f5018ed | ||
|
|
e9cd29c59e | ||
|
|
91c4e5e51f | ||
|
|
ca1cb668f3 | ||
|
|
a12ca697ed | ||
|
|
3ccb629a4e | ||
|
|
4db041c28f | ||
|
|
bdcf4a5438 | ||
|
|
c042050295 | ||
|
|
f87a87aba1 | ||
|
|
b3a88c4a7c | ||
|
|
9729663cb4 | ||
|
|
f66e6197d3 | ||
|
|
4ff940030d | ||
|
|
da8b88dfc6 | ||
|
|
ed13b1074d | ||
|
|
c5e985f6a4 | ||
|
|
160bb4e272 | ||
|
|
f89a3e644a | ||
|
|
4cfd0db899 | ||
|
|
c6cb992b92 | ||
|
|
1b3ea6cdbe | ||
|
|
79323e392b | ||
|
|
c6c985c1db | ||
|
|
8988b22a52 | ||
|
|
692ede503c | ||
|
|
3be04343b8 | ||
|
|
521157315b | ||
|
|
b4d7b34767 | ||
|
|
f912e90691 | ||
|
|
61ff2ce7e4 | ||
|
|
0316ec340a | ||
|
|
3975e8c280 | ||
|
|
37c40e4a8d | ||
|
|
7dc691deae | ||
|
|
ab5dfe6f62 | ||
|
|
b445e6f79f | ||
|
|
5f0cd72303 | ||
|
|
53dfa08300 | ||
|
|
321c23c52e | ||
|
|
dd6cb4af74 | ||
|
|
54b6aaec09 | ||
|
|
624d21d18b | ||
|
|
5c27155507 | ||
|
|
35552cfbef | ||
|
|
31bbeef24e | ||
|
|
5ee42c0294 | ||
|
|
3d08f768f8 | ||
|
|
603e3d7d65 | ||
|
|
eb8f71aa31 | ||
|
|
c7b5b41128 | ||
|
|
98dbff38ff | ||
|
|
d9317f6eb1 | ||
|
|
4b5dff8742 | ||
|
|
2256ef6232 | ||
|
|
182bc09023 | ||
|
|
a60e5040ea | ||
|
|
327426e443 | ||
|
|
c2a6e17fa5 | ||
|
|
85931e2a65 | ||
|
|
da94cd801b | ||
|
|
594570f9a1 | ||
|
|
548a14ab60 | ||
|
|
40016332ff | ||
|
|
2b9746232b | ||
|
|
1fe31e9262 | ||
|
|
b2a152a728 | ||
|
|
f93d9a0c35 | ||
|
|
af9d9c3f48 | ||
|
|
5cae41a500 | ||
|
|
d6c560e015 | ||
|
|
a2679a3841 | ||
|
|
d826e0172b | ||
|
|
f593f5eb58 | ||
|
|
d29565af9c | ||
|
|
7c3cef32ed | ||
|
|
2c15796108 | ||
|
|
553a3ef7e1 | ||
|
|
a7dfb671ce | ||
|
|
929218d74c | ||
|
|
a5ec9695df | ||
|
|
2784828a93 | ||
|
|
84657e9529 | ||
|
|
110375462e | ||
|
|
09e385633e | ||
|
|
f7410a510f | ||
|
|
20511fd39d | ||
|
|
dbacbe0341 | ||
|
|
bd8da39a19 | ||
|
|
675a353494 | ||
|
|
7b23ca1c96 | ||
|
|
61e8c6f435 | ||
|
|
a41b8dbb01 | ||
|
|
fe525f9242 | ||
|
|
7cbae9c0a9 | ||
|
|
93ac0a103f | ||
|
|
3b11787984 | ||
|
|
7b6fcaf3db | ||
|
|
11b838f394 | ||
|
|
38bd5eb68e | ||
|
|
1dc8d66b3f | ||
|
|
9f64e56923 | ||
|
|
a9e84678b3 | ||
|
|
d7c5c0074d | ||
|
|
97e148f4c8 | ||
|
|
e83bd039b3 | ||
|
|
a30d288b13 | ||
|
|
ded14711ac | ||
|
|
cece9d4aa1 | ||
|
|
f7f56c7a9b | ||
|
|
613a9de40e | ||
|
|
9ed8ad1382 | ||
|
|
7498118800 | ||
|
|
b894827607 | ||
|
|
cc4483dea1 | ||
|
|
8788fb0b27 | ||
|
|
62d4c62888 | ||
|
|
572d092f88 | ||
|
|
8bce03fad3 | ||
|
|
2ff771391c | ||
|
|
087e55277c | ||
|
|
a2d45fbbc5 | ||
|
|
59262fe345 | ||
|
|
ffc36f7346 | ||
|
|
549ace65f5 | ||
|
|
c76bec2298 | ||
|
|
290e47386e | ||
|
|
3d96475c21 | ||
|
|
b62fe06187 | ||
|
|
c0dc2b8392 | ||
|
|
e777bbb215 | ||
|
|
014f9f4d99 | ||
|
|
86bfd3d09f | ||
|
|
21d6f6da4c | ||
|
|
f826e0ceef | ||
|
|
458ad0f51a | ||
|
|
9a0ff42ec2 | ||
|
|
18dae448ec | ||
|
|
fc36a8cc8f | ||
|
|
a390df2b9e | ||
|
|
6f61d3f0e3 | ||
|
|
3a4e8ebdf4 | ||
|
|
537242b277 | ||
|
|
97eece59ea | ||
|
|
fc88d42e50 | ||
|
|
ec74712e55 | ||
|
|
12e1ccf439 | ||
|
|
24b8d5ce7c | ||
|
|
46c9c83b63 | ||
|
|
526a9fec03 | ||
|
|
ca20f3b906 | ||
|
|
af8c8a6248 | ||
|
|
2940e5d3d8 | ||
|
|
c98b001c9f | ||
|
|
1fc1c95d6e | ||
|
|
e4d0c4eda5 | ||
|
|
801d11c8e6 | ||
|
|
8143374929 | ||
|
|
df2ff9f874 | ||
|
|
4bac852d37 | ||
|
|
862a173392 | ||
|
|
bd47b31c65 | ||
|
|
aefb7f2e23 | ||
|
|
e509b8afa4 | ||
|
|
7b94f7258f | ||
|
|
8d81efae4e | ||
|
|
5b0b80277c | ||
|
|
60293d5a65 | ||
|
|
09b4aff9f5 | ||
|
|
7326cbeb14 | ||
|
|
91bd3fa4ea | ||
|
|
3cc6a9905e | ||
|
|
f01bfcd372 | ||
|
|
81b4365a14 | ||
|
|
7ab28a6db6 | ||
|
|
3bb548cf22 | ||
|
|
ba788d1b34 | ||
|
|
f51b01bcd9 | ||
|
|
361c97a9df | ||
|
|
f34153e601 | ||
|
|
67240acb48 | ||
|
|
4395dbfa7c | ||
|
|
48b0207636 | ||
|
|
f7b8ed519c | ||
|
|
eba88f2c0a | ||
|
|
8d95355727 | ||
|
|
e05a67c4ab | ||
|
|
5db91627a1 | ||
|
|
7e473aa8a8 | ||
|
|
1e1edd698d | ||
|
|
aa42a0a4c4 | ||
|
|
ad61596f66 | ||
|
|
bd518b3038 | ||
|
|
db3129ab11 | ||
|
|
57a38a83e4 | ||
|
|
c0de43e2f3 | ||
|
|
c6e29c9ce4 | ||
|
|
35e8f5eddf | ||
|
|
40ed72aeff | ||
|
|
75033cf42e | ||
|
|
4a29a63d50 | ||
|
|
595a6847dc | ||
|
|
64f403b644 | ||
|
|
314517c378 | ||
|
|
b90fc55b3f | ||
|
|
cd57966810 | ||
|
|
8c0851e2b5 | ||
|
|
b9efa434d2 | ||
|
|
adc085a313 | ||
|
|
a2a2f67239 | ||
|
|
c30fba61ca | ||
|
|
f09b37d28f | ||
|
|
6cbc89b01d | ||
|
|
ffd538fbd0 | ||
|
|
1f27f66432 | ||
|
|
25f302f62f | ||
|
|
d54eb6ed73 | ||
|
|
24a6d77777 | ||
|
|
5cbebe7ec6 | ||
|
|
a31c310ffa | ||
|
|
752d0b5ca9 | ||
|
|
170131188a | ||
|
|
3269613139 | ||
|
|
52cc74fb85 | ||
|
|
d7d09b1d56 | ||
|
|
797f2b5929 | ||
|
|
fa5053fe38 | ||
|
|
c682c249bd | ||
|
|
01c229c7c1 | ||
|
|
83f39d6b22 | ||
|
|
715ec6e7c6 | ||
|
|
b6fa34e87f | ||
|
|
6ff14cc7a1 | ||
|
|
d606ce89e0 | ||
|
|
41e80f1d24 | ||
|
|
8decd66e26 | ||
|
|
c033849fb4 | ||
|
|
14054b2198 | ||
|
|
3c3a6712bd | ||
|
|
6a97ed41e0 | ||
|
|
bfedd6c953 | ||
|
|
23d72346b3 | ||
|
|
e9510875ea | ||
|
|
84d7b6c48f | ||
|
|
5f4af7024d | ||
|
|
3b16eb807e | ||
|
|
ef6b52049f | ||
|
|
a7b035bb8e | ||
|
|
645216b8eb | ||
|
|
2b1c18635e | ||
|
|
bb7a76617e | ||
|
|
ab50e7861a | ||
|
|
d52b88c816 | ||
|
|
e5d0a2a14c | ||
|
|
11e9db7ded | ||
|
|
23c1a78d01 | ||
|
|
e524423191 | ||
|
|
7286e71442 | ||
|
|
71681458a1 | ||
|
|
4d4b3c8867 | ||
|
|
681d808a74 | ||
|
|
876a0b27a6 | ||
|
|
9dce3b9a17 | ||
|
|
f77b487520 | ||
|
|
f3c73a5c8a | ||
|
|
37502b3747 | ||
|
|
309e84d14c | ||
|
|
ff464bef9f | ||
|
|
dfa5cd65f3 | ||
|
|
ccba5969a5 | ||
|
|
03baef713d | ||
|
|
a3617349bb | ||
|
|
e57b22d2fc | ||
|
|
6aabaa497d | ||
|
|
6caa142ead | ||
|
|
b01e6e30a4 | ||
|
|
5e3a612828 | ||
|
|
b498e7e83e | ||
|
|
7508643c89 | ||
|
|
24d2189399 | ||
|
|
4e470f34fd | ||
|
|
e3ca6448f2 | ||
|
|
9dadac7d93 | ||
|
|
0715bd0aba | ||
|
|
92772e7ee0 | ||
|
|
f9f6c879e0 | ||
|
|
ec7623f5c5 | ||
|
|
0163242258 | ||
|
|
3f9c8247c6 | ||
|
|
20865ad202 | ||
|
|
b5ac895b15 | ||
|
|
fbd550228b | ||
|
|
238758fc0b | ||
|
|
328a4339a4 | ||
|
|
747d958507 | ||
|
|
8622160e62 | ||
|
|
df1042e87d | ||
|
|
a5c6c11f09 | ||
|
|
7bd602cd45 | ||
|
|
2065468f1f | ||
|
|
7f9061d0c8 | ||
|
|
00a638393e | ||
|
|
f21194f877 | ||
|
|
1772351fc5 | ||
|
|
1030fc5e16 | ||
|
|
bef3ae96f6 | ||
|
|
c9fa5b2104 | ||
|
|
79cd8c0805 | ||
|
|
2b80420794 | ||
|
|
b8e18613b1 | ||
|
|
87289e4804 | ||
|
|
ba3a06a782 | ||
|
|
2764ef0417 | ||
|
|
ae0e89aa31 | ||
|
|
d0e99cc517 | ||
|
|
604fb01d6c | ||
|
|
256a1687d1 | ||
|
|
ea1ae58e54 | ||
|
|
fe9d119fe2 | ||
|
|
4a199533c1 | ||
|
|
7e785f1b6c | ||
|
|
85b4824ea2 | ||
|
|
d39af74bcc | ||
|
|
bfb52af454 | ||
|
|
5630e5d488 | ||
|
|
29780ecf22 | ||
|
|
a8b542feaa | ||
|
|
e85b182da7 | ||
|
|
84e9195869 | ||
|
|
7a739457c9 | ||
|
|
30905a7c36 | ||
|
|
0326a6834a | ||
|
|
7c75a67f9f | ||
|
|
1aa0fbf7d5 | ||
|
|
9adce93645 | ||
|
|
b7392ef62d | ||
|
|
6b55c90a93 | ||
|
|
9e9cd9ea4e | ||
|
|
ef91fb9e06 | ||
|
|
2f49c525b6 | ||
|
|
f78f179071 | ||
|
|
6ed310f8ce | ||
|
|
8da5a32b48 | ||
|
|
74fcdaa223 | ||
|
|
6b77b8fbbb | ||
|
|
9f9fdca53d | ||
|
|
540317017f | ||
|
|
567174fcde | ||
|
|
262bc1dcbe | ||
|
|
b931928434 | ||
|
|
7e2057a847 | ||
|
|
4a9b98f534 | ||
|
|
7bf45581e3 | ||
|
|
61a7fe6217 | ||
|
|
efa1a3f14f | ||
|
|
925866c3f0 | ||
|
|
7291ec6f88 | ||
|
|
16c9203956 | ||
|
|
b08f104663 | ||
|
|
82b7c6c290 | ||
|
|
63009a332f | ||
|
|
95e56db159 | ||
|
|
48f981036b | ||
|
|
79be77f986 | ||
|
|
4fafab19fc | ||
|
|
cd71f6e858 | ||
|
|
63d5068c2c | ||
|
|
a9bc7fdeb7 | ||
|
|
89dc2608bc | ||
|
|
c97a7e5158 | ||
|
|
32e2d24b15 | ||
|
|
c102aae819 | ||
|
|
bed72cb5ed | ||
|
|
f0c1046fe9 | ||
|
|
d88104d105 | ||
|
|
f3e21e5a82 | ||
|
|
a77bee8664 | ||
|
|
b5d0aed59e | ||
|
|
2440cc6af5 | ||
|
|
90114dfbe0 | ||
|
|
64b8cdf7dc |
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,8 +22,6 @@ Steps to reproduce the behavior:
|
|||||||
**Does this happen in the official app?**
|
**Does this happen in the official app?**
|
||||||
|
|
||||||
Does this issue also occur with the respective upstream release?
|
Does this issue also occur with the respective upstream release?
|
||||||
(Please test using the respective `upstream-xxxxxx.apk` provided in [Releases](https://github.com/sk22/megalodon/releases) or at least using the current Mastodon version from the Play Store)
|
|
||||||
|
|
||||||
> No / Yes
|
> No / Yes
|
||||||
|
|
||||||
> In case it does, please consider filing an [upstream bug report](https://github.com/mastodon/mastodon-android/issues) instead.
|
> In case it does, please consider filing an [upstream bug report](https://github.com/mastodon/mastodon-android/issues) instead.
|
||||||
@@ -35,7 +33,7 @@ If applicable, add screenshots (and screen recordings, if possible) to help expl
|
|||||||
|
|
||||||
**Version**
|
**Version**
|
||||||
|
|
||||||
Megalodon version: [e.g. v1.1.4+fork.#]
|
Moshidon version: [e.g. v1.1.4+fork.#]
|
||||||
|
|
||||||
**Crash log**
|
**Crash log**
|
||||||
|
|
||||||
|
|||||||
48
.github/workflows/nightly-builds.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: Nightly builds
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: set up JDK 17
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Get current date
|
||||||
|
id: date
|
||||||
|
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
|
|
||||||
|
- name: Decode Keystore
|
||||||
|
id: decode_keystore
|
||||||
|
uses: timheuer/base64-to-file@v1
|
||||||
|
with:
|
||||||
|
fileName: 'nightly_keystore.jks'
|
||||||
|
fileDir: './mastodon/keystore/'
|
||||||
|
encodedString: ${{ secrets.KEYSTORE }}
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew assembleNightly
|
||||||
|
env:
|
||||||
|
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
|
||||||
|
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
|
||||||
|
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
|
||||||
|
CURRENT_DATE: ${{ steps.date.outputs.date }}
|
||||||
|
|
||||||
|
- name: Upload a Build Artifact
|
||||||
|
uses: actions/upload-artifact@v3.1.2
|
||||||
|
with:
|
||||||
|
name: moshidon-nightly.apk
|
||||||
|
path: ./mastodon/build/outputs/apk/nightly/moshidon-nightly.apk
|
||||||
2
.gitignore
vendored
@@ -9,3 +9,5 @@
|
|||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
*.jks
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
/mastodon/keystore/nightly_keystore.keystore
|
||||||
|
|||||||
32
README.md
@@ -5,13 +5,35 @@
|
|||||||
> A fork of [megalodon](https://github.com/sk22/megalodon) which is a fork of [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly won’t ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
|
> A fork of [megalodon](https://github.com/sk22/megalodon) which is a fork of [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly won’t ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
|
[](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
|
||||||
|
|
||||||
|
[](https://nightly.link/LucasGGamerM/moshidon/workflows/nightly-builds/master/moshidon-nightly.apk.zip)
|
||||||
|
|
||||||
|
|
||||||
|
[](https://translate.codeberg.org/engage/moshidon/)
|
||||||
|
|
||||||
|
[](https://github.com/LucasGGamerM/moshidon/actions/workflows/android.yml)
|
||||||
|
|
||||||
|
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.moshinda"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
|
||||||
|
|
||||||
|
<a href="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## F.A.Q
|
||||||
|
|
||||||
|
### Q: What are the main differences between Moshidon and Megalodon?
|
||||||
|
|
||||||
|
### A: There are many, but the most outstanding differences are: the ability to have other server's local timeline inside the app. It can be acessed in the "Add community" option in the top right corner of the Edit timelines screen. Other outstanding features that Moshidon has are some quality of life improvements, such as notification actions and allowing for unlisted replies by default. Most other features are pretty minor, such as profile notes directly available in the person's profile. Other features are quite minor usability and visibility improvements. All of which can be found in the settings page.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Key features
|
## Key features
|
||||||
|
|
||||||
|
### **The ability to add new custom local timelines!**
|
||||||
|
|
||||||
|
#### It can be accessed in the "Edit timelines" menu, where you can add a new "Community" to see other server's local posts!
|
||||||
|
|
||||||
### **Material you theme support on Android 12+ devices!**
|
### **Material you theme support on Android 12+ devices!**
|
||||||
|
|
||||||
### **Show posts filtered with a warning!**
|
### **Show posts filtered with a warning!**
|
||||||
@@ -25,7 +47,7 @@ Before | After
|
|||||||
|
|
||||||
### **Color themes**
|
### **Color themes**
|
||||||
|
|
||||||
**Allows you to change theme within the app. Supports Purple, pink, green, blue, orange and yellow!**
|
**Allows you to change theme within the app. Supports Purple, pink, green, blue, red, orange, yellow and Nord!**
|
||||||
|
|
||||||
### **Unlisted posting**
|
### **Unlisted posting**
|
||||||
|
|
||||||
@@ -67,9 +89,9 @@ To bookmark a post, press the button between the Favorite and Share buttons on t
|
|||||||
|
|
||||||
To install this app on your Android device, download the [latest release from GitHub](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk) and open it. You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
|
To install this app on your Android device, download the [latest release from GitHub](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk) and open it. You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
|
||||||
|
|
||||||
Moshidon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)’s automatic update checker. Megalodon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
|
Moshidon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)’s automatic update checker. Moshidon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
|
||||||
|
|
||||||
|
|
||||||
|
Moshidon is also available in [IzzyOnDroid repo](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda), compatible with all F-Droid clients. The APK provided here is the same as the one included in the Releases.
|
||||||
|
|
||||||
## Release variants
|
## Release variants
|
||||||
|
|
||||||
@@ -91,7 +113,7 @@ Variant with an integrated updater. If you download Moshidon from here (and not
|
|||||||
([Pull request](https://github.com/mastodon/mastodon-android/pull/103))
|
([Pull request](https://github.com/mastodon/mastodon-android/pull/103))
|
||||||
* Adding a useful private profile note box!*
|
* Adding a useful private profile note box!*
|
||||||
* Auto hiding the compose button on scroll!*
|
* Auto hiding the compose button on scroll!*
|
||||||
* Adding the hability to remind yourself to add alt text to images!*
|
* Adding the ability to remind yourself to add alt text to images!*
|
||||||
* An indicator for if an image has alt text or not*
|
* An indicator for if an image has alt text or not*
|
||||||
* Adding the ability to have drafts!*
|
* Adding the ability to have drafts!*
|
||||||
* Also adding the ability to view announcements from your instance!*
|
* Also adding the ability to view announcements from your instance!*
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Moshidon</title>
|
<title>Moshidon</title>
|
||||||
<link rel="icon" href="mastodon/src/main/res/mipmap-mdpi/ic_launcher_round.png">
|
<link rel="icon" href="mastodon/src/main/res/mipmap-mdpi/ic_launcher_round.png">
|
||||||
<link rel="me" href="https://floss.social/@mastodon">
|
<link rel="me" href="https://floss.social/@megalodon">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="markdown-body">
|
<body class="markdown-body">
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
files:
|
|
||||||
- source: /mastodon/src/main/res/values/strings.xml
|
|
||||||
translation: /mastodon/src/main/res/values-%android_code%/strings.xml
|
|
||||||
- source: /fastlane/metadata/android/en-US/*.txt
|
|
||||||
translation: /fastlane/metadata/android/%locale%/%original_file_name%
|
|
||||||
@@ -5,16 +5,41 @@ plugins {
|
|||||||
android {
|
android {
|
||||||
compileSdk 33
|
compileSdk 33
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
manifestPlaceholders = [oAuthScheme:"moshidon-android-auth"]
|
||||||
archivesBaseName = "moshidon"
|
archivesBaseName = "moshidon"
|
||||||
applicationId "org.joinmastodon.android.moshinda"
|
applicationId "org.joinmastodon.android.moshinda"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 92
|
versionCode 99
|
||||||
versionName "1.1.4+fork.92.moshinda"
|
versionName "1.2.0+fork.99.moshinda"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "nl-rNL", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
|
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "nl-rNL", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
nightly{
|
||||||
|
storeFile = file("keystore/nightly_keystore.jks")
|
||||||
|
storePassword System.getenv("SIGNING_STORE_PASSWORD")
|
||||||
|
if (storePassword == null) {
|
||||||
|
Properties properties = new Properties()
|
||||||
|
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||||
|
storePassword = properties.getProperty('SIGNING_STORE_PASSWORD')
|
||||||
|
}
|
||||||
|
keyAlias System.getenv("SIGNING_KEY_ALIAS")
|
||||||
|
if (keyAlias == null) {
|
||||||
|
Properties properties = new Properties()
|
||||||
|
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||||
|
keyAlias = properties.getProperty('SIGNING_KEY_ALIAS')
|
||||||
|
}
|
||||||
|
keyPassword System.getenv("SIGNING_KEY_PASSWORD")
|
||||||
|
if (keyPassword == null) {
|
||||||
|
Properties properties = new Properties()
|
||||||
|
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||||
|
keyPassword = properties.getProperty('SIGNING_KEY_PASSWORD')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// minifyEnabled true
|
// minifyEnabled true
|
||||||
@@ -25,10 +50,24 @@ android {
|
|||||||
debuggable true
|
debuggable true
|
||||||
versionNameSuffix '-debug'
|
versionNameSuffix '-debug'
|
||||||
applicationIdSuffix '.debug'
|
applicationIdSuffix '.debug'
|
||||||
|
manifestPlaceholders = [oAuthScheme:"moshidon-android-debug-auth"]
|
||||||
}
|
}
|
||||||
githubRelease{
|
githubRelease{
|
||||||
initWith release
|
initWith release
|
||||||
}
|
}
|
||||||
|
nightly{
|
||||||
|
initWith release
|
||||||
|
if(System.getenv("CURRENT_DATE") != null){
|
||||||
|
versionNameSuffix '-nightly+@' + System.getenv("CURRENT_DATE")
|
||||||
|
} else {
|
||||||
|
Properties properties = new Properties()
|
||||||
|
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||||
|
versionNameSuffix '-nightly+@' + properties.getProperty('CURRENT_DATE')
|
||||||
|
}
|
||||||
|
applicationIdSuffix '.nightly'
|
||||||
|
signingConfig signingConfigs.nightly
|
||||||
|
manifestPlaceholders = [oAuthScheme:"moshidon-android-nightly-auth"]
|
||||||
|
}
|
||||||
playRelease{
|
playRelease{
|
||||||
initWith release
|
initWith release
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.joinmastodon.android">
|
package="org.joinmastodon.android">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||||
|
|
||||||
<application>
|
|
||||||
|
<application
|
||||||
|
tools:replace="android:label"
|
||||||
|
android:label="@string/mo_app_name_debug">
|
||||||
<!-- <receiver android:name=".updater.GithubSelfUpdaterImpl$InstallerStatusReceiver" android:exported="false"/>-->
|
<!-- <receiver android:name=".updater.GithubSelfUpdaterImpl$InstallerStatusReceiver" android:exported="false"/>-->
|
||||||
<!-- <receiver android:name=".updater.GithubSelfUpdaterImpl$AfterUpdateRestartReceiver" android:exported="true" android:enabled="false">-->
|
<!-- <receiver android:name=".updater.GithubSelfUpdaterImpl$AfterUpdateRestartReceiver" android:exported="true" android:enabled="false">-->
|
||||||
<!-- <intent-filter>-->
|
<!-- <intent-filter>-->
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,20 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M54,90L54,90c-19.9,0 -36,-16.1 -36,-36v0c0,-19.9 16.1,-36 36,-36h0c19.9,0 36,16.1 36,36v0C90,73.9 73.9,90 54,90z"
|
||||||
|
android:strokeAlpha="0"
|
||||||
|
android:fillAlpha="0"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M52.5,41.6c-2.4,0 -4.3,0.9 -5.5,2.8l-1.2,2l-1.2,-2c-1.2,-1.9 -3.1,-2.8 -5.5,-2.8c-2.1,0 -3.8,0.8 -5.1,2.2c-1.2,1.4 -1.9,3.4 -1.9,5.9v12h4.7V50c0,-2.4 1.1,-3.7 3.1,-3.7c2.3,0 3.4,1.4 3.4,4.4v6.4h4.7v-6.4c0,-2.9 1.1,-4.4 3.4,-4.4c2.1,0 3.1,1.2 3.1,3.7v11.7h4.7v-12c0,-2.4 -0.6,-4.4 -1.9,-5.9C56.2,42.3 54.6,41.6 52.5,41.6z"
|
||||||
|
android:fillColor="#33D17A"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M65.9,58.1h0.8c0,0 0,0 -0.1,0c-0.6,-0.3 -1.1,-0.8 -1.4,-1.4c-0.3,-0.6 -0.5,-1.4 -0.5,-2.1c0,-0.8 0.2,-1.5 0.5,-2.1c0.4,-0.6 0.8,-1.1 1.4,-1.4c0.6,-0.3 1.2,-0.5 1.9,-0.5c0.7,0 1.3,0.2 1.9,0.5s1.1,0.8 1.4,1.4s0.5,1.3 0.5,2.1c0,0.2 0,0.4 0,0.6l0.7,0.7c0.4,0 0.8,0 1.1,0l1.5,-1.5l0.2,-0.2c-0.1,-1.2 -0.4,-2.3 -0.9,-3.4c-0.6,-1.1 -1.4,-2 -2.6,-2.6c-1.1,-0.6 -2.4,-1 -3.7,-1c-1.4,0 -2.7,0.3 -3.8,1c-1.1,0.6 -2,1.5 -2.6,2.6c-0.6,1.1 -0.9,2.4 -0.9,3.7s0.3,2.7 0.9,3.7c0.6,1.1 1.5,2 2.6,2.6c0.4,0.2 0.8,0.4 1.1,0.5v-1.8V58.1z"
|
||||||
|
android:fillColor="#33D17A"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M76,58.3l1.2,-1.2L76.2,56l-1.7,1.7c-0.4,-0.1 -0.7,-0.2 -1.1,-0.2s-0.8,0.1 -1.1,0.2L70.7,56l-1,1.1l1.2,1.2c-0.5,0.4 -1.1,0.9 -1.4,1.5h-2.1v1.5H69c0,0.2 -0.1,0.5 -0.1,0.8v0.8h-1.5v1.5h1.5v0.8c0,0.2 0,0.5 0.1,0.8h-1.6v1.5h2.1c0.8,1.4 2.3,2.3 4,2.3s3.1,-0.9 4,-2.3h2.1v-1.5H78c0,-0.2 0.1,-0.5 0.1,-0.8v-0.8h1.5v-1.5h-1.5v-0.8c0,-0.2 0,-0.5 -0.1,-0.8h1.6v-1.5h-2.1C77.1,59.2 76.6,58.8 76,58.3zM75,65.9H72v-1.5H75V65.9zM75,62.9H72v-1.5H75V62.9z"
|
||||||
|
android:fillColor="#33D17A"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M54,90L54,90c-19.9,0 -36,-16.1 -36,-36v0c0,-19.9 16.1,-36 36,-36h0c19.9,0 36,16.1 36,36v0C90,73.9 73.9,90 54,90z"
|
||||||
|
android:strokeAlpha="0"
|
||||||
|
android:fillAlpha="0"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M52.5,41.6c-2.4,0 -4.3,0.9 -5.5,2.8l-1.2,2l-1.2,-2c-1.2,-1.9 -3.1,-2.8 -5.5,-2.8c-2.1,0 -3.8,0.8 -5.1,2.2c-1.2,1.4 -1.9,3.4 -1.9,5.9v12h4.7V50c0,-2.4 1.1,-3.7 3.1,-3.7c2.3,0 3.4,1.4 3.4,4.4v6.4h4.7v-6.4c0,-2.9 1.1,-4.4 3.4,-4.4c2.1,0 3.1,1.2 3.1,3.7v11.7h4.7v-12c0,-2.4 -0.6,-4.4 -1.9,-5.9C56.2,42.3 54.6,41.6 52.5,41.6z"
|
||||||
|
android:fillColor="#33D17A"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M65.9,58.1h0.8c0,0 0,0 -0.1,0c-0.6,-0.3 -1.1,-0.8 -1.4,-1.4c-0.3,-0.6 -0.5,-1.4 -0.5,-2.1c0,-0.8 0.2,-1.5 0.5,-2.1c0.4,-0.6 0.8,-1.1 1.4,-1.4c0.6,-0.3 1.2,-0.5 1.9,-0.5c0.7,0 1.3,0.2 1.9,0.5s1.1,0.8 1.4,1.4s0.5,1.3 0.5,2.1c0,0.2 0,0.4 0,0.6l0.7,0.7c0.4,0 0.8,0 1.1,0l1.5,-1.5l0.2,-0.2c-0.1,-1.2 -0.4,-2.3 -0.9,-3.4c-0.6,-1.1 -1.4,-2 -2.6,-2.6c-1.1,-0.6 -2.4,-1 -3.7,-1c-1.4,0 -2.7,0.3 -3.8,1c-1.1,0.6 -2,1.5 -2.6,2.6c-0.6,1.1 -0.9,2.4 -0.9,3.7s0.3,2.7 0.9,3.7c0.6,1.1 1.5,2 2.6,2.6c0.4,0.2 0.8,0.4 1.1,0.5v-1.8V58.1z"
|
||||||
|
android:fillColor="#33D17A"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M76,58.3l1.2,-1.2L76.2,56l-1.7,1.7c-0.4,-0.1 -0.7,-0.2 -1.1,-0.2s-0.8,0.1 -1.1,0.2L70.7,56l-1,1.1l1.2,1.2c-0.5,0.4 -1.1,0.9 -1.4,1.5h-2.1v1.5H69c0,0.2 -0.1,0.5 -0.1,0.8v0.8h-1.5v1.5h1.5v0.8c0,0.2 0,0.5 0.1,0.8h-1.6v1.5h2.1c0.8,1.4 2.3,2.3 4,2.3s3.1,-0.9 4,-2.3h2.1v-1.5H78c0,-0.2 0.1,-0.5 0.1,-0.8v-0.8h1.5v-1.5h-1.5v-0.8c0,-0.2 0,-0.5 -0.1,-0.8h1.6v-1.5h-2.1C77.1,59.2 76.6,58.8 76,58.3zM75,65.9H72v-1.5H75V65.9zM75,62.9H72v-1.5H75V62.9z"
|
||||||
|
android:fillColor="#33D17A"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground_debug"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground_monochrome_debug"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground_debug"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground_monochrome_debug"/>
|
||||||
|
</adaptive-icon>
|
||||||
BIN
mastodon/src/github/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
mastodon/src/github/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
mastodon/src/github/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 988 B |
BIN
mastodon/src/github/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
mastodon/src/github/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
mastodon/src/github/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
mastodon/src/github/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
mastodon/src/github/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
mastodon/src/github/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
mastodon/src/github/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#000000</color>
|
||||||
|
</resources>
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||||
<data android:mimeType="text/plain" />
|
<data android:mimeType="text/plain" />
|
||||||
</intent>
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.TRANSLATE" />
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
@@ -41,10 +44,11 @@
|
|||||||
<action android:name="android.intent.action.VIEW"/>
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
<category android:name="android.intent.category.BROWSABLE"/>
|
<category android:name="android.intent.category.BROWSABLE"/>
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
<data android:scheme="moshidon-android-auth" android:host="callback"/>
|
<data android:scheme="${oAuthScheme}" android:host="callback"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">
|
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize"
|
||||||
|
android:theme="@style/TransparentDialog">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND"/>
|
<action android:name="android.intent.action.SEND"/>
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,83 @@
|
|||||||
|
package org.joinmastodon.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.ShortcutInfo;
|
||||||
|
import android.content.pm.ShortcutManager;
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
|
import org.joinmastodon.android.api.PushSubscriptionManager;
|
||||||
|
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||||
|
import org.joinmastodon.android.api.requests.accounts.GetPreferences;
|
||||||
|
import org.joinmastodon.android.api.requests.accounts.GetWordFilters;
|
||||||
|
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
||||||
|
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||||
|
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
||||||
|
import org.joinmastodon.android.api.session.AccountActivationInfo;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
||||||
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Application;
|
||||||
|
import org.joinmastodon.android.model.Emoji;
|
||||||
|
import org.joinmastodon.android.model.EmojiCategory;
|
||||||
|
import org.joinmastodon.android.model.Filter;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.Preferences;
|
||||||
|
import org.joinmastodon.android.model.Token;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.grishka.appkit.api.Callback;
|
||||||
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
|
|
||||||
|
public class DomainManager {
|
||||||
|
private static final String TAG="DomainManager";
|
||||||
|
|
||||||
|
private static final DomainManager instance=new DomainManager();
|
||||||
|
|
||||||
|
private String currentDomain = "";
|
||||||
|
|
||||||
|
|
||||||
|
public static DomainManager getInstance(){
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DomainManager(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentDomain() {
|
||||||
|
return currentDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentDomain(String domain) {
|
||||||
|
this.currentDomain = domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.joinmastodon.android;
|
package org.joinmastodon.android;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -12,7 +12,9 @@ import android.widget.Toast;
|
|||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.ComposeFragment;
|
import org.joinmastodon.android.fragments.ComposeFragment;
|
||||||
|
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.jsoup.internal.StringUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -27,18 +29,23 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
|||||||
UiUtils.setUserPreferredTheme(this);
|
UiUtils.setUserPreferredTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if(savedInstanceState==null){
|
if(savedInstanceState==null){
|
||||||
|
|
||||||
|
String text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
boolean isMastodonURL = UiUtils.looksLikeMastodonUrl(text);
|
||||||
|
|
||||||
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
||||||
if(sessions.isEmpty()){
|
if(sessions.isEmpty()){
|
||||||
Toast.makeText(this, R.string.err_not_logged_in, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.err_not_logged_in, Toast.LENGTH_SHORT).show();
|
||||||
finish();
|
finish();
|
||||||
}else if(sessions.size()==1){
|
}else if(sessions.size()==1 && !isMastodonURL){
|
||||||
openComposeFragment(sessions.get(0).getID());
|
openComposeFragment(sessions.get(0).getID());
|
||||||
}else{
|
}else{
|
||||||
getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
|
new AccountSwitcherSheet(this, false, false, isMastodonURL, accountSession -> {
|
||||||
UiUtils.pickAccount(this, null, R.string.choose_account, 0,
|
if(accountSession!=null)
|
||||||
session -> openComposeFragment(session.getID()),
|
openComposeFragment(accountSession.getID());
|
||||||
b -> b.setOnCancelListener(d -> finish())
|
else
|
||||||
);
|
UiUtils.openURL(this, AccountSessionManager.getInstance().getLastActiveAccountID(), text);
|
||||||
|
}).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,9 +58,15 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
|||||||
String subject = "";
|
String subject = "";
|
||||||
if (intent.hasExtra(Intent.EXTRA_SUBJECT)) {
|
if (intent.hasExtra(Intent.EXTRA_SUBJECT)) {
|
||||||
subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
||||||
if (!subject.isBlank()) builder.append(subject).append("\n\n");
|
if (!StringUtil.isBlank(subject)) builder.append(subject).append("\n\n");
|
||||||
|
}
|
||||||
|
if (intent.hasExtra(Intent.EXTRA_TEXT)) {
|
||||||
|
String extra = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
if (!StringUtil.isBlank(extra)) {
|
||||||
|
if (extra.startsWith(subject)) extra = extra.substring(subject.length()).trim();
|
||||||
|
builder.append(extra).append("\n\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (intent.hasExtra(Intent.EXTRA_TEXT)) builder.append(intent.getStringExtra(Intent.EXTRA_TEXT)).append("\n");
|
|
||||||
String text=builder.toString();
|
String text=builder.toString();
|
||||||
List<Uri> mediaUris;
|
List<Uri> mediaUris;
|
||||||
if(Intent.ACTION_SEND.equals(intent.getAction())){
|
if(Intent.ACTION_SEND.equals(intent.getAction())){
|
||||||
@@ -80,8 +93,7 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
|||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
if(!TextUtils.isEmpty(text))
|
if(!TextUtils.isEmpty(text))
|
||||||
args.putString("prefilledText", text);
|
args.putString("prefilledText", text);
|
||||||
if(!subject.isBlank())
|
args.putInt("selectionStart", StringUtil.isBlank(subject) ? 0 : subject.length());
|
||||||
args.putInt("selectionEnd", subject.length());
|
|
||||||
if(mediaUris!=null && !mediaUris.isEmpty())
|
if(mediaUris!=null && !mediaUris.isEmpty())
|
||||||
args.putParcelableArrayList("mediaAttachments", toArrayList(mediaUris));
|
args.putParcelableArrayList("mediaAttachments", toArrayList(mediaUris));
|
||||||
Fragment fragment=new ComposeFragment();
|
Fragment fragment=new ComposeFragment();
|
||||||
@@ -96,4 +108,11 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
|||||||
return null;
|
return null;
|
||||||
return new ArrayList<>(l);
|
return new ArrayList<>(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent outContent) {
|
||||||
|
super.onProvideAssistContent(outContent);
|
||||||
|
|
||||||
|
outContent.setWebUri(Uri.parse(DomainManager.getInstance().getCurrentDomain()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,14 @@ public class GlobalUserPreferences{
|
|||||||
public static boolean bottomEncoding;
|
public static boolean bottomEncoding;
|
||||||
public static boolean collapseLongPosts;
|
public static boolean collapseLongPosts;
|
||||||
public static boolean spectatorMode;
|
public static boolean spectatorMode;
|
||||||
|
public static boolean autoHideFab;
|
||||||
|
public static boolean defaultToUnlistedReplies;
|
||||||
|
public static boolean disableDoubleTapToSwipe;
|
||||||
|
public static boolean compactReblogReplyLine;
|
||||||
|
public static boolean confirmBeforeReblog;
|
||||||
|
public static boolean replyLineAboveHeader;
|
||||||
|
public static boolean swapBookmarkWithBoostAction;
|
||||||
|
public static boolean loadRemoteAccountFollowers;
|
||||||
public static String publishButtonText;
|
public static String publishButtonText;
|
||||||
public static ThemePreference theme;
|
public static ThemePreference theme;
|
||||||
public static ColorPreference color;
|
public static ColorPreference color;
|
||||||
@@ -60,7 +68,13 @@ public class GlobalUserPreferences{
|
|||||||
private final static Type recentEmojisType = new TypeToken<Map<String, Integer>>() {}.getType();
|
private final static Type recentEmojisType = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
public static Map<String, Integer> recentEmojis;
|
public static Map<String, Integer> recentEmojis;
|
||||||
|
|
||||||
private static SharedPreferences getPrefs(){
|
/**
|
||||||
|
* Pleroma
|
||||||
|
*/
|
||||||
|
public static String replyVisibility;
|
||||||
|
|
||||||
|
|
||||||
|
public static SharedPreferences getPrefs(){
|
||||||
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
|
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +93,7 @@ public class GlobalUserPreferences{
|
|||||||
showBoosts=prefs.getBoolean("showBoosts", true);
|
showBoosts=prefs.getBoolean("showBoosts", true);
|
||||||
loadNewPosts=prefs.getBoolean("loadNewPosts", true);
|
loadNewPosts=prefs.getBoolean("loadNewPosts", true);
|
||||||
showNewPostsButton=prefs.getBoolean("showNewPostsButton", true);
|
showNewPostsButton=prefs.getBoolean("showNewPostsButton", true);
|
||||||
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", true);
|
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
|
||||||
showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
|
showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
|
||||||
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
|
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
|
||||||
disableMarquee=prefs.getBoolean("disableMarquee", false);
|
disableMarquee=prefs.getBoolean("disableMarquee", false);
|
||||||
@@ -87,7 +101,7 @@ public class GlobalUserPreferences{
|
|||||||
disableDividers=prefs.getBoolean("disableDividers", true);
|
disableDividers=prefs.getBoolean("disableDividers", true);
|
||||||
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
|
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
|
||||||
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
|
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
|
||||||
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", true);
|
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", false);
|
||||||
reduceMotion=prefs.getBoolean("reduceMotion", false);
|
reduceMotion=prefs.getBoolean("reduceMotion", false);
|
||||||
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
||||||
enableFabAutoHide=prefs.getBoolean("enableFabAutoHide", true);
|
enableFabAutoHide=prefs.getBoolean("enableFabAutoHide", true);
|
||||||
@@ -99,6 +113,15 @@ public class GlobalUserPreferences{
|
|||||||
bottomEncoding=prefs.getBoolean("bottomEncoding", false);
|
bottomEncoding=prefs.getBoolean("bottomEncoding", false);
|
||||||
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
|
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
|
||||||
spectatorMode=prefs.getBoolean("spectatorMode", false);
|
spectatorMode=prefs.getBoolean("spectatorMode", false);
|
||||||
|
autoHideFab=prefs.getBoolean("autoHideFab", true);
|
||||||
|
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
|
||||||
|
defaultToUnlistedReplies=prefs.getBoolean("defaultToUnlistedReplies", false);
|
||||||
|
disableDoubleTapToSwipe=prefs.getBoolean("disableDoubleTapToSwipe", false);
|
||||||
|
replyLineAboveHeader=prefs.getBoolean("replyLineAboveHeader", true);
|
||||||
|
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
|
||||||
|
confirmBeforeReblog=prefs.getBoolean("confirmBeforeReblog", false);
|
||||||
|
swapBookmarkWithBoostAction=prefs.getBoolean("swapBookmarkWithBoostAction", false);
|
||||||
|
loadRemoteAccountFollowers=prefs.getBoolean("loadRemoteAccountFollowers", true);
|
||||||
publishButtonText=prefs.getString("publishButtonText", "");
|
publishButtonText=prefs.getString("publishButtonText", "");
|
||||||
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
|
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
|
||||||
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
|
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
|
||||||
@@ -107,6 +130,7 @@ public class GlobalUserPreferences{
|
|||||||
pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
|
pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
|
||||||
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
|
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
|
||||||
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
|
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
|
||||||
|
replyVisibility=prefs.getString("replyVisibility", null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
|
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
|
||||||
@@ -147,8 +171,16 @@ public class GlobalUserPreferences{
|
|||||||
.putBoolean("prefixRepliesWithRe", prefixRepliesWithRe)
|
.putBoolean("prefixRepliesWithRe", prefixRepliesWithRe)
|
||||||
.putBoolean("collapseLongPosts", collapseLongPosts)
|
.putBoolean("collapseLongPosts", collapseLongPosts)
|
||||||
.putBoolean("spectatorMode", spectatorMode)
|
.putBoolean("spectatorMode", spectatorMode)
|
||||||
|
.putBoolean("autoHideFab", autoHideFab)
|
||||||
.putString("publishButtonText", publishButtonText)
|
.putString("publishButtonText", publishButtonText)
|
||||||
.putBoolean("bottomEncoding", bottomEncoding)
|
.putBoolean("bottomEncoding", bottomEncoding)
|
||||||
|
.putBoolean("defaultToUnlistedReplies", defaultToUnlistedReplies)
|
||||||
|
.putBoolean("disableDoubleTapToSwipe", disableDoubleTapToSwipe)
|
||||||
|
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
|
||||||
|
.putBoolean("replyLineAboveHeader", replyLineAboveHeader)
|
||||||
|
.putBoolean("confirmBeforeReblog", confirmBeforeReblog)
|
||||||
|
.putBoolean("swapBookmarkWithBoostAction", swapBookmarkWithBoostAction)
|
||||||
|
.putBoolean("loadRemoteAccountFollowers", loadRemoteAccountFollowers)
|
||||||
.putInt("theme", theme.ordinal())
|
.putInt("theme", theme.ordinal())
|
||||||
.putString("color", color.name())
|
.putString("color", color.name())
|
||||||
.putString("recentLanguages", gson.toJson(recentLanguages))
|
.putString("recentLanguages", gson.toJson(recentLanguages))
|
||||||
@@ -156,6 +188,7 @@ public class GlobalUserPreferences{
|
|||||||
.putString("recentEmojis", gson.toJson(recentEmojis))
|
.putString("recentEmojis", gson.toJson(recentEmojis))
|
||||||
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
|
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
|
||||||
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
|
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
|
||||||
|
.putString("replyVisibility", replyVisibility)
|
||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package org.joinmastodon.android;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -17,7 +19,6 @@ import org.joinmastodon.android.fragments.ProfileFragment;
|
|||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
|
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
||||||
@@ -27,6 +28,7 @@ import androidx.annotation.Nullable;
|
|||||||
import me.grishka.appkit.FragmentStackActivity;
|
import me.grishka.appkit.FragmentStackActivity;
|
||||||
|
|
||||||
public class MainActivity extends FragmentStackActivity{
|
public class MainActivity extends FragmentStackActivity{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState){
|
protected void onCreate(@Nullable Bundle savedInstanceState){
|
||||||
UiUtils.setUserPreferredTheme(this);
|
UiUtils.setUserPreferredTheme(this);
|
||||||
@@ -81,6 +83,7 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
AccountSession accountSession;
|
AccountSession accountSession;
|
||||||
try{
|
try{
|
||||||
accountSession=AccountSessionManager.getInstance().getAccount(accountID);
|
accountSession=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
|
DomainManager.getInstance().setCurrentDomain(accountSession.domain);
|
||||||
}catch(IllegalStateException x){
|
}catch(IllegalStateException x){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -168,4 +171,11 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent outContent) {
|
||||||
|
super.onProvideAssistContent(outContent);
|
||||||
|
|
||||||
|
outContent.setWebUri(Uri.parse(DomainManager.getInstance().getCurrentDomain()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
package org.joinmastodon.android;
|
package org.joinmastodon.android;
|
||||||
|
|
||||||
|
import static org.joinmastodon.android.GlobalUserPreferences.getPrefs;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationChannelGroup;
|
import android.app.NotificationChannelGroup;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.app.RemoteInput;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.opengl.Visibility;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -16,15 +20,27 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
import org.joinmastodon.android.api.requests.notifications.GetNotificationByID;
|
import org.joinmastodon.android.api.requests.notifications.GetNotificationByID;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.events.NotificationReceivedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.NotificationAction;
|
||||||
|
import org.joinmastodon.android.model.Preferences;
|
||||||
import org.joinmastodon.android.model.PushNotification;
|
import org.joinmastodon.android.model.PushNotification;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
@@ -37,11 +53,14 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
private static final String TAG="PushNotificationReceive";
|
private static final String TAG="PushNotificationReceive";
|
||||||
|
|
||||||
public static final int NOTIFICATION_ID=178;
|
public static final int NOTIFICATION_ID=178;
|
||||||
|
private static final String ACTION_KEY_TEXT_REPLY = "ACTION_KEY_TEXT_REPLY";
|
||||||
|
|
||||||
private static final int SUMMARY_ID = 791;
|
private static final int SUMMARY_ID = 791;
|
||||||
private static int notificationId = 0;
|
private static int notificationId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent){
|
public void onReceive(Context context, Intent intent){
|
||||||
|
UiUtils.setUserPreferredTheme(context);
|
||||||
if(BuildConfig.DEBUG){
|
if(BuildConfig.DEBUG){
|
||||||
Log.e(TAG, "received: "+intent);
|
Log.e(TAG, "received: "+intent);
|
||||||
Bundle extras=intent.getExtras();
|
Bundle extras=intent.getExtras();
|
||||||
@@ -71,6 +90,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
}
|
}
|
||||||
String accountID=account.getID();
|
String accountID=account.getID();
|
||||||
PushNotification pn=AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().decryptNotification(k, p, s);
|
PushNotification pn=AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().decryptNotification(k, p, s);
|
||||||
|
E.post(new NotificationReceivedEvent(accountID, pn.notificationId+""));
|
||||||
new GetNotificationByID(pn.notificationId+"")
|
new GetNotificationByID(pn.notificationId+"")
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
@@ -92,14 +112,43 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
Log.w(TAG, "onReceive: invalid push notification format");
|
Log.w(TAG, "onReceive: invalid push notification format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(intent.getBooleanExtra("fromNotificationAction", false)){
|
||||||
|
String accountID=intent.getStringExtra("accountID");
|
||||||
|
int notificationId=intent.getIntExtra("notificationId", -1);
|
||||||
|
|
||||||
|
if (notificationId >= 0){
|
||||||
|
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
notificationManager.cancel(accountID, notificationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(intent.hasExtra("notification")){
|
||||||
|
org.joinmastodon.android.model.Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
|
||||||
|
String statusID=notification.status.id;
|
||||||
|
if (statusID != null) {
|
||||||
|
AccountSessionManager accountSessionManager = AccountSessionManager.getInstance();
|
||||||
|
Preferences preferences = accountSessionManager.getAccount(accountID).preferences;
|
||||||
|
|
||||||
|
switch (NotificationAction.values()[intent.getIntExtra("notificationAction", 0)]) {
|
||||||
|
case FAVORITE -> new SetStatusFavorited(statusID, true).exec(accountID);
|
||||||
|
case BOOKMARK -> new SetStatusBookmarked(statusID, true).exec(accountID);
|
||||||
|
case BOOST -> new SetStatusReblogged(notification.status.id, true, preferences.postingDefaultVisibility).exec(accountID);
|
||||||
|
case UNBOOST -> new SetStatusReblogged(notification.status.id, false, preferences.postingDefaultVisibility).exec(accountID);
|
||||||
|
case REPLY -> handleReplyAction(context, accountID, intent, notification, notificationId, preferences);
|
||||||
|
default -> Log.w(TAG, "onReceive: Failed to get NotificationAction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Log.e(TAG, "onReceive: Failed to load notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){
|
private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){
|
||||||
NotificationManager nm=context.getSystemService(NotificationManager.class);
|
NotificationManager nm=context.getSystemService(NotificationManager.class);
|
||||||
|
notificationId=getPrefs().getInt("latestNotificationId", 0);
|
||||||
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
|
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
|
||||||
String accountName="@"+self.username+"@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
|
String accountName="@"+self.username+"@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
|
||||||
Notification.Builder builder;
|
Notification.Builder builder;
|
||||||
Notification.Builder summaryNotification;
|
|
||||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
|
||||||
boolean hasGroup=false;
|
boolean hasGroup=false;
|
||||||
List<NotificationChannelGroup> channelGroups=nm.getNotificationChannelGroups();
|
List<NotificationChannelGroup> channelGroups=nm.getNotificationChannelGroups();
|
||||||
@@ -122,28 +171,21 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
nm.createNotificationChannels(channels);
|
nm.createNotificationChannels(channels);
|
||||||
}
|
}
|
||||||
builder=new Notification.Builder(context, accountID+"_"+pn.notificationType);
|
builder=new Notification.Builder(context, accountID+"_"+pn.notificationType);
|
||||||
// summaryNotification=new Notification.Builder(context, accountID);
|
|
||||||
}else{
|
}else{
|
||||||
builder=new Notification.Builder(context)
|
builder=new Notification.Builder(context)
|
||||||
.setPriority(Notification.PRIORITY_DEFAULT)
|
.setPriority(Notification.PRIORITY_DEFAULT)
|
||||||
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
|
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
|
||||||
summaryNotification=new Notification.Builder(context)
|
|
||||||
.setPriority(Notification.PRIORITY_DEFAULT)
|
|
||||||
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
|
|
||||||
}
|
}
|
||||||
Drawable avatar=ImageCache.getInstance(context).get(new UrlImageLoaderRequest(pn.icon, V.dp(50), V.dp(50)));
|
Drawable avatar=ImageCache.getInstance(context).get(new UrlImageLoaderRequest(pn.icon, V.dp(50), V.dp(50)));
|
||||||
Intent contentIntent=new Intent(context, MainActivity.class);
|
Intent contentIntent=new Intent(context, MainActivity.class);
|
||||||
contentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
contentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
contentIntent.putExtra("fromNotification", true);
|
contentIntent.putExtra("fromNotification", true);
|
||||||
contentIntent.putExtra("accountID", accountID);
|
contentIntent.putExtra("accountID", accountID);
|
||||||
contentIntent.putExtra("notificationID", notificationId);
|
|
||||||
if(notification!=null){
|
if(notification!=null){
|
||||||
contentIntent.putExtra("notification", Parcels.wrap(notification));
|
contentIntent.putExtra("notification", Parcels.wrap(notification));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setContentTitle(pn.title)
|
builder.setContentTitle(pn.title)
|
||||||
.setContentText(pn.body)
|
.setContentText(pn.body)
|
||||||
.setContentTitle(pn.title)
|
|
||||||
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
|
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
|
||||||
.setSmallIcon(R.drawable.ic_ntf_logo)
|
.setSmallIcon(R.drawable.ic_ntf_logo)
|
||||||
.setContentIntent(PendingIntent.getActivity(context, notificationId, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT))
|
.setContentIntent(PendingIntent.getActivity(context, notificationId, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT))
|
||||||
@@ -151,8 +193,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
.setShowWhen(true)
|
.setShowWhen(true)
|
||||||
.setCategory(Notification.CATEGORY_SOCIAL)
|
.setCategory(Notification.CATEGORY_SOCIAL)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setColor(context.getColor(R.color.shortcut_icon_background))
|
.setColor(context.getColor(R.color.shortcut_icon_background));
|
||||||
.setGroup(accountID);
|
|
||||||
|
|
||||||
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
||||||
builder.setSmallIcon(switch (pn.notificationType) {
|
builder.setSmallIcon(switch (pn.notificationType) {
|
||||||
@@ -175,8 +216,96 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
builder.setSubText(accountName);
|
builder.setSubText(accountName);
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationId++;
|
int id = GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId++;
|
||||||
nm.notify(accountID, GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId, builder.build());
|
getPrefs().edit().putInt("latestNotificationId", notificationId).apply();
|
||||||
|
|
||||||
|
if (notification != null){
|
||||||
|
switch (pn.notificationType){
|
||||||
|
case MENTION, STATUS -> {
|
||||||
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
|
||||||
|
builder.addAction(buildReplyAction(context, id, accountID, notification));
|
||||||
|
}
|
||||||
|
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_favorite), NotificationAction.FAVORITE));
|
||||||
|
if(GlobalUserPreferences.swapBookmarkWithBoostAction){
|
||||||
|
if(notification.status.visibility != StatusPrivacy.DIRECT) {
|
||||||
|
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_reblog), NotificationAction.BOOST));
|
||||||
|
}else{
|
||||||
|
// This is just so there is a bookmark action if you cannot reblog the toot
|
||||||
|
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.add_bookmark), NotificationAction.BOOKMARK));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.add_bookmark), NotificationAction.BOOKMARK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case UPDATE -> {
|
||||||
|
if(notification.status.reblogged)
|
||||||
|
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.sk_undo_reblog), NotificationAction.UNBOOST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nm.notify(accountID, id, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification.Action buildNotificationAction(Context context, int notificationId, String accountID, org.joinmastodon.android.model.Notification notification, String title, NotificationAction action){
|
||||||
|
Intent notificationIntent=new Intent(context, PushNotificationReceiver.class);
|
||||||
|
notificationIntent.putExtra("notificationId", notificationId);
|
||||||
|
notificationIntent.putExtra("fromNotificationAction", true);
|
||||||
|
notificationIntent.putExtra("accountID", accountID);
|
||||||
|
notificationIntent.putExtra("notificationAction", action.ordinal());
|
||||||
|
notificationIntent.putExtra("notification", Parcels.wrap(notification));
|
||||||
|
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, new Random().nextInt(), notificationIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
|
||||||
|
|
||||||
|
return new Notification.Action.Builder(null, title, actionPendingIntent).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification.Action buildReplyAction(Context context, int notificationId, String accountID, org.joinmastodon.android.model.Notification notification){
|
||||||
|
String replyLabel = context.getResources().getString(R.string.button_reply);
|
||||||
|
RemoteInput remoteInput = new RemoteInput.Builder(ACTION_KEY_TEXT_REPLY)
|
||||||
|
.setLabel(replyLabel)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Intent notificationIntent=new Intent(context, PushNotificationReceiver.class);
|
||||||
|
notificationIntent.putExtra("notificationId", notificationId);
|
||||||
|
notificationIntent.putExtra("fromNotificationAction", true);
|
||||||
|
notificationIntent.putExtra("accountID", accountID);
|
||||||
|
notificationIntent.putExtra("notificationAction", NotificationAction.REPLY.ordinal());
|
||||||
|
notificationIntent.putExtra("notification", Parcels.wrap(notification));
|
||||||
|
|
||||||
|
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT : PendingIntent.FLAG_UPDATE_CURRENT;
|
||||||
|
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context, new Random().nextInt(), notificationIntent,flags);
|
||||||
|
return new Notification.Action.Builder(null, replyLabel, replyPendingIntent).addRemoteInput(remoteInput).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReplyAction(Context context, String accountID, Intent intent, org.joinmastodon.android.model.Notification notification, int notificationId, Preferences preferences) {
|
||||||
|
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
|
||||||
|
if (remoteInput == null) {
|
||||||
|
Log.e(TAG, "handleReplyAction: Could not get reply input");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CharSequence input = remoteInput.getCharSequence(ACTION_KEY_TEXT_REPLY);
|
||||||
|
|
||||||
|
CreateStatus.Request req=new CreateStatus.Request();
|
||||||
|
req.status = input.toString() + "\n\n" + "@" + notification.status.account.acct;
|
||||||
|
req.language = notification.status.language;
|
||||||
|
req.visibility = (notification.status.visibility == StatusPrivacy.PUBLIC && GlobalUserPreferences.defaultToUnlistedReplies ? StatusPrivacy.UNLISTED : notification.status.visibility);
|
||||||
|
req.inReplyToId = notification.status.id;
|
||||||
|
if(!notification.status.spoilerText.isEmpty() && GlobalUserPreferences.prefixRepliesWithRe && !notification.status.spoilerText.startsWith("re: ")){
|
||||||
|
req.spoilerText = "re: " + notification.status.spoilerText;
|
||||||
|
}
|
||||||
|
|
||||||
|
new CreateStatus(req, UUID.randomUUID().toString()).exec(accountID);
|
||||||
|
|
||||||
|
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
Notification.Builder builder = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ?
|
||||||
|
new Notification.Builder(context, accountID+"_"+notification.type) :
|
||||||
|
new Notification.Builder(context)
|
||||||
|
.setPriority(Notification.PRIORITY_DEFAULT)
|
||||||
|
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
|
||||||
|
|
||||||
|
Notification repliedNotification = builder.setSmallIcon(R.drawable.ic_ntf_logo)
|
||||||
|
.setContentText(context.getString(R.string.mo_notification_action_replied, notification.status.account.getDisplayUsername()))
|
||||||
|
.build();
|
||||||
|
notificationManager.notify(accountID, notificationId, repliedNotification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,9 +13,11 @@ import org.joinmastodon.android.BuildConfig;
|
|||||||
import org.joinmastodon.android.MastodonApp;
|
import org.joinmastodon.android.MastodonApp;
|
||||||
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.PaginatedResponse;
|
import org.joinmastodon.android.model.PaginatedResponse;
|
||||||
import org.joinmastodon.android.model.SearchResult;
|
import org.joinmastodon.android.model.SearchResult;
|
||||||
@@ -126,11 +128,12 @@ public class CacheController{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<PaginatedResponse<List<Notification>>> callback){
|
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<CacheablePaginatedResponse<List<Notification>>> callback){
|
||||||
cancelDelayedClose();
|
cancelDelayedClose();
|
||||||
databaseThread.postRunnable(()->{
|
databaseThread.postRunnable(()->{
|
||||||
try{
|
try{
|
||||||
List<Filter> filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(Filter.FilterContext.NOTIFICATIONS)).collect(Collectors.toList());
|
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
|
List<Filter> filters=accountSession.wordFilters.stream().filter(f->f.context.contains(Filter.FilterContext.NOTIFICATIONS)).collect(Collectors.toList());
|
||||||
if(!forceReload){
|
if(!forceReload){
|
||||||
SQLiteDatabase db=getOrOpenDatabase();
|
SQLiteDatabase db=getOrOpenDatabase();
|
||||||
String table=onlyPosts ? "notifications_posts" : onlyMentions ? "notifications_mentions" : "notifications_all";
|
String table=onlyPosts ? "notifications_posts" : onlyMentions ? "notifications_mentions" : "notifications_all";
|
||||||
@@ -153,18 +156,19 @@ public class CacheController{
|
|||||||
result.add(ntf);
|
result.add(ntf);
|
||||||
}while(cursor.moveToNext());
|
}while(cursor.moveToNext());
|
||||||
String _newMaxID=newMaxID;
|
String _newMaxID=newMaxID;
|
||||||
uiHandler.post(()->callback.onSuccess(new PaginatedResponse<>(result, _newMaxID)));
|
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}catch(IOException x){
|
}catch(IOException x){
|
||||||
Log.w(TAG, "getNotifications: corrupted notification object in database", x);
|
Log.w(TAG, "getNotifications: corrupted notification object in database", x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class))
|
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(accountSession.domain);
|
||||||
|
new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), instance.pleroma != null)
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Notification> result){
|
public void onSuccess(List<Notification> result){
|
||||||
callback.onSuccess(new PaginatedResponse<>(result.stream().filter(ntf->{
|
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(ntf->{
|
||||||
if(ntf.status!=null){
|
if(ntf.status!=null){
|
||||||
for(Filter filter:filters){
|
for(Filter filter:filters){
|
||||||
if(filter.matches(ntf.status)){
|
if(filter.matches(ntf.status)){
|
||||||
@@ -173,7 +177,7 @@ public class CacheController{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id));
|
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
|
||||||
putNotifications(result, onlyMentions, onlyPosts, maxID==null);
|
putNotifications(result, onlyMentions, onlyPosts, maxID==null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.joinmastodon.android.MastodonApp;
|
|||||||
import org.joinmastodon.android.api.gson.IsoInstantTypeAdapter;
|
import org.joinmastodon.android.api.gson.IsoInstantTypeAdapter;
|
||||||
import org.joinmastodon.android.api.gson.IsoLocalDateTypeAdapter;
|
import org.joinmastodon.android.api.gson.IsoLocalDateTypeAdapter;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -40,12 +41,15 @@ import okhttp3.ResponseBody;
|
|||||||
|
|
||||||
public class MastodonAPIController{
|
public class MastodonAPIController{
|
||||||
private static final String TAG="MastodonAPIController";
|
private static final String TAG="MastodonAPIController";
|
||||||
public static final Gson gson=new GsonBuilder()
|
public static final Gson gsonWithoutDeserializer = new GsonBuilder()
|
||||||
.disableHtmlEscaping()
|
.disableHtmlEscaping()
|
||||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||||
.registerTypeAdapter(Instant.class, new IsoInstantTypeAdapter())
|
.registerTypeAdapter(Instant.class, new IsoInstantTypeAdapter())
|
||||||
.registerTypeAdapter(LocalDate.class, new IsoLocalDateTypeAdapter())
|
.registerTypeAdapter(LocalDate.class, new IsoLocalDateTypeAdapter())
|
||||||
.create();
|
.create();
|
||||||
|
public static final Gson gson = gsonWithoutDeserializer.newBuilder()
|
||||||
|
.registerTypeAdapter(Status.class, new Status.StatusDeserializer())
|
||||||
|
.create();
|
||||||
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
|
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
|
||||||
private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
|
private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
|
||||||
|
|
||||||
@@ -81,7 +85,7 @@ public class MastodonAPIController{
|
|||||||
final boolean isBad = host == null || badDomains.stream().anyMatch(h -> h.equalsIgnoreCase(host) || host.toLowerCase().endsWith("." + h));
|
final boolean isBad = host == null || badDomains.stream().anyMatch(h -> h.equalsIgnoreCase(host) || host.toLowerCase().endsWith("." + h));
|
||||||
thread.postRunnable(()->{
|
thread.postRunnable(()->{
|
||||||
try{
|
try{
|
||||||
if (isBad) throw new IllegalArgumentException();
|
// if (isBad) throw new IllegalArgumentException();
|
||||||
if(req.canceled)
|
if(req.canceled)
|
||||||
return;
|
return;
|
||||||
Request.Builder builder=new Request.Builder()
|
Request.Builder builder=new Request.Builder()
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.joinmastodon.android.api.requests.accounts;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.Account;
|
||||||
|
|
||||||
|
public class GetAccountByHandle extends MastodonAPIRequest<Account>{
|
||||||
|
public GetAccountByHandle(String acct){
|
||||||
|
super(HttpMethod.GET, "/accounts/lookup", Account.class);
|
||||||
|
addQueryParameter("acct", acct);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,15 @@ import org.joinmastodon.android.api.MastodonAPIRequest;
|
|||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
|
|
||||||
public class SetAccountMuted extends MastodonAPIRequest<Relationship>{
|
public class SetAccountMuted extends MastodonAPIRequest<Relationship>{
|
||||||
public SetAccountMuted(String id, boolean muted){
|
public SetAccountMuted(String id, boolean muted, long duration){
|
||||||
super(HttpMethod.POST, "/accounts/"+id+"/"+(muted ? "mute" : "unmute"), Relationship.class);
|
super(HttpMethod.POST, "/accounts/"+id+"/"+(muted ? "mute" : "unmute"), Relationship.class);
|
||||||
setRequestBody(new Object());
|
setRequestBody(muted ? new Request(duration): new Object());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Request{
|
||||||
|
public long duration;
|
||||||
|
public Request(long duration){
|
||||||
|
this.duration=duration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.joinmastodon.android.api.requests.markers;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.ApiUtils;
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.Marker;
|
||||||
|
import org.joinmastodon.android.model.Markers;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
public class GetMarkers extends MastodonAPIRequest<Markers> {
|
||||||
|
public GetMarkers(EnumSet<Marker.Type> timelines) {
|
||||||
|
super(HttpMethod.GET, "/markers", Markers.class);
|
||||||
|
for (String type : ApiUtils.enumSetToStrings(timelines, Marker.Type.class)){
|
||||||
|
addQueryParameter("timeline[]", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.joinmastodon.android.api.requests.notifications;
|
package org.joinmastodon.android.api.requests.notifications;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.ApiUtils;
|
import org.joinmastodon.android.api.ApiUtils;
|
||||||
@@ -11,19 +10,25 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GetNotifications extends MastodonAPIRequest<List<Notification>>{
|
public class GetNotifications extends MastodonAPIRequest<List<Notification>>{
|
||||||
public GetNotifications(String maxID, int limit, EnumSet<Notification.Type> includeTypes){
|
public GetNotifications(String maxID, int limit, EnumSet<Notification.Type> includeTypes, boolean isPleromaInstance){
|
||||||
super(HttpMethod.GET, "/notifications", new TypeToken<>(){});
|
super(HttpMethod.GET, "/notifications", new TypeToken<>(){});
|
||||||
if(maxID!=null)
|
if(maxID!=null)
|
||||||
addQueryParameter("max_id", maxID);
|
addQueryParameter("max_id", maxID);
|
||||||
if(limit>0)
|
if(limit>0)
|
||||||
addQueryParameter("limit", ""+limit);
|
addQueryParameter("limit", ""+limit);
|
||||||
if(includeTypes!=null){
|
if(includeTypes!=null){
|
||||||
|
if(!isPleromaInstance) {
|
||||||
for(String type:ApiUtils.enumSetToStrings(includeTypes, Notification.Type.class)){
|
for(String type:ApiUtils.enumSetToStrings(includeTypes, Notification.Type.class)){
|
||||||
addQueryParameter("types[]", type);
|
addQueryParameter("types[]", type);
|
||||||
}
|
}
|
||||||
for(String type:ApiUtils.enumSetToStrings(EnumSet.complementOf(includeTypes), Notification.Type.class)){
|
for(String type:ApiUtils.enumSetToStrings(EnumSet.complementOf(includeTypes), Notification.Type.class)){
|
||||||
addQueryParameter("exclude_types[]", type);
|
addQueryParameter("exclude_types[]", type);
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
for(String type:ApiUtils.enumSetToStrings(includeTypes, Notification.Type.class)){
|
||||||
|
addQueryParameter("include_types[]", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
removeUnsupportedItems=true;
|
removeUnsupportedItems=true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ public class CreateStatus extends MastodonAPIRequest<Status>{
|
|||||||
public Instant scheduledAt;
|
public Instant scheduledAt;
|
||||||
public String language;
|
public String language;
|
||||||
|
|
||||||
|
public String quoteId;
|
||||||
|
|
||||||
public static class Poll{
|
public static class Poll{
|
||||||
public ArrayList<String> options=new ArrayList<>();
|
public ArrayList<String> options=new ArrayList<>();
|
||||||
public int expiresIn;
|
public int expiresIn;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.joinmastodon.android.api.requests.timelines;
|
|||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
|
|
||||||
@@ -18,5 +19,7 @@ public class GetHomeTimeline extends MastodonAPIRequest<List<Status>>{
|
|||||||
addQueryParameter("since_id", sinceID);
|
addQueryParameter("since_id", sinceID);
|
||||||
if(limit>0)
|
if(limit>0)
|
||||||
addQueryParameter("limit", ""+limit);
|
addQueryParameter("limit", ""+limit);
|
||||||
|
if(GlobalUserPreferences.replyVisibility != null)
|
||||||
|
addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.joinmastodon.android.api.StatusInteractionController;
|
|||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Application;
|
import org.joinmastodon.android.model.Application;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
|
import org.joinmastodon.android.model.Markers;
|
||||||
import org.joinmastodon.android.model.Preferences;
|
import org.joinmastodon.android.model.Preferences;
|
||||||
import org.joinmastodon.android.model.PushSubscription;
|
import org.joinmastodon.android.model.PushSubscription;
|
||||||
import org.joinmastodon.android.model.Token;
|
import org.joinmastodon.android.model.Token;
|
||||||
@@ -31,6 +32,7 @@ public class AccountSession{
|
|||||||
public String pushAccountID;
|
public String pushAccountID;
|
||||||
public Preferences preferences;
|
public Preferences preferences;
|
||||||
public AccountActivationInfo activationInfo;
|
public AccountActivationInfo activationInfo;
|
||||||
|
public Markers markers;
|
||||||
private transient MastodonAPIController apiController;
|
private transient MastodonAPIController apiController;
|
||||||
private transient StatusInteractionController statusInteractionController, remoteStatusInteractionController;
|
private transient StatusInteractionController statusInteractionController, remoteStatusInteractionController;
|
||||||
private transient CacheController cacheController;
|
private transient CacheController cacheController;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.joinmastodon.android.api.requests.accounts.GetWordFilters;
|
|||||||
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||||
|
import org.joinmastodon.android.api.requests.markers.GetMarkers;
|
||||||
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
||||||
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
@@ -33,6 +34,8 @@ import org.joinmastodon.android.model.Emoji;
|
|||||||
import org.joinmastodon.android.model.EmojiCategory;
|
import org.joinmastodon.android.model.EmojiCategory;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.Marker;
|
||||||
|
import org.joinmastodon.android.model.Markers;
|
||||||
import org.joinmastodon.android.model.Preferences;
|
import org.joinmastodon.android.model.Preferences;
|
||||||
import org.joinmastodon.android.model.Token;
|
import org.joinmastodon.android.model.Token;
|
||||||
|
|
||||||
@@ -46,6 +49,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -61,7 +65,7 @@ import me.grishka.appkit.api.ErrorResponse;
|
|||||||
public class AccountSessionManager{
|
public class AccountSessionManager{
|
||||||
private static final String TAG="AccountSessionManager";
|
private static final String TAG="AccountSessionManager";
|
||||||
public static final String SCOPE="read write follow push";
|
public static final String SCOPE="read write follow push";
|
||||||
public static final String REDIRECT_URI="moshidon-android-auth://callback";
|
public static final String REDIRECT_URI = getRedirectURI();
|
||||||
|
|
||||||
private static final AccountSessionManager instance=new AccountSessionManager();
|
private static final AccountSessionManager instance=new AccountSessionManager();
|
||||||
|
|
||||||
@@ -80,6 +84,17 @@ public class AccountSessionManager{
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRedirectURI() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("moshidon-android-");
|
||||||
|
if (BuildConfig.BUILD_TYPE.equals("debug") || BuildConfig.BUILD_TYPE.equals("nightly")) {
|
||||||
|
builder.append(BuildConfig.BUILD_TYPE);
|
||||||
|
builder.append('-');
|
||||||
|
}
|
||||||
|
builder.append("auth://callback");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private AccountSessionManager(){
|
private AccountSessionManager(){
|
||||||
prefs=MastodonApp.context.getSharedPreferences("account_manager", Context.MODE_PRIVATE);
|
prefs=MastodonApp.context.getSharedPreferences("account_manager", Context.MODE_PRIVATE);
|
||||||
File file=new File(MastodonApp.context.getFilesDir(), "accounts.json");
|
File file=new File(MastodonApp.context.getFilesDir(), "accounts.json");
|
||||||
@@ -211,7 +226,7 @@ public class AccountSessionManager{
|
|||||||
.path("/oauth/authorize")
|
.path("/oauth/authorize")
|
||||||
.appendQueryParameter("response_type", "code")
|
.appendQueryParameter("response_type", "code")
|
||||||
.appendQueryParameter("client_id", result.clientId)
|
.appendQueryParameter("client_id", result.clientId)
|
||||||
.appendQueryParameter("redirect_uri", "moshidon-android-auth://callback")
|
.appendQueryParameter("redirect_uri", REDIRECT_URI)
|
||||||
.appendQueryParameter("scope", SCOPE)
|
.appendQueryParameter("scope", SCOPE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -255,6 +270,7 @@ public class AccountSessionManager{
|
|||||||
// if(now-session.filtersLastUpdated>3600_000L){
|
// if(now-session.filtersLastUpdated>3600_000L){
|
||||||
updateSessionWordFilters(session);
|
updateSessionWordFilters(session);
|
||||||
// }
|
// }
|
||||||
|
updateSessionMarkers(session);
|
||||||
}
|
}
|
||||||
if(loadedInstances){
|
if(loadedInstances){
|
||||||
maybeUpdateCustomEmojis(domains);
|
maybeUpdateCustomEmojis(domains);
|
||||||
@@ -271,6 +287,15 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void preferencesFromSource(AccountSession session, Account account) {
|
||||||
|
if (account != null && account.source != null && session.preferences != null) {
|
||||||
|
if (account.source.privacy != null)
|
||||||
|
session.preferences.postingDefaultVisibility = account.source.privacy;
|
||||||
|
if (account.source.language != null)
|
||||||
|
session.preferences.postingDefaultLanguage = account.source.language;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateSessionLocalInfo(AccountSession session){
|
private void updateSessionLocalInfo(AccountSession session){
|
||||||
new GetOwnAccount()
|
new GetOwnAccount()
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@@ -278,13 +303,12 @@ public class AccountSessionManager{
|
|||||||
public void onSuccess(Account result){
|
public void onSuccess(Account result){
|
||||||
session.self=result;
|
session.self=result;
|
||||||
session.infoLastUpdated=System.currentTimeMillis();
|
session.infoLastUpdated=System.currentTimeMillis();
|
||||||
|
preferencesFromSource(session, result);
|
||||||
writeAccountsFile();
|
writeAccountsFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error){
|
public void onError(ErrorResponse error){}
|
||||||
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.exec(session.getID());
|
.exec(session.getID());
|
||||||
}
|
}
|
||||||
@@ -294,10 +318,14 @@ public class AccountSessionManager{
|
|||||||
@Override
|
@Override
|
||||||
public void onSuccess(Preferences preferences) {
|
public void onSuccess(Preferences preferences) {
|
||||||
session.preferences=preferences;
|
session.preferences=preferences;
|
||||||
|
preferencesFromSource(session, session.self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error) {}
|
public void onError(ErrorResponse error) {
|
||||||
|
session.preferences = new Preferences();
|
||||||
|
preferencesFromSource(session, session.self);
|
||||||
|
}
|
||||||
}).exec(session.getID());
|
}).exec(session.getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,6 +347,21 @@ public class AccountSessionManager{
|
|||||||
.exec(session.getID());
|
.exec(session.getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSessionMarkers(AccountSession session) {
|
||||||
|
new GetMarkers(EnumSet.allOf(Marker.Type.class)).setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Markers markers) {
|
||||||
|
session.markers = markers;
|
||||||
|
writeAccountsFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}).exec(session.getID());
|
||||||
|
}
|
||||||
|
|
||||||
public void updateInstanceInfo(String domain){
|
public void updateInstanceInfo(String domain){
|
||||||
new GetInstance()
|
new GetInstance()
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package org.joinmastodon.android.events;
|
||||||
|
|
||||||
|
public class AllNotificationsSeenEvent {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.joinmastodon.android.events;
|
||||||
|
|
||||||
|
public class NotificationReceivedEvent {
|
||||||
|
public String account, id;
|
||||||
|
public NotificationReceivedEvent(String account, String id) {
|
||||||
|
this.account = account;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import android.text.Layout;
|
|||||||
import android.text.StaticLayout;
|
import android.text.StaticLayout;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -20,11 +21,14 @@ import android.view.animation.TranslateAnimation;
|
|||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.Toolbar;
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.MainActivity;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
|
import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||||
@@ -32,12 +36,10 @@ import org.joinmastodon.android.model.Poll;
|
|||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.BetterItemAnimator;
|
import org.joinmastodon.android.ui.BetterItemAnimator;
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.TileGridLayoutManager;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
@@ -45,8 +47,10 @@ import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
|||||||
import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||||
|
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout;
|
import org.joinmastodon.android.ui.views.MediaGridLayout;
|
||||||
|
import org.joinmastodon.android.utils.TypedObjectPool;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -57,7 +61,6 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
@@ -71,7 +74,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends BaseRecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop{
|
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends BaseRecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop, DomainDisplay{
|
||||||
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
||||||
protected DisplayItemsAdapter adapter;
|
protected DisplayItemsAdapter adapter;
|
||||||
protected String accountID;
|
protected String accountID;
|
||||||
@@ -81,6 +84,9 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
||||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||||
protected Rect tmpRect=new Rect();
|
protected Rect tmpRect=new Rect();
|
||||||
|
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
|
||||||
|
|
||||||
|
private final int THRESHOLD = 800;
|
||||||
|
|
||||||
public BaseStatusListFragment(){
|
public BaseStatusListFragment(){
|
||||||
super(20);
|
super(20);
|
||||||
@@ -94,6 +100,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
UiUtils.loadMaxWidth(getContext());
|
||||||
if(GlobalUserPreferences.disableMarquee){
|
if(GlobalUserPreferences.disableMarquee){
|
||||||
setTitleMarqueeEnabled(false);
|
setTitleMarqueeEnabled(false);
|
||||||
setSubtitleMarqueeEnabled(false);
|
setSubtitleMarqueeEnabled(false);
|
||||||
@@ -190,21 +197,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex){
|
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex, MediaGridStatusDisplayItem.Holder gridHolder){
|
||||||
final Status status=_status.reblog!=null ? _status.reblog : _status;
|
final Status status=_status.getContentStatus();
|
||||||
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
||||||
private ImageStatusDisplayItem.Holder<?> transitioningHolder;
|
private MediaAttachmentViewController transitioningHolder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPhotoViewVisibility(int index, boolean visible){
|
public void setPhotoViewVisibility(int index, boolean visible){
|
||||||
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
||||||
if(holder!=null)
|
if(holder!=null)
|
||||||
holder.photo.setAlpha(visible ? 1f : 0f);
|
holder.photo.setAlpha(visible ? 1f : 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
||||||
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
||||||
if(holder!=null){
|
if(holder!=null){
|
||||||
transitioningHolder=holder;
|
transitioningHolder=holder;
|
||||||
View view=transitioningHolder.photo;
|
View view=transitioningHolder.photo;
|
||||||
@@ -212,7 +219,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
view.getLocationOnScreen(pos);
|
view.getLocationOnScreen(pos);
|
||||||
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
||||||
list.setClipChildren(false);
|
list.setClipChildren(false);
|
||||||
transitioningHolder.itemView.setElevation(1f);
|
gridHolder.setClipChildren(false);
|
||||||
|
transitioningHolder.view.setElevation(1f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -239,15 +247,16 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
view.setTranslationY(0f);
|
view.setTranslationY(0f);
|
||||||
view.setScaleX(1f);
|
view.setScaleX(1f);
|
||||||
view.setScaleY(1f);
|
view.setScaleY(1f);
|
||||||
transitioningHolder.itemView.setElevation(0f);
|
transitioningHolder.view.setElevation(0f);
|
||||||
if(list!=null)
|
if(list!=null)
|
||||||
list.setClipChildren(true);
|
list.setClipChildren(true);
|
||||||
|
gridHolder.setClipChildren(true);
|
||||||
transitioningHolder=null;
|
transitioningHolder=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Drawable getPhotoViewCurrentDrawable(int index){
|
public Drawable getPhotoViewCurrentDrawable(int index){
|
||||||
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
||||||
if(holder!=null)
|
if(holder!=null)
|
||||||
return holder.photo.getDrawable();
|
return holder.photo.getDrawable();
|
||||||
return null;
|
return null;
|
||||||
@@ -263,23 +272,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
requestPermissions(permissions, PhotoViewer.PERMISSION_REQUEST);
|
requestPermissions(permissions, PhotoViewer.PERMISSION_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageStatusDisplayItem.Holder<?> findPhotoViewHolder(int index){
|
private MediaAttachmentViewController findPhotoViewHolder(int index){
|
||||||
if(list==null)
|
return gridHolder.getViewController(index);
|
||||||
return null;
|
|
||||||
int offset=0;
|
|
||||||
for(StatusDisplayItem item:displayItems){
|
|
||||||
if(item.parentID.equals(parentID)){
|
|
||||||
if(item instanceof ImageStatusDisplayItem){
|
|
||||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(getMainAdapterOffset()+offset+index);
|
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
||||||
return imgHolder;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -296,9 +290,15 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
currentPhotoViewer.offsetView(-dx, -dy);
|
currentPhotoViewer.offsetView(-dx, -dy);
|
||||||
|
|
||||||
if (fab!=null && GlobalUserPreferences.enableFabAutoHide) {
|
if (fab!=null && GlobalUserPreferences.enableFabAutoHide) {
|
||||||
|
// This piece of code should make it so that the fab is always visible if the status list scroll view is at the item at the top
|
||||||
|
if(list.getChildAt(0).getTop() == 0){
|
||||||
|
scrollDiff= THRESHOLD +1;
|
||||||
|
}else{
|
||||||
if(dy > 0){
|
if(dy > 0){
|
||||||
scrollDiff=0;
|
scrollDiff=0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
0,
|
0,
|
||||||
@@ -306,29 +306,30 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
0,
|
0,
|
||||||
fab.getHeight() * 2);
|
fab.getHeight() * 2);
|
||||||
animate.setDuration(300);
|
animate.setDuration(300);
|
||||||
animate.setFillAfter(true);
|
// animate.setFillAfter(true);
|
||||||
fab.startAnimation(animate);
|
fab.startAnimation(animate);
|
||||||
|
fab.setEnabled(false);
|
||||||
fab.setVisibility(View.INVISIBLE);
|
fab.setVisibility(View.INVISIBLE);
|
||||||
scrollDiff = 0;
|
scrollDiff = 0;
|
||||||
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
||||||
if (scrollDiff > 800) {
|
if (scrollDiff > THRESHOLD) {
|
||||||
fab.setVisibility(View.VISIBLE);
|
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
fab.getHeight() * 2,
|
fab.getHeight() * 2,
|
||||||
0);
|
0);
|
||||||
animate.setDuration(300);
|
animate.setDuration(300);
|
||||||
animate.setFillAfter(true);
|
// animate.setFillAfter(true);
|
||||||
fab.startAnimation(animate);
|
fab.startAnimation(animate);
|
||||||
|
fab.setEnabled(true);
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
scrollDiff = 0;
|
scrollDiff = 0;
|
||||||
} else {
|
} else {
|
||||||
scrollDiff += Math.abs(dy);
|
scrollDiff += Math.abs(dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}});
|
||||||
});
|
|
||||||
list.addItemDecoration(new StatusListItemDecoration());
|
list.addItemDecoration(new StatusListItemDecoration());
|
||||||
((UsableRecyclerView)list).setSelectorBoundsProvider(new UsableRecyclerView.SelectorBoundsProvider(){
|
((UsableRecyclerView)list).setSelectorBoundsProvider(new UsableRecyclerView.SelectorBoundsProvider(){
|
||||||
private Rect tmpRect=new Rect();
|
private Rect tmpRect=new Rect();
|
||||||
@@ -371,31 +372,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RecyclerView.LayoutManager onCreateLayoutManager(){
|
|
||||||
GridLayoutManager lm=new TileGridLayoutManager(getActivity(), 1000);
|
|
||||||
lm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){
|
|
||||||
@Override
|
|
||||||
public int getSpanSize(int position){
|
|
||||||
position-=getMainAdapterOffset();
|
|
||||||
if(position>=0 && position<displayItems.size()){
|
|
||||||
StatusDisplayItem item=displayItems.get(position);
|
|
||||||
if(item instanceof ImageStatusDisplayItem imgItem){
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=imgItem.tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgItem.thisTile;
|
|
||||||
int spans=0;
|
|
||||||
for(int i=0;i<tile.colSpan;i++){
|
|
||||||
spans+=layout.columnSizes[tile.startCol+i];
|
|
||||||
}
|
|
||||||
return spans;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return lm;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig){
|
public void onConfigurationChanged(Configuration newConfig){
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
@@ -444,7 +420,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
List<StatusDisplayItem> pollItems=displayItems.subList(firstOptionIndex, footerIndex+1);
|
List<StatusDisplayItem> pollItems=displayItems.subList(firstOptionIndex, footerIndex+1);
|
||||||
int prevSize=pollItems.size();
|
int prevSize=pollItems.size();
|
||||||
pollItems.clear();
|
pollItems.clear();
|
||||||
StatusDisplayItem.buildPollItems(itemID, this, poll, pollItems);
|
StatusDisplayItem.buildPollItems(itemID, this, poll, pollItems, status);
|
||||||
if(prevSize!=pollItems.size()){
|
if(prevSize!=pollItems.size()){
|
||||||
adapter.notifyItemRangeRemoved(firstOptionIndex, prevSize);
|
adapter.notifyItemRangeRemoved(firstOptionIndex, prevSize);
|
||||||
adapter.notifyItemRangeInserted(firstOptionIndex, pollItems.size());
|
adapter.notifyItemRangeInserted(firstOptionIndex, pollItems.size());
|
||||||
@@ -481,12 +457,26 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
if(holder.getItem().status.reloadWhenClicked){
|
||||||
|
Status queryStatus = holder.getItem().status;
|
||||||
|
UiUtils.lookupStatus(getContext(), queryStatus, accountID, null, status -> {
|
||||||
|
submitPollVote(holder.getItemID(), status.poll.id, poll.selectedOptions.stream().map(opt->poll.options.indexOf(opt)).collect(Collectors.toList()));
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
submitPollVote(holder.getItemID(), poll.id, Collections.singletonList(poll.options.indexOf(option)));
|
submitPollVote(holder.getItemID(), poll.id, Collections.singletonList(poll.options.indexOf(option)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPollVoteButtonClick(PollFooterStatusDisplayItem.Holder holder){
|
public void onPollVoteButtonClick(PollFooterStatusDisplayItem.Holder holder){
|
||||||
Poll poll=holder.getItem().poll;
|
Poll poll=holder.getItem().poll;
|
||||||
|
if(holder.getItem().status.reloadWhenClicked){
|
||||||
|
Status queryStatus = holder.getItem().status;
|
||||||
|
UiUtils.lookupStatus(getContext(), queryStatus, accountID, null, status -> {
|
||||||
|
submitPollVote(holder.getItemID(), status.poll.id, poll.selectedOptions.stream().map(opt->poll.options.indexOf(opt)).collect(Collectors.toList()));
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
submitPollVote(holder.getItemID(), poll.id, poll.selectedOptions.stream().map(opt->poll.options.indexOf(opt)).collect(Collectors.toList()));
|
submitPollVote(holder.getItemID(), poll.id, poll.selectedOptions.stream().map(opt->poll.options.indexOf(opt)).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +504,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
revealSpoiler(status, holder.getItemID());
|
revealSpoiler(status, holder.getItemID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRevealSpoilerClick(ImageStatusDisplayItem.Holder<?> holder){
|
public void onRevealSpoilerClick(MediaGridStatusDisplayItem.Holder holder){
|
||||||
Status status=holder.getItem().status;
|
Status status=holder.getItem().status;
|
||||||
revealSpoiler(status, holder.getItemID());
|
revealSpoiler(status, holder.getItemID());
|
||||||
}
|
}
|
||||||
@@ -548,7 +538,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
holder.getItem().status.textExpandable = expandable;
|
holder.getItem().status.textExpandable = expandable;
|
||||||
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
||||||
if (header != null) header.rebind();
|
if (header != null) header.rebind();
|
||||||
holder.rebind();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,13 +551,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
|
|
||||||
protected void updateImagesSpoilerState(Status status, String itemID){
|
protected void updateImagesSpoilerState(Status status, String itemID){
|
||||||
ArrayList<Integer> updatedPositions=new ArrayList<>();
|
ArrayList<Integer> updatedPositions=new ArrayList<>();
|
||||||
for(ImageStatusDisplayItem.Holder photo:(List<ImageStatusDisplayItem.Holder>)findAllHoldersOfType(itemID, ImageStatusDisplayItem.Holder.class)){
|
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(itemID, MediaGridStatusDisplayItem.Holder.class);
|
||||||
photo.setRevealed(status.spoilerRevealed);
|
if(mediaGrid!=null){
|
||||||
updatedPositions.add(photo.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
mediaGrid.setRevealed(status.spoilerRevealed);
|
||||||
|
updatedPositions.add(mediaGrid.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
||||||
}
|
}
|
||||||
int i=0;
|
int i=0;
|
||||||
for(StatusDisplayItem item:displayItems){
|
for(StatusDisplayItem item:displayItems){
|
||||||
if(itemID.equals(item.parentID) && item instanceof ImageStatusDisplayItem && !updatedPositions.contains(i)){
|
if(itemID.equals(item.parentID) && item instanceof MediaGridStatusDisplayItem && !updatedPositions.contains(i)){
|
||||||
adapter.notifyItemChanged(i);
|
adapter.notifyItemChanged(i);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@@ -655,6 +645,11 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0) == null || list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected int getListWidthForMediaLayout(){
|
protected int getListWidthForMediaLayout(){
|
||||||
return list.getWidth();
|
return list.getWidth();
|
||||||
}
|
}
|
||||||
@@ -711,6 +706,15 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
return UiUtils.pickAccountForCompose(getActivity(), accountID);
|
return UiUtils.pickAccountForCompose(getActivity(), accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MediaAttachmentViewController makeNewMediaAttachmentView(MediaGridStatusDisplayItem.GridItemType type){
|
||||||
|
return new MediaAttachmentViewController(getActivity(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> getAttachmentViewsPool(){
|
||||||
|
return attachmentViewsPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|
||||||
public DisplayItemsAdapter(){
|
public DisplayItemsAdapter(){
|
||||||
@@ -748,16 +752,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
public ImageLoaderRequest getImageRequest(int position, int image){
|
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||||
return displayItems.get(position).getImageRequest(image);
|
return displayItems.get(position).getImageRequest(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onViewDetachedFromWindow(@NonNull BindableViewHolder<StatusDisplayItem> holder){
|
|
||||||
// if(holder instanceof ImageLoaderViewHolder){
|
|
||||||
// int count=holder.getItem().getImageCount();
|
|
||||||
// for(int i=0;i<count;i++){
|
|
||||||
// ((ImageLoaderViewHolder) holder).clearImage(i);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StatusListItemDecoration extends RecyclerView.ItemDecoration{
|
private class StatusListItemDecoration extends RecyclerView.ItemDecoration{
|
||||||
@@ -791,25 +785,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
for(int i=0;i<parent.getChildCount();i++){
|
for(int i=0;i<parent.getChildCount();i++){
|
||||||
View child=parent.getChildAt(i);
|
View child=parent.getChildAt(i);
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
if(holder instanceof MediaGridStatusDisplayItem.Holder imgHolder){
|
||||||
if(!imgHolder.getItem().status.spoilerRevealed && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
if(!imgHolder.getItem().status.spoilerRevealed && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
||||||
hiddenMediaPaint.setColor(0x80000000);
|
hiddenMediaPaint.setColor(0x80000000);
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
c.drawRect(child.getX(), child.getY(), child.getX()+child.getWidth(), child.getY()+child.getHeight(), hiddenMediaPaint);
|
||||||
float hGap=tile.startCol>0 ? V.dp(1) : 0;
|
|
||||||
float vGap=tile.startRow>0 ? V.dp(1) : 0;
|
|
||||||
c.drawRect(child.getX()-hGap, child.getY()-vGap, child.getX()+child.getWidth(), child.getY()+child.getHeight(), hiddenMediaPaint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(int i=0;i<parent.getChildCount();i++){
|
for(int i=0;i<parent.getChildCount();i++){
|
||||||
View child=parent.getChildAt(i);
|
View child=parent.getChildAt(i);
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
if(holder instanceof MediaGridStatusDisplayItem.Holder imgHolder){
|
||||||
if(!imgHolder.getItem().status.spoilerRevealed){
|
if(!imgHolder.getItem().status.spoilerRevealed){
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
if(TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
||||||
if(tile.startCol==0 && tile.startRow==0 && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
|
||||||
int listWidth=getListWidthForMediaLayout();
|
int listWidth=getListWidthForMediaLayout();
|
||||||
int width=Math.min(listWidth, V.dp(ImageAttachmentFrameLayout.MAX_WIDTH));
|
int width=Math.min(listWidth, UiUtils.MAX_WIDTH);
|
||||||
if(currentMediaHiddenLayoutsWidth!=width)
|
if(currentMediaHiddenLayoutsWidth!=width)
|
||||||
rebuildMediaHiddenLayouts(width-V.dp(32));
|
rebuildMediaHiddenLayouts(width-V.dp(32));
|
||||||
c.save();
|
c.save();
|
||||||
@@ -834,47 +824,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
|
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder){
|
|
||||||
int listWidth=getListWidthForMediaLayout();
|
|
||||||
int width=Math.min(listWidth, V.dp(ImageAttachmentFrameLayout.MAX_WIDTH));
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=((ImageStatusDisplayItem.Holder<?>) holder).getItem().tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=((ImageStatusDisplayItem.Holder<?>) holder).getItem().thisTile;
|
|
||||||
if(tile.startCol+tile.colSpan<layout.columnSizes.length){
|
|
||||||
outRect.right=V.dp(1);
|
|
||||||
}
|
|
||||||
if(tile.startRow+tile.rowSpan<layout.rowSizes.length){
|
|
||||||
outRect.bottom=V.dp(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For a view that spans rows, compensate its additional height so the row it's in stays the right height
|
|
||||||
if(tile.rowSpan>1){
|
|
||||||
outRect.bottom=-(Math.round(tile.height/1000f*width)-Math.round(layout.rowSizes[tile.startRow]/1000f*width));
|
|
||||||
}
|
|
||||||
// ...and for its siblings, offset those on rows below first to the right where they belong
|
|
||||||
if(tile.startCol>0 && layout.tiles[0].rowSpan>1 && tile.startRow>layout.tiles[0].startRow){
|
|
||||||
int xOffset=Math.round(layout.tiles[0].width/1000f*listWidth);
|
|
||||||
outRect.left=xOffset;
|
|
||||||
outRect.right=-xOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the width of the media block is smaller than that of the RecyclerView, offset the views horizontally to center them
|
|
||||||
if(listWidth>width){
|
|
||||||
outRect.left+=(listWidth-V.dp(ImageAttachmentFrameLayout.MAX_WIDTH))/2;
|
|
||||||
if(tile.startCol>0){
|
|
||||||
int spanOffset=0;
|
|
||||||
for(int i=0;i<tile.startCol;i++){
|
|
||||||
spanOffset+=layout.columnSizes[i];
|
|
||||||
}
|
|
||||||
outRect.left-=Math.round(spanOffset/1000f*listWidth);
|
|
||||||
outRect.left+=Math.round(spanOffset/1000f*width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rebuildMediaHiddenLayouts(int width){
|
private void rebuildMediaHiddenLayouts(int width){
|
||||||
currentMediaHiddenLayoutsWidth=width;
|
currentMediaHiddenLayoutsWidth=width;
|
||||||
String title=getString(R.string.sensitive_content);
|
String title=getString(R.string.sensitive_content);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import android.graphics.drawable.LayerDrawable;
|
|||||||
import android.icu.text.BreakIterator;
|
import android.icu.text.BreakIterator;
|
||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.opengl.Visibility;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -111,7 +112,7 @@ import org.joinmastodon.android.ui.text.ComposeAutocompleteSpan;
|
|||||||
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
|
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||||
import org.joinmastodon.android.ui.utils.TransferSpeedTracker;
|
import org.joinmastodon.android.utils.TransferSpeedTracker;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ComposeEditText;
|
import org.joinmastodon.android.ui.views.ComposeEditText;
|
||||||
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
|
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
|
||||||
@@ -206,6 +207,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
private List<EmojiCategory> customEmojis;
|
private List<EmojiCategory> customEmojis;
|
||||||
private CustomEmojiPopupKeyboard emojiKeyboard;
|
private CustomEmojiPopupKeyboard emojiKeyboard;
|
||||||
private Status replyTo;
|
private Status replyTo;
|
||||||
|
private Status quote;
|
||||||
private String initialText;
|
private String initialText;
|
||||||
private String uuid;
|
private String uuid;
|
||||||
private int pollDuration=24*3600;
|
private int pollDuration=24*3600;
|
||||||
@@ -258,6 +260,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus"));
|
editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus"));
|
||||||
if(getArguments().containsKey("replyTo"))
|
if(getArguments().containsKey("replyTo"))
|
||||||
replyTo=Parcels.unwrap(getArguments().getParcelable("replyTo"));
|
replyTo=Parcels.unwrap(getArguments().getParcelable("replyTo"));
|
||||||
|
if(getArguments().containsKey("quote"))
|
||||||
|
quote=Parcels.unwrap(getArguments().getParcelable("quote"));
|
||||||
if(instance==null){
|
if(instance==null){
|
||||||
Nav.finish(this);
|
Nav.finish(this);
|
||||||
return;
|
return;
|
||||||
@@ -355,7 +359,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
scheduleTimeBtn=view.findViewById(R.id.scheduled_time_btn);
|
scheduleTimeBtn=view.findViewById(R.id.scheduled_time_btn);
|
||||||
sensitiveIcon=view.findViewById(R.id.sensitive_icon);
|
sensitiveIcon=view.findViewById(R.id.sensitive_icon);
|
||||||
sensitiveItem=view.findViewById(R.id.sensitive_item);
|
sensitiveItem=view.findViewById(R.id.sensitive_item);
|
||||||
replyText=view.findViewById(R.id.reply_text);
|
replyText=view.findViewById(GlobalUserPreferences.replyLineAboveHeader ? R.id.reply_text : R.id.reply_text_below);
|
||||||
|
view.findViewById(GlobalUserPreferences.replyLineAboveHeader ? R.id.reply_text_below : R.id.reply_text)
|
||||||
|
.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (isPhotoPickerAvailable()) {
|
if (isPhotoPickerAvailable()) {
|
||||||
PopupMenu attachPopup = new PopupMenu(getContext(), mediaBtn);
|
PopupMenu attachPopup = new PopupMenu(getContext(), mediaBtn);
|
||||||
@@ -627,7 +633,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
spoilerEdit.addTextChangedListener(new SimpleTextWatcher(e->updateCharCounter()));
|
spoilerEdit.addTextChangedListener(new SimpleTextWatcher(e->updateCharCounter()));
|
||||||
if(replyTo!=null){
|
if(replyTo!=null || quote!=null){
|
||||||
|
Status status = quote!=null ? quote : replyTo;
|
||||||
View replyWrap = view.findViewById(R.id.reply_wrap);
|
View replyWrap = view.findViewById(R.id.reply_wrap);
|
||||||
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
||||||
int scrollHeight = scrollView.getHeight();
|
int scrollHeight = scrollView.getHeight();
|
||||||
@@ -653,13 +660,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
originalPost.setOnClickListener(v->{
|
originalPost.setOnClickListener(v->{
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putParcelable("status", Parcels.wrap(replyTo));
|
args.putParcelable("status", Parcels.wrap(status));
|
||||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||||
Nav.go(getActivity(), ThreadFragment.class, args);
|
Nav.go(getActivity(), ThreadFragment.class, args);
|
||||||
});
|
});
|
||||||
|
|
||||||
ImageView avatar = view.findViewById(R.id.avatar);
|
ImageView avatar = view.findViewById(R.id.avatar);
|
||||||
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(replyTo.account.avatar));
|
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(status.account.avatar));
|
||||||
ViewOutlineProvider roundCornersOutline=new ViewOutlineProvider(){
|
ViewOutlineProvider roundCornersOutline=new ViewOutlineProvider(){
|
||||||
@Override
|
@Override
|
||||||
public void getOutline(View view, Outline outline){
|
public void getOutline(View view, Outline outline){
|
||||||
@@ -671,15 +678,15 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
avatar.setOnClickListener(v->{
|
avatar.setOnClickListener(v->{
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(replyTo.account));
|
args.putParcelable("profileAccount", Parcels.wrap(status.account));
|
||||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||||
Nav.go(getActivity(), ProfileFragment.class, args);
|
Nav.go(getActivity(), ProfileFragment.class, args);
|
||||||
});
|
});
|
||||||
|
|
||||||
((TextView) view.findViewById(R.id.name)).setText(replyTo.account.displayName);
|
((TextView) view.findViewById(R.id.name)).setText(status.account.displayName);
|
||||||
((TextView) view.findViewById(R.id.username)).setText(replyTo.account.getDisplayUsername());
|
((TextView) view.findViewById(R.id.username)).setText(status.account.getDisplayUsername());
|
||||||
view.findViewById(R.id.visibility).setVisibility(View.GONE);
|
view.findViewById(R.id.visibility).setVisibility(View.GONE);
|
||||||
Drawable visibilityIcon = getActivity().getDrawable(switch(replyTo.visibility){
|
Drawable visibilityIcon = getActivity().getDrawable(switch(status.visibility){
|
||||||
case PUBLIC -> R.drawable.ic_fluent_earth_20_regular;
|
case PUBLIC -> R.drawable.ic_fluent_earth_20_regular;
|
||||||
case UNLISTED -> R.drawable.ic_fluent_lock_open_20_regular;
|
case UNLISTED -> R.drawable.ic_fluent_lock_open_20_regular;
|
||||||
case PRIVATE -> R.drawable.ic_fluent_lock_closed_20_filled;
|
case PRIVATE -> R.drawable.ic_fluent_lock_closed_20_filled;
|
||||||
@@ -690,27 +697,28 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
moreBtn.setImageDrawable(visibilityIcon);
|
moreBtn.setImageDrawable(visibilityIcon);
|
||||||
moreBtn.setBackground(null);
|
moreBtn.setBackground(null);
|
||||||
TextView timestamp = view.findViewById(R.id.timestamp);
|
TextView timestamp = view.findViewById(R.id.timestamp);
|
||||||
if (replyTo.editedAt==null) timestamp.setText(UiUtils.formatRelativeTimestamp(getContext(), replyTo.createdAt));
|
if (status.editedAt!=null) timestamp.setText(getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(getContext(), status.editedAt)));
|
||||||
else timestamp.setText(getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(getContext(), replyTo.editedAt)));
|
else if (status.createdAt!=null) timestamp.setText(UiUtils.formatRelativeTimestamp(getContext(), status.createdAt));
|
||||||
if (replyTo.spoilerText != null && !replyTo.spoilerText.isBlank()) {
|
else timestamp.setText("");
|
||||||
|
if (status.spoilerText != null && !status.spoilerText.isBlank()) {
|
||||||
view.findViewById(R.id.spoiler_header).setVisibility(View.VISIBLE);
|
view.findViewById(R.id.spoiler_header).setVisibility(View.VISIBLE);
|
||||||
((TextView) view.findViewById(R.id.spoiler_title_inline)).setText(replyTo.spoilerText);
|
((TextView) view.findViewById(R.id.spoiler_title_inline)).setText(status.spoilerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpannableStringBuilder content = HtmlParser.parse(replyTo.content, replyTo.emojis, replyTo.mentions, replyTo.tags, accountID);
|
SpannableStringBuilder content = HtmlParser.parse(status.content, status.emojis, status.mentions, status.tags, accountID);
|
||||||
LinkedTextView text = view.findViewById(R.id.text);
|
LinkedTextView text = view.findViewById(R.id.text);
|
||||||
if (content.length() > 0) text.setText(content);
|
if (content.length() > 0) text.setText(content);
|
||||||
else view.findViewById(R.id.display_item_text).setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
|
else view.findViewById(R.id.display_item_text).setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
|
||||||
|
|
||||||
replyText.setText(getString(R.string.in_reply_to, replyTo.account.displayName));
|
replyText.setText(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.displayName));
|
||||||
int visibilityNameRes = switch (replyTo.visibility) {
|
int visibilityNameRes = switch (status.visibility) {
|
||||||
case PUBLIC -> R.string.visibility_public;
|
case PUBLIC -> R.string.visibility_public;
|
||||||
case UNLISTED -> R.string.sk_visibility_unlisted;
|
case UNLISTED -> R.string.sk_visibility_unlisted;
|
||||||
case PRIVATE -> R.string.visibility_followers_only;
|
case PRIVATE -> R.string.visibility_followers_only;
|
||||||
case DIRECT -> R.string.visibility_private;
|
case DIRECT -> R.string.visibility_private;
|
||||||
case LOCAL -> R.string.sk_local_only;
|
case LOCAL -> R.string.sk_local_only;
|
||||||
};
|
};
|
||||||
replyText.setContentDescription(getString(R.string.in_reply_to, replyTo.account.displayName) + ". " + getString(R.string.post_visibility) + ": " + getString(visibilityNameRes));
|
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.displayName) + ". " + getString(R.string.post_visibility) + ": " + getString(visibilityNameRes));
|
||||||
replyText.setOnClickListener(v->{
|
replyText.setOnClickListener(v->{
|
||||||
scrollView.smoothScrollTo(0, 0);
|
scrollView.smoothScrollTo(0, 0);
|
||||||
});
|
});
|
||||||
@@ -721,9 +729,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
|
|
||||||
ArrayList<String> mentions=new ArrayList<>();
|
ArrayList<String> mentions=new ArrayList<>();
|
||||||
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
||||||
if(!replyTo.account.id.equals(ownID))
|
if(!status.account.id.equals(ownID))
|
||||||
mentions.add('@'+replyTo.account.acct);
|
mentions.add('@'+status.account.acct);
|
||||||
for(Mention mention:replyTo.mentions){
|
for(Mention mention:status.mentions){
|
||||||
if(mention.id.equals(ownID))
|
if(mention.id.equals(ownID))
|
||||||
continue;
|
continue;
|
||||||
String m='@'+mention.acct;
|
String m='@'+mention.acct;
|
||||||
@@ -736,17 +744,17 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
ignoreSelectionChanges=true;
|
ignoreSelectionChanges=true;
|
||||||
mainEditText.setSelection(mainEditText.length());
|
mainEditText.setSelection(mainEditText.length());
|
||||||
ignoreSelectionChanges=false;
|
ignoreSelectionChanges=false;
|
||||||
if(!TextUtils.isEmpty(replyTo.spoilerText)){
|
if(!TextUtils.isEmpty(status.spoilerText)){
|
||||||
hasSpoiler=true;
|
hasSpoiler=true;
|
||||||
spoilerEdit.setVisibility(View.VISIBLE);
|
spoilerEdit.setVisibility(View.VISIBLE);
|
||||||
if(GlobalUserPreferences.prefixRepliesWithRe && !replyTo.spoilerText.startsWith("re: ")){
|
if(GlobalUserPreferences.prefixRepliesWithRe && !status.spoilerText.startsWith("re: ")){
|
||||||
spoilerEdit.setText("re: " + replyTo.spoilerText);
|
spoilerEdit.setText("re: " + status.spoilerText);
|
||||||
}else{
|
}else{
|
||||||
spoilerEdit.setText(replyTo.spoilerText);
|
spoilerEdit.setText(status.spoilerText);
|
||||||
}
|
}
|
||||||
spoilerBtn.setSelected(true);
|
spoilerBtn.setSelected(true);
|
||||||
}
|
}
|
||||||
if (replyTo.language != null && !replyTo.language.isEmpty()) updateLanguage(replyTo.language);
|
if (status.language != null && !status.language.isEmpty()) updateLanguage(status.language);
|
||||||
}
|
}
|
||||||
}else if (editingStatus==null || editingStatus.inReplyToId==null){
|
}else if (editingStatus==null || editingStatus.inReplyToId==null){
|
||||||
// TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed
|
// TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed
|
||||||
@@ -1012,9 +1020,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onCustomEmojiClick(Emoji emoji){
|
private void onCustomEmojiClick(Emoji emoji){
|
||||||
int start=mainEditText.getSelectionStart();
|
if(getActivity().getCurrentFocus() instanceof EditText edit){
|
||||||
String prefix=start>0 && !Character.isWhitespace(mainEditText.getText().charAt(start-1)) ? " :" : ":";
|
int start=edit.getSelectionStart();
|
||||||
mainEditText.getText().replace(start, mainEditText.getSelectionEnd(), prefix+emoji.shortcode+':');
|
String prefix=start>0 && !Character.isWhitespace(edit.getText().charAt(start-1)) ? " :" : ":";
|
||||||
|
edit.getText().replace(start, edit.getSelectionEnd(), prefix+emoji.shortcode+':');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1137,6 +1147,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
if(hasSpoiler && spoilerEdit.length()>0){
|
if(hasSpoiler && spoilerEdit.length()>0){
|
||||||
req.spoilerText=spoilerEdit.getText().toString();
|
req.spoilerText=spoilerEdit.getText().toString();
|
||||||
}
|
}
|
||||||
|
if(quote != null){
|
||||||
|
req.quoteId=quote.id;
|
||||||
|
}
|
||||||
if(uuid==null)
|
if(uuid==null)
|
||||||
uuid=UUID.randomUUID().toString();
|
uuid=UUID.randomUUID().toString();
|
||||||
|
|
||||||
@@ -1169,7 +1182,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}else{
|
}else{
|
||||||
E.post(new StatusUpdatedEvent(result));
|
E.post(new StatusUpdatedEvent(result));
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !isStateSaved()) {
|
||||||
Nav.finish(ComposeFragment.this);
|
Nav.finish(ComposeFragment.this);
|
||||||
|
}
|
||||||
if (getArguments().getBoolean("navigateToStatus", false)) {
|
if (getArguments().getBoolean("navigateToStatus", false)) {
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
@@ -1370,6 +1385,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StringFormatInvalid")
|
||||||
private boolean addMediaAttachment(Uri uri, String description){
|
private boolean addMediaAttachment(Uri uri, String description){
|
||||||
if(getMediaAttachmentsCount()==MAX_ATTACHMENTS){
|
if(getMediaAttachmentsCount()==MAX_ATTACHMENTS){
|
||||||
showMediaAttachmentError(getResources().getQuantityString(R.plurals.cant_add_more_than_x_attachments, MAX_ATTACHMENTS, MAX_ATTACHMENTS));
|
showMediaAttachmentError(getResources().getQuantityString(R.plurals.cant_add_more_than_x_attachments, MAX_ATTACHMENTS, MAX_ATTACHMENTS));
|
||||||
@@ -1945,7 +1961,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadDefaultStatusVisibility(Bundle savedInstanceState) {
|
private void loadDefaultStatusVisibility(Bundle savedInstanceState) {
|
||||||
if(replyTo != null) statusVisibility = replyTo.visibility;
|
if(replyTo != null) {
|
||||||
|
statusVisibility = (replyTo.visibility == StatusPrivacy.PUBLIC && GlobalUserPreferences.defaultToUnlistedReplies ? StatusPrivacy.UNLISTED : replyTo.visibility);
|
||||||
|
}
|
||||||
|
|
||||||
// A saved privacy setting from a previous compose session wins over the reply visibility
|
// A saved privacy setting from a previous compose session wins over the reply visibility
|
||||||
if(savedInstanceState !=null){
|
if(savedInstanceState !=null){
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
|
import org.joinmastodon.android.MainActivity;
|
||||||
|
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||||
|
import org.joinmastodon.android.model.Filter;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
|
public class CustomLocalTimelineFragment extends StatusListFragment {
|
||||||
|
// private String name;
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
private String maxID;
|
||||||
|
@Override
|
||||||
|
protected boolean withComposeButton() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity){
|
||||||
|
super.onAttach(activity);
|
||||||
|
domain=getArguments().getString("domain");
|
||||||
|
updateTitle(domain);
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTitle(String domain) {
|
||||||
|
this.domain = domain;
|
||||||
|
setTitle(this.domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doLoadData(int offset, int count){
|
||||||
|
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count)
|
||||||
|
.setCallback(new SimpleCallback<>(this){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<Status> result){
|
||||||
|
if(!result.isEmpty())
|
||||||
|
maxID=result.get(result.size()-1).id;
|
||||||
|
if (getActivity() == null) return;
|
||||||
|
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
|
||||||
|
result.stream().forEach(status -> {
|
||||||
|
status.account.acct += "@"+domain;
|
||||||
|
status.mentions.forEach(mention -> mention.id = null);
|
||||||
|
status.reloadWhenClicked = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
onDataLoaded(result, !result.isEmpty());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execNoAuth(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onShown(){
|
||||||
|
super.onShown();
|
||||||
|
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
|
||||||
|
public interface DomainDisplay {
|
||||||
|
|
||||||
|
default String getDomain(){
|
||||||
|
AccountSession session = AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
|
if (session != null)
|
||||||
|
return session.domain;
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import static org.joinmastodon.android.ui.utils.UiUtils.makeBackItem;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.InputType;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -15,6 +16,7 @@ import android.view.SubMenu;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@@ -30,6 +32,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.lists.GetLists;
|
import org.joinmastodon.android.api.requests.lists.GetLists;
|
||||||
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
|
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
|
||||||
|
import org.joinmastodon.android.model.CustomLocalTimeline;
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.model.HeaderPaginationList;
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
import org.joinmastodon.android.model.ListTimeline;
|
import org.joinmastodon.android.model.ListTimeline;
|
||||||
@@ -47,11 +50,11 @@ import java.util.Map;
|
|||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefinition> implements ScrollableToTop {
|
public class EditTimelinesFragment extends RecyclerFragment<TimelineDefinition> implements ScrollableToTop {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private TimelinesAdapter adapter;
|
private TimelinesAdapter adapter;
|
||||||
private final ItemTouchHelper itemTouchHelper;
|
private final ItemTouchHelper itemTouchHelper;
|
||||||
@@ -60,6 +63,7 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
private final Map<MenuItem, TimelineDefinition> timelineByMenuItem = new HashMap<>();
|
private final Map<MenuItem, TimelineDefinition> timelineByMenuItem = new HashMap<>();
|
||||||
private final List<ListTimeline> listTimelines = new ArrayList<>();
|
private final List<ListTimeline> listTimelines = new ArrayList<>();
|
||||||
private final List<Hashtag> hashtags = new ArrayList<>();
|
private final List<Hashtag> hashtags = new ArrayList<>();
|
||||||
|
private final List<CustomLocalTimeline> localTimelines = new ArrayList<>();
|
||||||
|
|
||||||
public EditTimelinesFragment() {
|
public EditTimelinesFragment() {
|
||||||
super(10);
|
super(10);
|
||||||
@@ -128,6 +132,10 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
optionsMenu.performIdentifierAction(R.id.menu_add_timeline, 0);
|
optionsMenu.performIdentifierAction(R.id.menu_add_timeline, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (item.getItemId() == R.id.menu_add_local_timelines) {
|
||||||
|
addNewLocalTimeline();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
TimelineDefinition tl = timelineByMenuItem.get(item);
|
TimelineDefinition tl = timelineByMenuItem.get(item);
|
||||||
if (tl != null) {
|
if (tl != null) {
|
||||||
data.add(tl.copy());
|
data.add(tl.copy());
|
||||||
@@ -138,6 +146,26 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addNewLocalTimeline() {
|
||||||
|
FrameLayout inputWrap = new FrameLayout(getContext());
|
||||||
|
EditText input = new EditText(getContext());
|
||||||
|
input.setHint(R.string.sk_example_domain);
|
||||||
|
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
|
||||||
|
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
params.setMargins(V.dp(16), V.dp(4), V.dp(16), V.dp(16));
|
||||||
|
input.setLayoutParams(params);
|
||||||
|
inputWrap.addView(input);
|
||||||
|
new M3AlertDialogBuilder(getContext()).setTitle(R.string.mo_add_custom_server_local_timeline).setView(inputWrap)
|
||||||
|
.setPositiveButton(R.string.save, (d, which) -> {
|
||||||
|
TimelineDefinition tl = TimelineDefinition.ofCustomLocalTimeline(input.getText().toString().trim());
|
||||||
|
data.add(tl);
|
||||||
|
saveTimelines();
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.cancel, (d, which) -> {
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void addTimelineToOptions(TimelineDefinition tl, Menu menu) {
|
private void addTimelineToOptions(TimelineDefinition tl, Menu menu) {
|
||||||
if (data.contains(tl)) return;
|
if (data.contains(tl)) return;
|
||||||
MenuItem item = menu.add(0, View.generateViewId(), Menu.NONE, tl.getTitle(getContext()));
|
MenuItem item = menu.add(0, View.generateViewId(), Menu.NONE, tl.getTitle(getContext()));
|
||||||
@@ -161,6 +189,9 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
SubMenu hashtagsMenu = menu.addSubMenu(R.string.sk_hashtag);
|
SubMenu hashtagsMenu = menu.addSubMenu(R.string.sk_hashtag);
|
||||||
hashtagsMenu.getItem().setIcon(R.drawable.ic_fluent_number_symbol_24_regular);
|
hashtagsMenu.getItem().setIcon(R.drawable.ic_fluent_number_symbol_24_regular);
|
||||||
|
|
||||||
|
MenuItem addLocalTimelines = menu.add(0, R.id.menu_add_local_timelines, NONE, R.string.local_timeline);
|
||||||
|
addLocalTimelines.setIcon(R.drawable.ic_fluent_add_24_regular);
|
||||||
|
|
||||||
makeBackItem(timelinesMenu);
|
makeBackItem(timelinesMenu);
|
||||||
makeBackItem(listsMenu);
|
makeBackItem(listsMenu);
|
||||||
makeBackItem(hashtagsMenu);
|
makeBackItem(hashtagsMenu);
|
||||||
@@ -205,6 +236,11 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import me.grishka.appkit.Nav;
|
|||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
@@ -47,7 +46,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class FollowRequestsListFragment extends BaseRecyclerFragment<FollowRequestsListFragment.AccountWrapper> implements ScrollableToTop{
|
public class FollowRequestsListFragment extends RecyclerFragment<FollowRequestsListFragment.AccountWrapper> implements ScrollableToTop{
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||||
private GetAccountRelationships relationshipsRequest;
|
private GetAccountRelationships relationshipsRequest;
|
||||||
@@ -149,6 +148,11 @@ public class FollowRequestsListFragment extends BaseRecyclerFragment<FollowReque
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|
||||||
public AccountsAdapter(){
|
public AccountsAdapter(){
|
||||||
|
|||||||
@@ -16,11 +16,10 @@ import org.joinmastodon.android.ui.DividerItemDecoration;
|
|||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class FollowedHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop {
|
public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop {
|
||||||
private String nextMaxID;
|
private String nextMaxID;
|
||||||
private String accountId;
|
private String accountId;
|
||||||
|
|
||||||
@@ -76,6 +75,11 @@ public class FollowedHashtagsFragment extends BaseRecyclerFragment<Hashtag> impl
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
|
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.tags.GetHashtag;
|
import org.joinmastodon.android.api.requests.tags.GetHashtag;
|
||||||
@@ -43,12 +44,19 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/tags/" + hashtag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity){
|
public void onAttach(Activity activity){
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
updateTitle(getArguments().getString("hashtag"));
|
updateTitle(getArguments().getString("hashtag"));
|
||||||
following=getArguments().getBoolean("following", false);
|
following=getArguments().getBoolean("following", false);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
DomainManager.getInstance().setCurrentDomain(getDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTitle(String hashtagName) {
|
private void updateTitle(String hashtagName) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.joinmastodon.android.fragments;
|
|||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -16,21 +17,41 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.IdRes;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.MainActivity;
|
||||||
|
import org.joinmastodon.android.E;
|
||||||
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
|
||||||
|
import org.joinmastodon.android.events.NotificationReceivedEvent;
|
||||||
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
|
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.TabBar;
|
import org.joinmastodon.android.ui.views.TabBar;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.annotation.IdRes;
|
import androidx.annotation.IdRes;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
import me.grishka.appkit.FragmentStackActivity;
|
import me.grishka.appkit.FragmentStackActivity;
|
||||||
|
import me.grishka.appkit.api.Callback;
|
||||||
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.fragments.AppKitFragment;
|
import me.grishka.appkit.fragments.AppKitFragment;
|
||||||
import me.grishka.appkit.fragments.LoaderFragment;
|
import me.grishka.appkit.fragments.LoaderFragment;
|
||||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||||
@@ -44,14 +65,13 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
|
|
||||||
private HomeTabFragment homeTabFragment;
|
private HomeTabFragment homeTabFragment;
|
||||||
|
|
||||||
// private HomeTimelineFragment homeTimelineFragment;
|
|
||||||
|
|
||||||
private NotificationsFragment notificationsFragment;
|
private NotificationsFragment notificationsFragment;
|
||||||
private DiscoverFragment searchFragment;
|
private DiscoverFragment searchFragment;
|
||||||
private ProfileFragment profileFragment;
|
private ProfileFragment profileFragment;
|
||||||
private TabBar tabBar;
|
private TabBar tabBar;
|
||||||
private View tabBarWrap;
|
private View tabBarWrap;
|
||||||
private ImageView tabBarAvatar;
|
private ImageView tabBarAvatar;
|
||||||
|
private ImageView notificationTabIcon;
|
||||||
@IdRes
|
@IdRes
|
||||||
private int currentTab=R.id.tab_home;
|
private int currentTab=R.id.tab_home;
|
||||||
|
|
||||||
@@ -60,6 +80,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
E.register(this);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
setTitle(R.string.mo_app_name);
|
setTitle(R.string.mo_app_name);
|
||||||
|
|
||||||
@@ -73,9 +94,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
homeTabFragment=new HomeTabFragment();
|
homeTabFragment=new HomeTabFragment();
|
||||||
homeTabFragment.setArguments(args);
|
homeTabFragment.setArguments(args);
|
||||||
|
|
||||||
// homeTimelineFragment=new HomeTimelineFragment();
|
|
||||||
// homeTimelineFragment.setArguments(args);
|
|
||||||
|
|
||||||
args=new Bundle(args);
|
args=new Bundle(args);
|
||||||
args.putBoolean("noAutoLoad", true);
|
args.putBoolean("noAutoLoad", true);
|
||||||
searchFragment=new DiscoverFragment();
|
searchFragment=new DiscoverFragment();
|
||||||
@@ -117,6 +135,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
|
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
|
||||||
ViewImageLoader.load(tabBarAvatar, null, new UrlImageLoaderRequest(self.avatar, V.dp(28), V.dp(28)));
|
ViewImageLoader.load(tabBarAvatar, null, new UrlImageLoaderRequest(self.avatar, V.dp(28), V.dp(28)));
|
||||||
|
|
||||||
|
notificationTabIcon=content.findViewById(R.id.tab_notifications);
|
||||||
|
updateNotificationBadge();
|
||||||
|
|
||||||
if(savedInstanceState==null){
|
if(savedInstanceState==null){
|
||||||
getChildFragmentManager().beginTransaction()
|
getChildFragmentManager().beginTransaction()
|
||||||
.add(R.id.fragment_wrap, homeTabFragment)
|
.add(R.id.fragment_wrap, homeTabFragment)
|
||||||
@@ -125,12 +146,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
.add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
|
.add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
||||||
// getChildFragmentManager().beginTransaction()
|
|
||||||
// .add(R.id.fragment_wrap, homeTimelineFragment)
|
|
||||||
// .add(R.id.fragment_wrap, searchFragment).hide(searchFragment)
|
|
||||||
// .add(R.id.fragment_wrap, notificationsFragment).hide(notificationsFragment)
|
|
||||||
// .add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
|
|
||||||
// .commit();
|
|
||||||
|
|
||||||
String defaultTab=getArguments().getString("tab");
|
String defaultTab=getArguments().getString("tab");
|
||||||
if("notifications".equals(defaultTab)){
|
if("notifications".equals(defaultTab)){
|
||||||
@@ -155,12 +170,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
|
|
||||||
if(savedInstanceState==null) return;
|
if(savedInstanceState==null) return;
|
||||||
|
|
||||||
// if(savedInstanceState==null || homeTimelineFragment!=null)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
homeTabFragment=(HomeTabFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTabFragment");
|
homeTabFragment=(HomeTabFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTabFragment");
|
||||||
|
|
||||||
// homeTimelineFragment=(HomeTimelineFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTimelineFragment");
|
|
||||||
searchFragment=(DiscoverFragment) getChildFragmentManager().getFragment(savedInstanceState, "searchFragment");
|
searchFragment=(DiscoverFragment) getChildFragmentManager().getFragment(savedInstanceState, "searchFragment");
|
||||||
notificationsFragment=(NotificationsFragment) getChildFragmentManager().getFragment(savedInstanceState, "notificationsFragment");
|
notificationsFragment=(NotificationsFragment) getChildFragmentManager().getFragment(savedInstanceState, "notificationsFragment");
|
||||||
profileFragment=(ProfileFragment) getChildFragmentManager().getFragment(savedInstanceState, "profileFragment");
|
profileFragment=(ProfileFragment) getChildFragmentManager().getFragment(savedInstanceState, "profileFragment");
|
||||||
@@ -175,19 +187,14 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
.show(current)
|
.show(current)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
||||||
// getChildFragmentManager().beginTransaction()
|
|
||||||
// .hide(homeTimelineFragment)
|
|
||||||
// .hide(searchFragment)
|
|
||||||
// .hide(notificationsFragment)
|
|
||||||
// .hide(profileFragment)
|
|
||||||
// .show(current)
|
|
||||||
// .commit();
|
|
||||||
maybeTriggerLoading(current);
|
maybeTriggerLoading(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHiddenChanged(boolean hidden){
|
public void onHiddenChanged(boolean hidden){
|
||||||
super.onHiddenChanged(hidden);
|
super.onHiddenChanged(hidden);
|
||||||
|
if (!hidden && fragmentForTab(currentTab) instanceof DomainDisplay display)
|
||||||
|
DomainManager.getInstance().setCurrentDomain(display.getDomain());
|
||||||
fragmentForTab(currentTab).onHiddenChanged(hidden);
|
fragmentForTab(currentTab).onHiddenChanged(hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,8 +221,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
|
|
||||||
homeTabFragment.onApplyWindowInsets(topOnlyInsets);
|
homeTabFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
|
|
||||||
// homeTimelineFragment.onApplyWindowInsets(topOnlyInsets);
|
|
||||||
|
|
||||||
searchFragment.onApplyWindowInsets(topOnlyInsets);
|
searchFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
notificationsFragment.onApplyWindowInsets(topOnlyInsets);
|
notificationsFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
profileFragment.onApplyWindowInsets(topOnlyInsets);
|
profileFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
@@ -224,9 +229,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
private Fragment fragmentForTab(@IdRes int tab){
|
private Fragment fragmentForTab(@IdRes int tab){
|
||||||
if(tab==R.id.tab_home){
|
if(tab==R.id.tab_home){
|
||||||
return homeTabFragment;
|
return homeTabFragment;
|
||||||
|
|
||||||
// if(tab==R.id.tab_home){
|
|
||||||
// return homeTimelineFragment;
|
|
||||||
}else if(tab==R.id.tab_search){
|
}else if(tab==R.id.tab_search){
|
||||||
return searchFragment;
|
return searchFragment;
|
||||||
}else if(tab==R.id.tab_notifications){
|
}else if(tab==R.id.tab_notifications){
|
||||||
@@ -255,6 +257,11 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
scrollable.scrollToTop();
|
scrollable.scrollToTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newFragment instanceof DomainDisplay display) {
|
||||||
|
DomainManager.getInstance().setCurrentDomain(display.getDomain());
|
||||||
|
}
|
||||||
|
|
||||||
getChildFragmentManager().beginTransaction().hide(fragmentForTab(currentTab)).show(newFragment).commit();
|
getChildFragmentManager().beginTransaction().hide(fragmentForTab(currentTab)).show(newFragment).commit();
|
||||||
maybeTriggerLoading(newFragment);
|
maybeTriggerLoading(newFragment);
|
||||||
currentTab=tab;
|
currentTab=tab;
|
||||||
@@ -285,7 +292,10 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
|
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
|
||||||
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")");
|
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")");
|
||||||
}
|
}
|
||||||
new AccountSwitcherSheet(getActivity()).show();
|
new AccountSwitcherSheet(getActivity(), true, true, false, accountSession -> {
|
||||||
|
getActivity().finish();
|
||||||
|
getActivity().startActivity(new Intent(getActivity(), MainActivity.class));
|
||||||
|
}).show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(tab==R.id.tab_search){
|
if(tab==R.id.tab_search){
|
||||||
@@ -321,10 +331,50 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
if (searchFragment.isAdded()) getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
|
if (searchFragment.isAdded()) getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
|
||||||
if (notificationsFragment.isAdded()) getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
if (notificationsFragment.isAdded()) getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
||||||
if (profileFragment.isAdded()) getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
if (profileFragment.isAdded()) getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
||||||
|
}
|
||||||
|
|
||||||
// getChildFragmentManager().putFragment(outState, "homeTimelineFragment", homeTimelineFragment);
|
public void updateNotificationBadge() {
|
||||||
// getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
|
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
// getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
|
||||||
// getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
if (instance == null) return;
|
||||||
|
|
||||||
|
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance != null && instance.pleroma != null)
|
||||||
|
.setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<Notification> notifications) {
|
||||||
|
if (notifications.size() > 0) {
|
||||||
|
try {
|
||||||
|
long newestId = Long.parseLong(notifications.get(0).id);
|
||||||
|
long lastSeenId = Long.parseLong(session.markers.notifications.lastReadId);
|
||||||
|
System.out.println("NEWEST: " + newestId);
|
||||||
|
System.out.println("LAST SEEN: " + lastSeenId);
|
||||||
|
|
||||||
|
setNotificationBadge(newestId > lastSeenId);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
setNotificationBadge(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
setNotificationBadge(false);
|
||||||
|
}
|
||||||
|
}).exec(accountID);
|
||||||
|
}
|
||||||
|
public void setNotificationBadge(boolean badge) {
|
||||||
|
notificationTabIcon.setImageResource(badge
|
||||||
|
? R.drawable.ic_fluent_alert_28_selector_badged
|
||||||
|
: R.drawable.ic_fluent_alert_28_selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onNotificationReceived(NotificationReceivedEvent notificationReceivedEvent) {
|
||||||
|
if (notificationReceivedEvent.account.equals(accountID)) setNotificationBadge(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onAllNotificationsSeen(AllNotificationsSeenEvent allNotificationsSeenEvent) {
|
||||||
|
setNotificationBadge(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.reduceMotion;
|
import static org.joinmastodon.android.GlobalUserPreferences.reduceMotion;
|
||||||
|
import static org.joinmastodon.android.GlobalUserPreferences.showNewPostsButton;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
@@ -35,6 +36,7 @@ import androidx.viewpager2.widget.ViewPager2;
|
|||||||
|
|
||||||
import com.squareup.otto.Subscribe;
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -70,7 +72,7 @@ import me.grishka.appkit.fragments.OnBackPressedListener;
|
|||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class HomeTabFragment extends MastodonToolbarFragment implements ScrollableToTop, OnBackPressedListener {
|
public class HomeTabFragment extends MastodonToolbarFragment implements ScrollableToTop, OnBackPressedListener, DomainDisplay {
|
||||||
private static final int ANNOUNCEMENTS_RESULT = 654;
|
private static final int ANNOUNCEMENTS_RESULT = 654;
|
||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
@@ -196,6 +198,10 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
if (fragments[position] instanceof BaseRecyclerFragment<?> page){
|
if (fragments[position] instanceof BaseRecyclerFragment<?> page){
|
||||||
if(!page.loaded && !page.isDataLoading()) page.loadData();
|
if(!page.loaded && !page.isDataLoading()) page.loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update recent app list url
|
||||||
|
if (fragments[position] instanceof DomainDisplay page)
|
||||||
|
DomainManager.getInstance().setCurrentDomain(page.getDomain());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -280,6 +286,14 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
}).exec(accountID);
|
}).exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
if (fragments[pager.getCurrentItem()] instanceof DomainDisplay page) {
|
||||||
|
return page.getDomain();
|
||||||
|
}
|
||||||
|
return DomainDisplay.super.getDomain();
|
||||||
|
}
|
||||||
|
|
||||||
private void addListsToOverflowMenu() {
|
private void addListsToOverflowMenu() {
|
||||||
Context ctx = getContext();
|
Context ctx = getContext();
|
||||||
listsMenu.clear();
|
listsMenu.clear();
|
||||||
@@ -358,7 +372,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
addListsToOverflowMenu();
|
addListsToOverflowMenu();
|
||||||
addHashtagsToOverflowMenu();
|
addHashtagsToOverflowMenu();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !UiUtils.isEMUI()) {
|
||||||
m.setGroupDividerEnabled(true);
|
m.setGroupDividerEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,9 +478,20 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrollToTop(){
|
public void scrollToTop(){
|
||||||
|
if (((ScrollableToTop) fragments[pager.getCurrentItem()]).isScrolledToTop() &&
|
||||||
|
!GlobalUserPreferences.disableDoubleTapToSwipe && !newPostsBtnShown) {
|
||||||
|
int nextPage = (pager.getCurrentItem() + 1) % count;
|
||||||
|
navigateTo(nextPage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
((ScrollableToTop) fragments[pager.getCurrentItem()]).scrollToTop();
|
((ScrollableToTop) fragments[pager.getCurrentItem()]).scrollToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return ((ScrollableToTop) fragments[pager.getCurrentItem()]).isScrolledToTop();
|
||||||
|
}
|
||||||
|
|
||||||
public void hideNewPostsButton(){
|
public void hideNewPostsButton(){
|
||||||
if(!newPostsBtnShown)
|
if(!newPostsBtnShown)
|
||||||
return;
|
return;
|
||||||
@@ -537,8 +562,8 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
|
|
||||||
private void onNewPostsBtnClick(View view) {
|
private void onNewPostsBtnClick(View view) {
|
||||||
if(newPostsBtnShown){
|
if(newPostsBtnShown){
|
||||||
hideNewPostsButton();
|
|
||||||
scrollToTop();
|
scrollToTop();
|
||||||
|
hideNewPostsButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/home";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity){
|
public void onAttach(Activity activity){
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
@@ -167,6 +172,10 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|
||||||
|
if (parent.getParentFragment() instanceof HomeFragment homeFragment) {
|
||||||
|
homeFragment.updateNotificationBadge();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -37,11 +37,10 @@ import me.grishka.appkit.Nav;
|
|||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> implements ScrollableToTop {
|
public class ListTimelinesFragment extends RecyclerFragment<ListTimeline> implements ScrollableToTop {
|
||||||
private String accountId;
|
private String accountId;
|
||||||
private String profileAccountId;
|
private String profileAccountId;
|
||||||
private final HashMap<String, Boolean> userInListBefore = new HashMap<>();
|
private final HashMap<String, Boolean> userInListBefore = new HashMap<>();
|
||||||
@@ -200,6 +199,11 @@ public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> im
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
private class ListsAdapter extends RecyclerView.Adapter<ListViewHolder>{
|
private class ListsAdapter extends RecyclerView.Adapter<ListViewHolder>{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import me.grishka.appkit.api.ErrorResponse;
|
|||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class NotificationsFragment extends MastodonToolbarFragment implements ScrollableToTop{
|
public class NotificationsFragment extends MastodonToolbarFragment implements ScrollableToTop, DomainDisplay{
|
||||||
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ViewPager2 pager;
|
private ViewPager2 pager;
|
||||||
@@ -48,6 +48,11 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return DomainDisplay.super.getDomain() + "/notifications";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -140,17 +145,20 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putBoolean("__is_tab", true);
|
args.putBoolean("__is_tab", true);
|
||||||
|
args.putBoolean("noAutoLoad", true);
|
||||||
|
|
||||||
allNotificationsFragment=new NotificationsListFragment();
|
allNotificationsFragment=new NotificationsListFragment();
|
||||||
allNotificationsFragment.setArguments(args);
|
allNotificationsFragment.setArguments(args);
|
||||||
|
|
||||||
args=new Bundle(args);
|
args=new Bundle(args);
|
||||||
args.putBoolean("onlyMentions", true);
|
args.putBoolean("onlyMentions", true);
|
||||||
|
args.putBoolean("noAutoLoad", true);
|
||||||
mentionsFragment=new NotificationsListFragment();
|
mentionsFragment=new NotificationsListFragment();
|
||||||
mentionsFragment.setArguments(args);
|
mentionsFragment.setArguments(args);
|
||||||
|
|
||||||
args=new Bundle(args);
|
args=new Bundle(args);
|
||||||
args.putBoolean("onlyPosts", true);
|
args.putBoolean("onlyPosts", true);
|
||||||
|
args.putBoolean("noAutoLoad", true);
|
||||||
postsFragment=new NotificationsListFragment();
|
postsFragment=new NotificationsListFragment();
|
||||||
postsFragment.setArguments(args);
|
postsFragment.setArguments(args);
|
||||||
|
|
||||||
@@ -197,9 +205,19 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrollToTop(){
|
public void scrollToTop(){
|
||||||
|
if (getFragmentForPage(pager.getCurrentItem()).isScrolledToTop() && !GlobalUserPreferences.disableDoubleTapToSwipe) {
|
||||||
|
int nextPage = (pager.getCurrentItem() + 1) % tabViews.length;
|
||||||
|
pager.setCurrentItem(nextPage, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
getFragmentForPage(pager.getCurrentItem()).scrollToTop();
|
getFragmentForPage(pager.getCurrentItem()).scrollToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return getFragmentForPage(pager.getCurrentItem()).isScrolledToTop();
|
||||||
|
}
|
||||||
|
|
||||||
public void loadData(){
|
public void loadData(){
|
||||||
refreshFollowRequestsBadge();
|
refreshFollowRequestsBadge();
|
||||||
if(allNotificationsFragment!=null && !allNotificationsFragment.loaded && !allNotificationsFragment.dataLoading)
|
if(allNotificationsFragment!=null && !allNotificationsFragment.loaded && !allNotificationsFragment.dataLoading)
|
||||||
@@ -226,7 +244,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
@Override
|
@Override
|
||||||
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||||
FrameLayout view=tabViews[viewType];
|
FrameLayout view=tabViews[viewType];
|
||||||
((ViewGroup)view.getParent()).removeView(view);
|
if (view.getParent() != null) ((ViewGroup)view.getParent()).removeView(view);
|
||||||
view.setVisibility(View.VISIBLE);
|
view.setVisibility(View.VISIBLE);
|
||||||
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
return new SimpleViewHolder(view);
|
return new SimpleViewHolder(view);
|
||||||
|
|||||||
@@ -11,17 +11,17 @@ import org.joinmastodon.android.E;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
|
||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.PaginatedResponse;
|
import org.joinmastodon.android.model.PaginatedResponse;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||||
@@ -40,7 +40,6 @@ import java.util.stream.Stream;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.utils.V;
|
|
||||||
|
|
||||||
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
|
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
|
||||||
private boolean onlyMentions;
|
private boolean onlyMentions;
|
||||||
@@ -53,6 +52,11 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/notifications";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -98,13 +102,6 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, n.status, extraText, n, null) : null;
|
HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, n.status, extraText, n, null) : null;
|
||||||
if(n.status!=null){
|
if(n.status!=null){
|
||||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS);
|
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS);
|
||||||
if(titleItem!=null){
|
|
||||||
for(StatusDisplayItem item:items){
|
|
||||||
if(item instanceof ImageStatusDisplayItem imgItem){
|
|
||||||
imgItem.horizontalInset=V.dp(32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(titleItem!=null)
|
if(titleItem!=null)
|
||||||
items.add(0, titleItem);
|
items.add(0, titleItem);
|
||||||
return items;
|
return items;
|
||||||
@@ -127,6 +124,8 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
knownAccounts.put(s.account.id, s.account);
|
knownAccounts.put(s.account.id, s.account);
|
||||||
if(s.status!=null && !knownAccounts.containsKey(s.status.account.id))
|
if(s.status!=null && !knownAccounts.containsKey(s.status.account.id))
|
||||||
knownAccounts.put(s.status.account.id, s.status.account);
|
knownAccounts.put(s.status.account.id, s.status.account);
|
||||||
|
if(s.status!=null && s.status.reblog!=null && !knownAccounts.containsKey(s.status.reblog.account.id))
|
||||||
|
knownAccounts.put(s.status.reblog.account.id, s.status.reblog.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -135,7 +134,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
.getAccount(accountID).getCacheController()
|
.getAccount(accountID).getCacheController()
|
||||||
.getNotifications(offset>0 ? maxID : null, count, onlyMentions, onlyPosts, refreshing, new SimpleCallback<>(this){
|
.getNotifications(offset>0 ? maxID : null, count, onlyMentions, onlyPosts, refreshing, new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(PaginatedResponse<List<Notification>> result){
|
public void onSuccess(CacheablePaginatedResponse<List<Notification>> result){
|
||||||
if (getActivity() == null) return;
|
if (getActivity() == null) return;
|
||||||
if(refreshing)
|
if(refreshing)
|
||||||
relationships.clear();
|
relationships.clear();
|
||||||
@@ -147,8 +146,12 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
loadRelationships(needRelationships);
|
loadRelationships(needRelationships);
|
||||||
maxID=result.maxID;
|
maxID=result.maxID;
|
||||||
|
|
||||||
if(offset==0 && !result.items.isEmpty()){
|
if(offset==0 && !result.items.isEmpty() && !result.isFromCache()){
|
||||||
|
E.post(new AllNotificationsSeenEvent());
|
||||||
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
|
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
|
||||||
|
AccountSessionManager.getInstance().getAccount(accountID).markers
|
||||||
|
.notifications.lastReadId = result.items.get(0).id;
|
||||||
|
AccountSessionManager.getInstance().writeAccountsFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -168,8 +171,11 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
@Override
|
@Override
|
||||||
protected void onShown(){
|
protected void onShown(){
|
||||||
super.onShown();
|
super.onShown();
|
||||||
// if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
|
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading){
|
||||||
// loadData();
|
refreshing=true;
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import org.joinmastodon.android.model.TimelineDefinition;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class PinnableStatusListFragment extends StatusListFragment {
|
public abstract class PinnableStatusListFragment extends StatusListFragment implements DomainDisplay {
|
||||||
protected boolean pinnedUpdated;
|
protected boolean pinnedUpdated;
|
||||||
protected List<TimelineDefinition> pinnedTimelines;
|
protected List<TimelineDefinition> pinnedTimelines;
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.SubMenu;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
@@ -47,7 +48,9 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.MainActivity;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
@@ -89,13 +92,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
@@ -158,7 +158,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
private WindowInsets childInsets;
|
private WindowInsets childInsets;
|
||||||
private PhotoViewer currentPhotoViewer;
|
private PhotoViewer currentPhotoViewer;
|
||||||
private boolean editModeLoading;
|
private boolean editModeLoading;
|
||||||
private boolean isScrollingUp = false;
|
protected int scrollDiff = 0;
|
||||||
|
|
||||||
private static final int MAX_FIELDS=4;
|
private static final int MAX_FIELDS=4;
|
||||||
|
|
||||||
@@ -206,6 +206,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHiddenChanged(boolean hidden) {
|
||||||
|
super.onHiddenChanged(hidden);
|
||||||
|
if (!hidden) {
|
||||||
|
DomainManager.getInstance().setCurrentDomain(account.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||||
View content=inflater.inflate(R.layout.fragment_profile, container, false);
|
View content=inflater.inflate(R.layout.fragment_profile, container, false);
|
||||||
@@ -359,6 +367,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
});
|
});
|
||||||
|
|
||||||
actionButton.setOnClickListener(this::onActionButtonClick);
|
actionButton.setOnClickListener(this::onActionButtonClick);
|
||||||
|
actionButton.setOnLongClickListener(this::onActionButtonLongClick);
|
||||||
notifyButton.setOnClickListener(this::onNotifyButtonClick);
|
notifyButton.setOnClickListener(this::onNotifyButtonClick);
|
||||||
avatar.setOnClickListener(this::onAvatarClick);
|
avatar.setOnClickListener(this::onAvatarClick);
|
||||||
cover.setOnClickListener(this::onCoverClick);
|
cover.setOnClickListener(this::onCoverClick);
|
||||||
@@ -453,6 +462,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh(){
|
public void onRefresh(){
|
||||||
|
if(isInEditMode){
|
||||||
|
refreshing=false;
|
||||||
|
refreshLayout.setRefreshing(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(refreshing)
|
if(refreshing)
|
||||||
return;
|
return;
|
||||||
refreshing=true;
|
refreshing=true;
|
||||||
@@ -511,6 +525,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
toolbarTitleView.setTranslationY(titleTransY);
|
toolbarTitleView.setTranslationY(titleTransY);
|
||||||
toolbarSubtitleView.setTranslationY(titleTransY);
|
toolbarSubtitleView.setTranslationY(titleTransY);
|
||||||
}
|
}
|
||||||
|
RecyclerFragment.setRefreshLayoutColors(refreshLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -569,8 +584,10 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
for (Account.Role role : account.roles) {
|
for (Account.Role role : account.roles) {
|
||||||
TextView roleText = new TextView(getActivity(), null, 0, R.style.role_label);
|
TextView roleText = new TextView(getActivity(), null, 0, R.style.role_label);
|
||||||
roleText.setText(role.name);
|
roleText.setText(role.name);
|
||||||
|
if (!TextUtils.isEmpty(role.color) && role.color.startsWith("#")) try {
|
||||||
GradientDrawable bg = (GradientDrawable) roleText.getBackground().mutate();
|
GradientDrawable bg = (GradientDrawable) roleText.getBackground().mutate();
|
||||||
bg.setStroke(V.dp(2), Color.parseColor(role.color));
|
bg.setStroke(V.dp(2), Color.parseColor(role.color));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
rolesView.addView(roleText);
|
rolesView.addView(roleText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -636,10 +653,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
fields.clear();
|
fields.clear();
|
||||||
|
|
||||||
|
if (account.createdAt != null) {
|
||||||
AccountField joined=new AccountField();
|
AccountField joined=new AccountField();
|
||||||
joined.parsedName=joined.name=getString(R.string.profile_joined);
|
joined.parsedName=joined.name=getString(R.string.profile_joined);
|
||||||
joined.parsedValue=joined.value=DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(LocalDateTime.ofInstant(account.createdAt, ZoneId.systemDefault()));
|
joined.parsedValue=joined.value=DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(LocalDateTime.ofInstant(account.createdAt, ZoneId.systemDefault()));
|
||||||
fields.add(joined);
|
fields.add(joined);
|
||||||
|
}
|
||||||
|
|
||||||
for(AccountField field:account.fields){
|
for(AccountField field:account.fields){
|
||||||
field.parsedValue=ssb=HtmlParser.parse(field.value, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
field.parsedValue=ssb=HtmlParser.parse(field.value, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
||||||
@@ -699,6 +718,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
}else{
|
}else{
|
||||||
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags, R.id.favorites, R.id.scheduled);
|
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags, R.id.favorites, R.id.scheduled);
|
||||||
}
|
}
|
||||||
|
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
||||||
|
MenuItem openWithAccounts = menu.findItem(R.id.open_with_account);
|
||||||
|
openWithAccounts.setVisible(hasMultipleAccounts);
|
||||||
|
SubMenu accountsMenu = openWithAccounts.getSubMenu();
|
||||||
|
if (hasMultipleAccounts) {
|
||||||
|
accountsMenu.clear();
|
||||||
|
UiUtils.populateAccountsMenu(accountID, accountsMenu, s-> UiUtils.openURL(
|
||||||
|
getActivity(), s.getID(), account.url, false
|
||||||
|
));
|
||||||
|
}
|
||||||
menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getShortUsername()));
|
menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getShortUsername()));
|
||||||
if(isOwnProfile)
|
if(isOwnProfile)
|
||||||
return;
|
return;
|
||||||
@@ -836,6 +865,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
// aboutFragment.setNote(relationship.note, accountID, profileAccountID);
|
// aboutFragment.setNote(relationship.note, accountID, profileAccountID);
|
||||||
}
|
}
|
||||||
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
|
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
|
||||||
|
DomainManager.getInstance().setCurrentDomain(account.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageButton getFab() {
|
public ImageButton getFab() {
|
||||||
@@ -872,6 +902,36 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
if(currentPhotoViewer!=null){
|
if(currentPhotoViewer!=null){
|
||||||
currentPhotoViewer.offsetView(0, oldScrollY-scrollY);
|
currentPhotoViewer.offsetView(0, oldScrollY-scrollY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GlobalUserPreferences.enableFabAutoHide){
|
||||||
|
int dy = scrollY - oldScrollY;
|
||||||
|
|
||||||
|
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
||||||
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
fab.getHeight() * 2);
|
||||||
|
animate.setDuration(300);
|
||||||
|
fab.startAnimation(animate);
|
||||||
|
fab.setVisibility(View.INVISIBLE);
|
||||||
|
scrollDiff = 0;
|
||||||
|
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
||||||
|
if (scrollDiff > 400) {
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
fab.getHeight() * 2,
|
||||||
|
0);
|
||||||
|
animate.setDuration(300);
|
||||||
|
fab.startAnimation(animate);
|
||||||
|
scrollDiff = 0;
|
||||||
|
} else {
|
||||||
|
scrollDiff += Math.abs(dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Fragment getFragmentForPage(int page){
|
private Fragment getFragmentForPage(int page){
|
||||||
@@ -900,6 +960,31 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean onActionButtonLongClick(View v) {
|
||||||
|
if (isOwnProfile || AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false;
|
||||||
|
UiUtils.pickAccount(getActivity(), accountID, R.string.sk_follow_as, R.drawable.ic_fluent_person_add_28_regular, session -> {
|
||||||
|
UiUtils.lookupAccount(getActivity(), account, session.getID(), accountID, acc -> {
|
||||||
|
if (acc == null) return;
|
||||||
|
new SetAccountFollowed(acc.id, true, true).setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Relationship relationship) {
|
||||||
|
Toast.makeText(
|
||||||
|
getActivity(),
|
||||||
|
getString(R.string.sk_followed_as, session.self.getShortUsername()),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(getActivity());
|
||||||
|
}
|
||||||
|
}).exec(session.getID());
|
||||||
|
});
|
||||||
|
}, null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void setActionProgressVisible(boolean visible){
|
private void setActionProgressVisible(boolean visible){
|
||||||
actionButton.setTextVisible(!visible);
|
actionButton.setTextVisible(!visible);
|
||||||
actionProgress.setVisibility(visible ? View.VISIBLE : View.GONE);
|
actionProgress.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||||
@@ -946,7 +1031,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
pager.setUserInputEnabled(false);
|
pager.setUserInputEnabled(false);
|
||||||
actionButton.setText(R.string.done);
|
actionButton.setText(R.string.done);
|
||||||
ArrayList<Animator> animators=new ArrayList<>();
|
ArrayList<Animator> animators=new ArrayList<>();
|
||||||
Drawable overlay=getResources().getDrawable(R.drawable.edit_avatar_overlay).mutate();
|
Drawable overlay=getResources().getDrawable(R.drawable.edit_avatar_overlay, getActivity().getTheme()).mutate();
|
||||||
avatar.setForeground(overlay);
|
avatar.setForeground(overlay);
|
||||||
animators.add(ObjectAnimator.ofInt(overlay, "alpha", 0, 255));
|
animators.add(ObjectAnimator.ofInt(overlay, "alpha", 0, 255));
|
||||||
|
|
||||||
@@ -1147,6 +1232,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
scrollView.smoothScrollTo(0, 0);
|
scrollView.smoothScrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void onFollowersOrFollowingClick(View v){
|
private void onFollowersOrFollowingClick(View v){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
@@ -1166,7 +1256,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
@Override
|
@Override
|
||||||
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||||
FrameLayout view=tabViews[viewType];
|
FrameLayout view=tabViews[viewType];
|
||||||
((ViewGroup)view.getParent()).removeView(view);
|
if (view.getParent() != null) ((ViewGroup)view.getParent()).removeView(view);
|
||||||
view.setVisibility(View.VISIBLE);
|
view.setVisibility(View.VISIBLE);
|
||||||
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
return new SimpleViewHolder(view);
|
return new SimpleViewHolder(view);
|
||||||
@@ -1318,6 +1408,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
private class EditableAboutViewHolder extends BaseViewHolder {
|
private class EditableAboutViewHolder extends BaseViewHolder {
|
||||||
private EditText title;
|
private EditText title;
|
||||||
|
private boolean titleHasFocus, valueHasFocus;
|
||||||
private EditText value;
|
private EditText value;
|
||||||
|
|
||||||
public EditableAboutViewHolder(){
|
public EditableAboutViewHolder(){
|
||||||
@@ -1329,7 +1420,19 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
title.addTextChangedListener(new SimpleTextWatcher(e->item.name=e.toString()));
|
title.addTextChangedListener(new SimpleTextWatcher(e->item.name=e.toString()));
|
||||||
|
title.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
|
titleHasFocus = hasFocus;
|
||||||
|
}
|
||||||
|
});
|
||||||
value.addTextChangedListener(new SimpleTextWatcher(e->item.value=e.toString()));
|
value.addTextChangedListener(new SimpleTextWatcher(e->item.value=e.toString()));
|
||||||
|
value.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
|
valueHasFocus = hasFocus;
|
||||||
|
}
|
||||||
|
});
|
||||||
findViewById(R.id.remove_row_btn).setOnClickListener(this::onRemoveRowClick);
|
findViewById(R.id.remove_row_btn).setOnClickListener(this::onRemoveRowClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1340,6 +1443,10 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onRemoveRowClick(View v){
|
private void onRemoveRowClick(View v){
|
||||||
|
if(titleHasFocus || valueHasFocus){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int pos=getAbsoluteAdapterPosition();
|
int pos=getAbsoluteAdapterPosition();
|
||||||
metadataListData.remove(pos);
|
metadataListData.remove(pos);
|
||||||
adapter.notifyItemRemoved(pos);
|
adapter.notifyItemRemoved(pos);
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class RecyclerFragment<T> extends BaseRecyclerFragment<T> {
|
||||||
|
public RecyclerFragment(int perPage) {
|
||||||
|
super(perPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecyclerFragment(int layout, int perPage) {
|
||||||
|
super(layout, perPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
if (refreshLayout != null) setRefreshLayoutColors(refreshLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setRefreshLayoutColors(SwipeRefreshLayout l) {
|
||||||
|
List<Integer> colors = new ArrayList<>(Arrays.asList(
|
||||||
|
R.color.primary_600,
|
||||||
|
R.color.red_primary_600,
|
||||||
|
R.color.green_primary_600,
|
||||||
|
R.color.blue_primary_600,
|
||||||
|
R.color.purple_600
|
||||||
|
));
|
||||||
|
int primary = UiUtils.getThemeColorRes(l.getContext(), R.attr.colorPrimary600);
|
||||||
|
if (!colors.contains(primary)) colors.add(0, primary);
|
||||||
|
int offset = colors.indexOf(primary);
|
||||||
|
int[] sorted = new int[colors.size()];
|
||||||
|
for (int i = 0; i < colors.size(); i++) {
|
||||||
|
sorted[i] = colors.get((i + offset) % colors.size());
|
||||||
|
}
|
||||||
|
l.setColorSchemeResources(sorted);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public interface ScrollableToTop{
|
public interface ScrollableToTop{
|
||||||
|
boolean isScrolledToTop();
|
||||||
|
|
||||||
void scrollToTop();
|
void scrollToTop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import android.widget.Toast;
|
|||||||
import com.squareup.otto.Subscribe;
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
import org.joinmastodon.android.BuildConfig;
|
import org.joinmastodon.android.BuildConfig;
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences.ColorPreference;
|
import org.joinmastodon.android.GlobalUserPreferences.ColorPreference;
|
||||||
@@ -81,7 +82,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
private ArrayList<Item> items=new ArrayList<>();
|
private ArrayList<Item> items=new ArrayList<>();
|
||||||
private ThemeItem themeItem;
|
private ThemeItem themeItem;
|
||||||
private NotificationPolicyItem notificationPolicyItem;
|
private NotificationPolicyItem notificationPolicyItem;
|
||||||
private SwitchItem showNewPostsButtonItem, glitchModeItem;
|
private SwitchItem showNewPostsButtonItem, glitchModeItem, compactReblogReplyLineItem;
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private boolean needUpdateNotificationSettings;
|
private boolean needUpdateNotificationSettings;
|
||||||
private boolean needAppRestart;
|
private boolean needAppRestart;
|
||||||
@@ -103,6 +104,8 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
|
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
|
||||||
String instanceName = UiUtils.getInstanceName(accountID);
|
String instanceName = UiUtils.getInstanceName(accountID);
|
||||||
|
|
||||||
|
DomainManager.getInstance().setCurrentDomain(session.domain + "/settings");
|
||||||
|
|
||||||
if(GithubSelfUpdater.needSelfUpdating()){
|
if(GithubSelfUpdater.needSelfUpdating()){
|
||||||
GithubSelfUpdater updater=GithubSelfUpdater.getInstance();
|
GithubSelfUpdater updater=GithubSelfUpdater.getInstance();
|
||||||
GithubSelfUpdater.UpdateState state=updater.getState();
|
GithubSelfUpdater.UpdateState state=updater.getState();
|
||||||
@@ -112,23 +115,8 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.settings_theme));
|
items.add(new HeaderItem(R.string.settings_theme));
|
||||||
|
|
||||||
items.add(themeItem=new ThemeItem());
|
items.add(themeItem=new ThemeItem());
|
||||||
items.add(new SwitchItem(R.string.theme_true_black, R.drawable.ic_fluent_dark_theme_24_regular, GlobalUserPreferences.trueBlackTheme, this::onTrueBlackThemeChanged));
|
|
||||||
items.add(new SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i->{
|
|
||||||
GlobalUserPreferences.disableMarquee=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i->{
|
|
||||||
GlobalUserPreferences.uniformNotificationIcon=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i->{
|
|
||||||
GlobalUserPreferences.reduceMotion=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
items.add(new ButtonItem(R.string.sk_settings_color_palette, R.drawable.ic_fluent_color_24_regular, b->{
|
items.add(new ButtonItem(R.string.sk_settings_color_palette, R.drawable.ic_fluent_color_24_regular, b->{
|
||||||
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
||||||
popupMenu.inflate(R.menu.color_palettes);
|
popupMenu.inflate(R.menu.color_palettes);
|
||||||
@@ -148,15 +136,71 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
case NORD -> R.string.mo_color_palette_nord;
|
case NORD -> R.string.mo_color_palette_nord;
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.theme_true_black, R.drawable.ic_fluent_dark_theme_24_regular, GlobalUserPreferences.trueBlackTheme, this::onTrueBlackThemeChanged));
|
||||||
|
items.add(new SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i->{
|
||||||
|
GlobalUserPreferences.disableMarquee=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i->{
|
||||||
|
GlobalUserPreferences.uniformNotificationIcon=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i->{
|
||||||
|
GlobalUserPreferences.reduceMotion=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
items.add(new HeaderItem(R.string.settings_behavior));
|
||||||
|
items.add(new SwitchItem(R.string.settings_gif, R.drawable.ic_fluent_gif_24_regular, GlobalUserPreferences.playGifs, i->{
|
||||||
|
GlobalUserPreferences.playGifs=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.settings_custom_tabs, R.drawable.ic_fluent_link_24_regular, GlobalUserPreferences.useCustomTabs, i->{
|
||||||
|
GlobalUserPreferences.useCustomTabs=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_show_interaction_counts, R.drawable.ic_fluent_number_row_24_regular, GlobalUserPreferences.showInteractionCounts, i->{
|
||||||
|
GlobalUserPreferences.showInteractionCounts=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_always_reveal_content_warnings, R.drawable.ic_fluent_chat_warning_24_regular, GlobalUserPreferences.alwaysExpandContentWarnings, i->{
|
||||||
|
GlobalUserPreferences.alwaysExpandContentWarnings=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
|
||||||
|
// items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged));
|
||||||
|
items.add(new SwitchItem(R.string.mo_hide_compose_button_while_scrolling_setting, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.enableFabAutoHide, i->{
|
||||||
|
GlobalUserPreferences.enableFabAutoHide =i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_tabs_disable_swipe, R.drawable.ic_fluent_swipe_right_24_regular, GlobalUserPreferences.disableSwipe, i->{
|
||||||
|
GlobalUserPreferences.disableSwipe=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.mo_disable_double_tap_to_swipe_between_tabs, R.drawable.ic_fluent_double_tap_swipe_right_24_regular, GlobalUserPreferences.disableDoubleTapToSwipe, i->{
|
||||||
|
GlobalUserPreferences.disableDoubleTapToSwipe=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_confirm_before_reblog, R.drawable.ic_fluent_checkmark_circle_24_regular, GlobalUserPreferences.confirmBeforeReblog, i->{
|
||||||
|
GlobalUserPreferences.confirmBeforeReblog=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.mo_swap_bookmark_with_reblog, R.drawable.ic_boost, GlobalUserPreferences.swapBookmarkWithBoostAction, i -> {
|
||||||
|
GlobalUserPreferences.swapBookmarkWithBoostAction=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
items.add(new HeaderItem(R.string.mo_composer_behavior));
|
||||||
items.add(new ButtonItem(R.string.sk_settings_publish_button_text, R.drawable.ic_fluent_send_24_regular, b-> {
|
items.add(new ButtonItem(R.string.sk_settings_publish_button_text, R.drawable.ic_fluent_send_24_regular, b-> {
|
||||||
updatePublishText(b);
|
updatePublishText(b);
|
||||||
if (GlobalUserPreferences.relocatePublishButton) {
|
|
||||||
b.setOnClickListener(l -> {
|
|
||||||
Toast.makeText(getActivity(), R.string.mo_disable_relocate_publish_button_to_enable_customization,
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
b.setOnClickListener(l -> {
|
b.setOnClickListener(l -> {
|
||||||
|
if(!GlobalUserPreferences.relocatePublishButton) {
|
||||||
FrameLayout inputWrap = new FrameLayout(getContext());
|
FrameLayout inputWrap = new FrameLayout(getContext());
|
||||||
EditText input = new EditText(getContext());
|
EditText input = new EditText(getContext());
|
||||||
input.setHint(R.string.publish);
|
input.setHint(R.string.publish);
|
||||||
@@ -179,50 +223,26 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
.setNegativeButton(R.string.cancel, (d, which) -> {
|
.setNegativeButton(R.string.cancel, (d, which) -> {
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
});}
|
|
||||||
}));
|
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.settings_behavior));
|
} else {
|
||||||
items.add(new SwitchItem(R.string.settings_gif, R.drawable.ic_fluent_gif_24_regular, GlobalUserPreferences.playGifs, i->{
|
Toast.makeText(getActivity(), R.string.mo_disable_relocate_publish_button_to_enable_customization,
|
||||||
GlobalUserPreferences.playGifs=i.checked;
|
Toast.LENGTH_LONG).show();
|
||||||
GlobalUserPreferences.save();
|
}
|
||||||
}));
|
});
|
||||||
items.add(new SwitchItem(R.string.settings_custom_tabs, R.drawable.ic_fluent_link_24_regular, GlobalUserPreferences.useCustomTabs, i->{
|
|
||||||
GlobalUserPreferences.useCustomTabs=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_show_interaction_counts, R.drawable.ic_fluent_number_row_24_regular, GlobalUserPreferences.showInteractionCounts, i->{
|
|
||||||
GlobalUserPreferences.showInteractionCounts=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_always_reveal_content_warnings, R.drawable.ic_fluent_chat_warning_24_regular, GlobalUserPreferences.alwaysExpandContentWarnings, i->{
|
|
||||||
GlobalUserPreferences.alwaysExpandContentWarnings=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_tabs_disable_swipe, R.drawable.ic_fluent_swipe_right_24_regular, GlobalUserPreferences.disableSwipe, i->{
|
|
||||||
GlobalUserPreferences.disableSwipe=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
// items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged));
|
|
||||||
items.add(new SwitchItem(R.string.mo_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{
|
|
||||||
GlobalUserPreferences.disableDividers=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.mo_hide_compose_button_while_scrolling_setting, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.enableFabAutoHide, i->{
|
|
||||||
GlobalUserPreferences.enableFabAutoHide =i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.mo_relocate_publish_button, R.drawable.ic_fluent_arrow_autofit_down_24_regular, GlobalUserPreferences.relocatePublishButton, i->{
|
items.add(new SwitchItem(R.string.mo_relocate_publish_button, R.drawable.ic_fluent_arrow_autofit_down_24_regular, GlobalUserPreferences.relocatePublishButton, i->{
|
||||||
GlobalUserPreferences.relocatePublishButton=i.checked;
|
GlobalUserPreferences.relocatePublishButton=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
|
items.add(new SwitchItem(R.string.mo_change_default_reply_visibility_to_unlisted, R.drawable.ic_fluent_lock_open_24_regular, GlobalUserPreferences.defaultToUnlistedReplies, i->{
|
||||||
GlobalUserPreferences.keepOnlyLatestNotification=i.checked;
|
GlobalUserPreferences.defaultToUnlistedReplies=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.mo_disable_reminder_to_add_alt_text, R.drawable.ic_fluent_image_alt_text_24_regular, GlobalUserPreferences.disableAltTextReminder, i->{
|
||||||
|
GlobalUserPreferences.disableAltTextReminder=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_prefix_reply_cw_with_re, R.drawable.ic_fluent_arrow_reply_24_regular, GlobalUserPreferences.prefixRepliesWithRe, i->{
|
items.add(new SwitchItem(R.string.sk_settings_prefix_reply_cw_with_re, R.drawable.ic_fluent_arrow_reply_24_regular, GlobalUserPreferences.prefixRepliesWithRe, i->{
|
||||||
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
|
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
@@ -233,6 +253,22 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.showReplies=i.checked;
|
GlobalUserPreferences.showReplies=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
|
if (instance.pleroma != null) {
|
||||||
|
items.add(new ButtonItem(R.string.sk_settings_reply_visibility, R.drawable.ic_fluent_chat_24_regular, b->{
|
||||||
|
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
||||||
|
popupMenu.inflate(R.menu.reply_visibility);
|
||||||
|
popupMenu.setOnMenuItemClickListener(item -> this.onReplyVisibilityChanged(item, b));
|
||||||
|
b.setOnTouchListener(popupMenu.getDragToOpenListener());
|
||||||
|
b.setOnClickListener(v->popupMenu.show());
|
||||||
|
b.setText(GlobalUserPreferences.replyVisibility == null ?
|
||||||
|
R.string.sk_settings_reply_visibility_all :
|
||||||
|
switch(GlobalUserPreferences.replyVisibility){
|
||||||
|
case "following" -> R.string.sk_settings_reply_visibility_following;
|
||||||
|
case "self" -> R.string.sk_settings_reply_visibility_self;
|
||||||
|
default -> R.string.sk_settings_reply_visibility_all;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
items.add(new SwitchItem(R.string.sk_settings_show_boosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, GlobalUserPreferences.showBoosts, i->{
|
items.add(new SwitchItem(R.string.sk_settings_show_boosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, GlobalUserPreferences.showBoosts, i->{
|
||||||
GlobalUserPreferences.showBoosts=i.checked;
|
GlobalUserPreferences.showBoosts=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
@@ -260,23 +296,43 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
items.add(new SwitchItem(R.string.sk_settings_show_no_alt_indicator, R.drawable.ic_fluent_important_24_regular, GlobalUserPreferences.showNoAltIndicator, i->{
|
items.add(new SwitchItem(R.string.sk_settings_show_no_alt_indicator, R.drawable.ic_fluent_important_24_regular, GlobalUserPreferences.showNoAltIndicator, i->{
|
||||||
GlobalUserPreferences.showNoAltIndicator=i.checked;
|
GlobalUserPreferences.showNoAltIndicator=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_collapse_long_posts, R.drawable.ic_fluent_chevron_down_24_filled, GlobalUserPreferences.collapseLongPosts, i->{
|
items.add(new SwitchItem(R.string.sk_settings_collapse_long_posts, R.drawable.ic_fluent_chevron_down_24_regular, GlobalUserPreferences.collapseLongPosts, i->{
|
||||||
GlobalUserPreferences.collapseLongPosts=i.checked;
|
GlobalUserPreferences.collapseLongPosts=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_spectator_mode, R.drawable.ic_fluent_eye_24_regular, GlobalUserPreferences.spectatorMode, i->{
|
items.add(new SwitchItem(R.string.sk_settings_hide_interaction, R.drawable.ic_fluent_eye_24_regular, GlobalUserPreferences.spectatorMode, i->{
|
||||||
GlobalUserPreferences.spectatorMode=i.checked;
|
GlobalUserPreferences.spectatorMode=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
needAppRestart=true;
|
needAppRestart=true;
|
||||||
}));
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_hide_fab, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.autoHideFab, i->{
|
||||||
|
GlobalUserPreferences.autoHideFab=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_reply_line_above_avatar, R.drawable.ic_fluent_arrow_reply_24_regular, GlobalUserPreferences.replyLineAboveHeader, i->{
|
||||||
|
GlobalUserPreferences.replyLineAboveHeader=i.checked;
|
||||||
|
GlobalUserPreferences.compactReblogReplyLine=i.checked;
|
||||||
|
compactReblogReplyLineItem.enabled=i.checked;
|
||||||
|
compactReblogReplyLineItem.checked= GlobalUserPreferences.replyLineAboveHeader;
|
||||||
|
if (list.findViewHolderForAdapterPosition(items.indexOf(compactReblogReplyLineItem)) instanceof SwitchViewHolder svh) svh.rebind();
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(compactReblogReplyLineItem=new SwitchItem(R.string.sk_compact_reblog_reply_line, R.drawable.ic_fluent_re_order_24_regular, GlobalUserPreferences.compactReblogReplyLine, i->{
|
||||||
|
GlobalUserPreferences.compactReblogReplyLine=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
compactReblogReplyLineItem.enabled=GlobalUserPreferences.replyLineAboveHeader;
|
||||||
// items.add(new SwitchItem(R.string.sk_settings_translate_only_opened, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
|
// items.add(new SwitchItem(R.string.sk_settings_translate_only_opened, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
|
||||||
// GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
|
// GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
|
||||||
// GlobalUserPreferences.save();
|
// GlobalUserPreferences.save();
|
||||||
// needAppRestart=true;
|
// needAppRestart=true;
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.settings_notifications));
|
items.add(new HeaderItem(R.string.settings_notifications));
|
||||||
items.add(notificationPolicyItem=new NotificationPolicyItem());
|
items.add(notificationPolicyItem=new NotificationPolicyItem());
|
||||||
PushSubscription pushSubscription=getPushSubscription();
|
PushSubscription pushSubscription=getPushSubscription();
|
||||||
@@ -290,6 +346,24 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
items.add(new SwitchItem(R.string.sk_notify_update, R.drawable.ic_fluent_history_24_regular, pushSubscription.alerts.update, i->onNotificationsChanged(PushNotification.Type.UPDATE, i.checked), switchEnabled));
|
items.add(new SwitchItem(R.string.sk_notify_update, R.drawable.ic_fluent_history_24_regular, pushSubscription.alerts.update, i->onNotificationsChanged(PushNotification.Type.UPDATE, i.checked), switchEnabled));
|
||||||
items.add(new SwitchItem(R.string.sk_notify_poll_results, R.drawable.ic_fluent_poll_24_regular, pushSubscription.alerts.poll, i->onNotificationsChanged(PushNotification.Type.POLL, i.checked), switchEnabled));
|
items.add(new SwitchItem(R.string.sk_notify_poll_results, R.drawable.ic_fluent_poll_24_regular, pushSubscription.alerts.poll, i->onNotificationsChanged(PushNotification.Type.POLL, i.checked), switchEnabled));
|
||||||
|
|
||||||
|
items.add(new HeaderItem(R.string.mo_miscellaneous_settings));
|
||||||
|
items.add(new SwitchItem(R.string.mo_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{
|
||||||
|
GlobalUserPreferences.disableDividers=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_enable_delete_notifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, GlobalUserPreferences.enableDeleteNotifications, i->{
|
||||||
|
GlobalUserPreferences.enableDeleteNotifications=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
|
||||||
|
GlobalUserPreferences.keepOnlyLatestNotification=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.settings_account));
|
items.add(new HeaderItem(R.string.settings_account));
|
||||||
items.add(new TextItem(R.string.sk_settings_profile, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/profile"), R.drawable.ic_fluent_open_24_regular));
|
items.add(new TextItem(R.string.sk_settings_profile, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/profile"), R.drawable.ic_fluent_open_24_regular));
|
||||||
items.add(new TextItem(R.string.sk_settings_posting, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/preferences/other"), R.drawable.ic_fluent_open_24_regular));
|
items.add(new TextItem(R.string.sk_settings_posting, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/preferences/other"), R.drawable.ic_fluent_open_24_regular));
|
||||||
@@ -343,6 +417,13 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
|
|
||||||
items.add(new HeaderItem(R.string.sk_settings_about));
|
items.add(new HeaderItem(R.string.sk_settings_about));
|
||||||
|
|
||||||
|
// if(BuildConfig.BUILD_TYPE.equals("nightly")){
|
||||||
|
// items.add(new TextItem(R.string.mo_download_latest_nightly_release, ()->UiUtils.launchWebBrowser(getActivity(), "https://nightly.link/LucasGGamerM/moshidon/workflows/nightly-builds/master/moshidon-nightly.apk.zip"), R.drawable.ic_fluent_open_24_regular));
|
||||||
|
// }
|
||||||
|
|
||||||
|
items.add(new TextItem(R.string.mo_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon"), R.drawable.ic_fluent_open_24_regular));
|
||||||
|
items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sponsors/LucasGGamerM"), R.drawable.ic_fluent_heart_24_regular));
|
||||||
|
|
||||||
if (GithubSelfUpdater.needSelfUpdating()) {
|
if (GithubSelfUpdater.needSelfUpdating()) {
|
||||||
checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
|
checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
|
||||||
items.add(checkForUpdateItem);
|
items.add(checkForUpdateItem);
|
||||||
@@ -352,9 +433,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.add(new TextItem(R.string.mo_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon"), R.drawable.ic_fluent_open_24_regular));
|
|
||||||
items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sponsors/LucasGGamerM"), R.drawable.ic_fluent_heart_24_regular));
|
|
||||||
|
|
||||||
LruCache<?, ?> cache = imageCache == null ? null : imageCache.getLruCache();
|
LruCache<?, ?> cache = imageCache == null ? null : imageCache.getLruCache();
|
||||||
clearImageCacheItem = new TextItem(R.string.settings_clear_cache, UiUtils.formatFileSize(getContext(), cache != null ? cache.size() : 0, true), this::clearImageCache, 0);
|
clearImageCacheItem = new TextItem(R.string.settings_clear_cache, UiUtils.formatFileSize(getContext(), cache != null ? cache.size() : 0, true), this::clearImageCache, 0);
|
||||||
items.add(clearImageCacheItem);
|
items.add(clearImageCacheItem);
|
||||||
@@ -382,7 +460,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
|
items.add(new FooterItem(getString(R.string.mo_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePublishText(Button btn) {
|
private void updatePublishText(Button btn) {
|
||||||
@@ -497,6 +575,25 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean onReplyVisibilityChanged(MenuItem item, Button btn){
|
||||||
|
String pref = null;
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
if (id == R.id.reply_visibility_following) pref = "following";
|
||||||
|
else if (id == R.id.reply_visibility_self) pref = "self";
|
||||||
|
|
||||||
|
GlobalUserPreferences.replyVisibility=pref;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
btn.setText(GlobalUserPreferences.replyVisibility == null ?
|
||||||
|
R.string.sk_settings_reply_visibility_all :
|
||||||
|
switch(GlobalUserPreferences.replyVisibility){
|
||||||
|
case "following" -> R.string.sk_settings_reply_visibility_following;
|
||||||
|
case "self" -> R.string.sk_settings_reply_visibility_self;
|
||||||
|
default -> R.string.sk_settings_reply_visibility_all;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void restartActivityToApplyNewTheme(){
|
private void restartActivityToApplyNewTheme(){
|
||||||
// Calling activity.recreate() causes a black screen for like half a second.
|
// Calling activity.recreate() causes a black screen for like half a second.
|
||||||
// So, let's take a screenshot and overlay it on top to create the illusion of a smoother transition.
|
// So, let's take a screenshot and overlay it on top to create the illusion of a smoother transition.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.squareup.otto.Subscribe;
|
|||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.MainActivity;
|
||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||||
@@ -18,6 +19,7 @@ import org.joinmastodon.android.model.Status;
|
|||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -28,7 +30,7 @@ import java.util.stream.Stream;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
|
|
||||||
public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
public abstract class StatusListFragment extends BaseStatusListFragment<Status> implements DomainDisplay{
|
||||||
protected EventListener eventListener=new EventListener();
|
protected EventListener eventListener=new EventListener();
|
||||||
|
|
||||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||||
@@ -41,6 +43,8 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
protected void addAccountToKnown(Status s){
|
protected void addAccountToKnown(Status s){
|
||||||
if(!knownAccounts.containsKey(s.account.id))
|
if(!knownAccounts.containsKey(s.account.id))
|
||||||
knownAccounts.put(s.account.id, s.account);
|
knownAccounts.put(s.account.id, s.account);
|
||||||
|
if(s.reblog!=null && !knownAccounts.containsKey(s.reblog.account.id))
|
||||||
|
knownAccounts.put(s.reblog.account.id, s.reblog.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -60,6 +64,18 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
Status status=getContentStatusByID(id);
|
Status status=getContentStatusByID(id);
|
||||||
if(status==null)
|
if(status==null)
|
||||||
return;
|
return;
|
||||||
|
if(status.reloadWhenClicked){
|
||||||
|
UiUtils.lookupStatus(getContext(), status, accountID, null, status1 -> {
|
||||||
|
status1.filterRevealed = true;
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
args.putString("account", accountID);
|
||||||
|
args.putParcelable("status", Parcels.wrap(status1));
|
||||||
|
if(status1.inReplyToAccountId!=null && knownAccounts.containsKey(status1.inReplyToAccountId))
|
||||||
|
args.putParcelable("inReplyToAccount", Parcels.wrap(knownAccounts.get(status1.inReplyToAccountId)));
|
||||||
|
Nav.go(getActivity(), ThreadFragment.class, args);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
status.filterRevealed = true;
|
status.filterRevealed = true;
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
@@ -149,7 +165,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
|
|
||||||
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
|
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
|
||||||
List<Status> toRemove=Stream.concat(data.stream(), preloadedData.stream())
|
List<Status> toRemove=Stream.concat(data.stream(), preloadedData.stream())
|
||||||
.filter(s->s.account.id.equals(ev.postsByAccountID) || (s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID)))
|
.filter(s->s.account.id.equals(ev.postsByAccountID) || (!ev.isUnfollow && s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID)))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
for(Status s:toRemove){
|
for(Status s:toRemove){
|
||||||
removeStatus(s);
|
removeStatus(s);
|
||||||
|
|||||||
@@ -3,11 +3,15 @@ package org.joinmastodon.android.fragments;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.StatusContext;
|
import org.joinmastodon.android.model.StatusContext;
|
||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
@@ -19,15 +23,21 @@ import org.joinmastodon.android.ui.utils.UiUtils;
|
|||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
public class ThreadFragment extends StatusListFragment{
|
public class ThreadFragment extends StatusListFragment implements DomainDisplay{
|
||||||
protected Status mainStatus;
|
protected Status mainStatus;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return mainStatus.url;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -38,6 +48,8 @@ public class ThreadFragment extends StatusListFragment{
|
|||||||
data.add(mainStatus);
|
data.add(mainStatus);
|
||||||
onAppendItems(Collections.singletonList(mainStatus));
|
onAppendItems(Collections.singletonList(mainStatus));
|
||||||
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis));
|
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis));
|
||||||
|
|
||||||
|
DomainManager.getInstance().setCurrentDomain(getDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,6 +80,30 @@ public class ThreadFragment extends StatusListFragment{
|
|||||||
data.add(mainStatus);
|
data.add(mainStatus);
|
||||||
onAppendItems(Collections.singletonList(mainStatus));
|
onAppendItems(Collections.singletonList(mainStatus));
|
||||||
}
|
}
|
||||||
|
AccountSession account=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
|
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(account.domain);
|
||||||
|
if(instance.pleroma != null){
|
||||||
|
List<String> threadIds=new ArrayList<>();
|
||||||
|
threadIds.add(mainStatus.id);
|
||||||
|
for(Status s:result.descendants){
|
||||||
|
if(threadIds.contains(s.inReplyToId)){
|
||||||
|
threadIds.add(s.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
threadIds.add(mainStatus.inReplyToId);
|
||||||
|
for(int i=result.ancestors.size()-1; i >= 0; i--){
|
||||||
|
Status s=result.ancestors.get(i);
|
||||||
|
if(s.inReplyToId != null && threadIds.contains(s.id)){
|
||||||
|
threadIds.add(s.inReplyToId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.ancestors=result.ancestors.stream().filter(s -> threadIds.contains(s.id)).collect(Collectors.toList());
|
||||||
|
result.descendants=getDescendantsOrdered(mainStatus.id,
|
||||||
|
result.descendants.stream()
|
||||||
|
.filter(s -> threadIds.contains(s.id))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
result.descendants=filterStatuses(result.descendants);
|
result.descendants=filterStatuses(result.descendants);
|
||||||
result.ancestors=filterStatuses(result.ancestors);
|
result.ancestors=filterStatuses(result.ancestors);
|
||||||
if(footerProgress!=null)
|
if(footerProgress!=null)
|
||||||
@@ -90,6 +126,24 @@ public class ThreadFragment extends StatusListFragment{
|
|||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Status> getDescendantsOrdered(String id, List<Status> statuses){
|
||||||
|
List<Status> out=new ArrayList<>();
|
||||||
|
for(Status s:getDirectDescendants(id, statuses)){
|
||||||
|
out.add(s);
|
||||||
|
getDirectDescendants(s.id, statuses).forEach(d ->{
|
||||||
|
out.add(d);
|
||||||
|
out.addAll(getDescendantsOrdered(d.id, statuses));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Status> getDirectDescendants(String id, List<Status> statuses){
|
||||||
|
return statuses.stream()
|
||||||
|
.filter(s -> s.inReplyToId.equals(id))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
private List<Status> filterStatuses(List<Status> statuses){
|
private List<Status> filterStatuses(List<Status> statuses){
|
||||||
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,Filter.FilterContext.THREAD);
|
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,Filter.FilterContext.THREAD);
|
||||||
return statuses.stream()
|
return statuses.stream()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
|||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
@@ -48,7 +49,6 @@ import me.grishka.appkit.Nav;
|
|||||||
import me.grishka.appkit.api.APIRequest;
|
import me.grishka.appkit.api.APIRequest;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
@@ -57,7 +57,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseAccountListFragment.AccountItem>{
|
public abstract class BaseAccountListFragment extends RecyclerFragment<BaseAccountListFragment.AccountItem> {
|
||||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||||
protected String accountID;
|
protected String accountID;
|
||||||
protected ArrayList<APIRequest<?>> relationshipsRequests=new ArrayList<>();
|
protected ArrayList<APIRequest<?>> relationshipsRequests=new ArrayList<>();
|
||||||
@@ -74,6 +74,8 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDataLoaded(List<AccountItem> d, boolean more){
|
protected void onDataLoaded(List<AccountItem> d, boolean more){
|
||||||
|
if (getActivity() == null)
|
||||||
|
return;
|
||||||
if(refreshing){
|
if(refreshing){
|
||||||
relationships.clear();
|
relationships.clear();
|
||||||
}
|
}
|
||||||
@@ -267,6 +269,15 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(){
|
public void onClick(){
|
||||||
|
if(item.account.reloadWhenClicked){
|
||||||
|
UiUtils.lookupAccount(getContext(), item.account, accountID, null, account -> {
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
args.putString("account", accountID);
|
||||||
|
args.putParcelable("profileAccount", Parcels.wrap(account));
|
||||||
|
Nav.go(getActivity(), ProfileFragment.class, args);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(item.account));
|
args.putParcelable("profileAccount", Parcels.wrap(item.account));
|
||||||
@@ -295,7 +306,6 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
|||||||
|
|
||||||
menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername()));
|
menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername()));
|
||||||
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getShortUsername()));
|
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getShortUsername()));
|
||||||
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.sk_lists_with_user, account.getShortUsername())).setVisible(relationship.following);
|
|
||||||
menu.findItem(R.id.soft_block).setVisible(relationship.followedBy && !relationship.following);
|
menu.findItem(R.id.soft_block).setVisible(relationship.followedBy && !relationship.following);
|
||||||
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
||||||
MenuItem manageUserLists=menu.findItem(R.id.manage_user_lists);
|
MenuItem manageUserLists=menu.findItem(R.id.manage_user_lists);
|
||||||
@@ -309,7 +319,7 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
|||||||
manageUserLists.setVisible(true);
|
manageUserLists.setVisible(true);
|
||||||
}else{
|
}else{
|
||||||
hideBoosts.setVisible(false);
|
hideBoosts.setVisible(false);
|
||||||
manageUserLists.setVisible(true);
|
manageUserLists.setVisible(false);
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.block_domain).setVisible(false);
|
menu.findItem(R.id.block_domain).setVisible(false);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public class FollowerListFragment extends AccountRelatedAccountListFragment{
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
targetAccount = account;
|
||||||
setSubtitle(getResources().getQuantityString(R.plurals.x_followers, (int)(account.followersCount%1000), account.followersCount));
|
setSubtitle(getResources().getQuantityString(R.plurals.x_followers, (int)(account.followersCount%1000), account.followersCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,4 +20,9 @@ public class FollowerListFragment extends AccountRelatedAccountListFragment{
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetAccountFollowers(account.id, maxID, count);
|
return new GetAccountFollowers(account.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HeaderPaginationRequest<Account> onCreateRemoteRequest(String id, String maxID, int count){
|
||||||
|
return new GetAccountFollowers(id, maxID, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public class FollowingListFragment extends AccountRelatedAccountListFragment{
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
targetAccount = account;
|
||||||
setSubtitle(getResources().getQuantityString(R.plurals.x_following, (int)(account.followingCount%1000), account.followingCount));
|
setSubtitle(getResources().getQuantityString(R.plurals.x_following, (int)(account.followingCount%1000), account.followingCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,4 +20,9 @@ public class FollowingListFragment extends AccountRelatedAccountListFragment{
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetAccountFollowing(account.id, maxID, count);
|
return new GetAccountFollowing(account.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HeaderPaginationRequest<Account> onCreateRemoteRequest(String id, String maxID, int count){
|
||||||
|
return new GetAccountFollowing(id, maxID, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,52 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
|
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.HeaderPaginationList;
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.grishka.appkit.api.Callback;
|
||||||
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
public abstract class PaginatedAccountListFragment extends BaseAccountListFragment{
|
public abstract class PaginatedAccountListFragment extends BaseAccountListFragment{
|
||||||
private String nextMaxID;
|
private String nextMaxID;
|
||||||
|
|
||||||
|
protected Account targetAccount;
|
||||||
|
|
||||||
public abstract HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count);
|
public abstract HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count);
|
||||||
|
|
||||||
|
public abstract HeaderPaginationRequest<Account> onCreateRemoteRequest(String id, String maxID, int count);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
|
if (shouldLoadRemote()) {
|
||||||
|
UiUtils.lookupRemoteAccount(getContext(), targetAccount, accountID, null, account -> {
|
||||||
|
if(account != null){
|
||||||
|
loadRemoteFollower(offset, count, account);
|
||||||
|
} else {
|
||||||
|
loadFollower(offset, count);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
loadFollower(offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldLoadRemote() {
|
||||||
|
if (!GlobalUserPreferences.loadRemoteAccountFollowers && (this instanceof FollowingListFragment || this instanceof FollowerListFragment)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return targetAccount != null && targetAccount.getDomain() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadFollower(int offset, int count) {
|
||||||
currentRequest=onCreateRequest(offset==0 ? null : nextMaxID, count)
|
currentRequest=onCreateRequest(offset==0 ? null : nextMaxID, count)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
@@ -23,13 +55,42 @@ public abstract class PaginatedAccountListFragment extends BaseAccountListFragme
|
|||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
nextMaxID=null;
|
nextMaxID=null;
|
||||||
if (getActivity() == null) return;
|
|
||||||
onDataLoaded(result.stream().map(AccountItem::new).collect(Collectors.toList()), nextMaxID!=null);
|
onDataLoaded(result.stream().map(AccountItem::new).collect(Collectors.toList()), nextMaxID!=null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadRemoteFollower(int offset, int count, Account account) {
|
||||||
|
String ownDomain = AccountSessionManager.getInstance().getLastActiveAccount().domain;
|
||||||
|
currentRequest=onCreateRemoteRequest(account.id, offset==0 ? null : nextMaxID, count)
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(HeaderPaginationList<Account> result){
|
||||||
|
if(result.nextPageUri!=null)
|
||||||
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
|
else
|
||||||
|
nextMaxID=null;
|
||||||
|
result.stream().forEach(remoteAccount -> {
|
||||||
|
remoteAccount.reloadWhenClicked = true;
|
||||||
|
if (remoteAccount.getDomain() == null) {
|
||||||
|
remoteAccount.acct += "@" + Uri.parse(remoteAccount.url).getHost();
|
||||||
|
} else if (remoteAccount.getDomain().equals(ownDomain)) {
|
||||||
|
remoteAccount.acct = remoteAccount.username;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onDataLoaded(result.stream().map(AccountItem::new).collect(Collectors.toList()), nextMaxID!=null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(getContext());
|
||||||
|
loadFollower(offset, count);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execNoAuth(targetAccount.getDomain());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume(){
|
public void onResume(){
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|||||||
@@ -18,4 +18,9 @@ public class StatusFavoritesListFragment extends StatusRelatedAccountListFragmen
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetStatusFavorites(status.id, maxID, count);
|
return new GetStatusFavorites(status.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HeaderPaginationRequest<Account> onCreateRemoteRequest(String id, String maxID, int count) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,4 +18,9 @@ public class StatusReblogsListFragment extends StatusRelatedAccountListFragment{
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetStatusReblogs(status.id, maxID, count);
|
return new GetStatusReblogs(status.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HeaderPaginationRequest<Account> onCreateRemoteRequest(String id, String maxID, int count) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,10 @@ import android.widget.TextView;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
||||||
|
import org.joinmastodon.android.fragments.DomainDisplay;
|
||||||
import org.joinmastodon.android.fragments.IsOnTop;
|
import org.joinmastodon.android.fragments.IsOnTop;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.FollowSuggestion;
|
import org.joinmastodon.android.model.FollowSuggestion;
|
||||||
@@ -49,7 +51,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop {
|
public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop, DomainDisplay {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||||
private GetAccountRelationships relationshipsRequest;
|
private GetAccountRelationships relationshipsRequest;
|
||||||
@@ -58,6 +60,11 @@ public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccou
|
|||||||
super(20);
|
super(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return DomainDisplay.super.getDomain() + "/explore/suggestions";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -140,6 +147,11 @@ public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccou
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnTop() {
|
public boolean isOnTop() {
|
||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.BuildConfig;
|
import org.joinmastodon.android.BuildConfig;
|
||||||
|
import org.joinmastodon.android.DomainManager;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.fragments.DomainDisplay;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
||||||
import org.joinmastodon.android.ui.SimpleViewHolder;
|
import org.joinmastodon.android.ui.SimpleViewHolder;
|
||||||
@@ -38,7 +40,7 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|||||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener{
|
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener, DomainDisplay {
|
||||||
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ViewPager2 pager;
|
private ViewPager2 pager;
|
||||||
@@ -64,6 +66,17 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
|
|
||||||
// private final boolean noFederated = !GlobalUserPreferences.showFederatedTimeline;
|
// private final boolean noFederated = !GlobalUserPreferences.showFederatedTimeline;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
if (searchActive) {
|
||||||
|
return searchFragment.getDomain();
|
||||||
|
}
|
||||||
|
if (tabViews[tabLayout.getSelectedTabPosition()] instanceof DomainDisplay page) {
|
||||||
|
return page.getDomain();
|
||||||
|
}
|
||||||
|
return DomainDisplay.super.getDomain() + "/explore";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -127,6 +140,9 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
if(!page.loaded && !page.isDataLoading())
|
if(!page.loaded && !page.isDataLoading())
|
||||||
page.loadData();
|
page.loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_page instanceof DomainDisplay display)
|
||||||
|
DomainManager.getInstance().setCurrentDomain(display.getDomain());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,7 +224,9 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
tabLayoutMediator.attach();
|
tabLayoutMediator.attach();
|
||||||
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
|
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
|
||||||
@Override
|
@Override
|
||||||
public void onTabSelected(TabLayout.Tab tab){}
|
public void onTabSelected(TabLayout.Tab tab){
|
||||||
|
DomainManager.getInstance().setCurrentDomain(getDomain());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabUnselected(TabLayout.Tab tab){}
|
public void onTabUnselected(TabLayout.Tab tab){}
|
||||||
@@ -284,6 +302,15 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
if(!searchActive){
|
||||||
|
return ((ScrollableToTop)getFragmentForPage(pager.getCurrentItem())).isScrolledToTop();
|
||||||
|
}else{
|
||||||
|
return searchFragment.isScrolledToTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void loadData(){
|
public void loadData(){
|
||||||
if(hashtagsFragment!=null && !hashtagsFragment.loaded && !hashtagsFragment.dataLoading)
|
if(hashtagsFragment!=null && !hashtagsFragment.loaded && !hashtagsFragment.dataLoading)
|
||||||
hashtagsFragment.loadData();
|
hashtagsFragment.loadData();
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.trends.GetTrendingLinks;
|
import org.joinmastodon.android.api.requests.trends.GetTrendingLinks;
|
||||||
|
import org.joinmastodon.android.fragments.DomainDisplay;
|
||||||
import org.joinmastodon.android.fragments.IsOnTop;
|
import org.joinmastodon.android.fragments.IsOnTop;
|
||||||
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.model.Card;
|
import org.joinmastodon.android.model.Card;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||||
@@ -35,7 +37,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements ScrollableToTop, IsOnTop {
|
public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements ScrollableToTop, IsOnTop, DomainDisplay {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private List<ImageLoaderRequest> imageRequests=Collections.emptyList();
|
private List<ImageLoaderRequest> imageRequests=Collections.emptyList();
|
||||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS);
|
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS);
|
||||||
@@ -44,6 +46,11 @@ public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements
|
|||||||
super(10);
|
super(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return DomainDisplay.super.getDomain() + "/explore/links";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -83,6 +90,11 @@ public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnTop() {
|
public boolean isOnTop() {
|
||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ import me.grishka.appkit.api.SimpleCallback;
|
|||||||
public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop {
|
public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop {
|
||||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_POSTS);
|
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_POSTS);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/explore/posts";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetTrendingStatuses(offset, count)
|
currentRequest=new GetTrendingStatuses(offset, count)
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ public class FederatedTimelineFragment extends StatusListFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/public";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ public class LocalTimelineFragment extends StatusListFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/public/local";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
setLayout(R.layout.fragment_search);
|
setLayout(R.layout.fragment_search);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return super.getDomain() + "/search";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -248,7 +253,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setQuery(String q){
|
public void setQuery(String q){
|
||||||
if(Objects.equals(q, currentQuery))
|
if(Objects.equals(q, currentQuery) || q.isBlank())
|
||||||
return;
|
return;
|
||||||
if(currentRequest!=null){
|
if(currentRequest!=null){
|
||||||
currentRequest.cancel();
|
currentRequest.cancel();
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.trends.GetTrendingHashtags;
|
import org.joinmastodon.android.api.requests.trends.GetTrendingHashtags;
|
||||||
|
import org.joinmastodon.android.fragments.DomainDisplay;
|
||||||
import org.joinmastodon.android.fragments.IsOnTop;
|
import org.joinmastodon.android.fragments.IsOnTop;
|
||||||
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||||
@@ -24,7 +26,7 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop {
|
public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop, DomainDisplay {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_HASHTAGS);
|
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_HASHTAGS);
|
||||||
|
|
||||||
@@ -32,6 +34,11 @@ public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> impl
|
|||||||
super(10);
|
super(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return DomainDisplay.super.getDomain() + "/explore/tags";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -68,6 +75,11 @@ public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> impl
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrolledToTop() {
|
||||||
|
return list.getChildAt(0).getTop() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnTop() {
|
public boolean isOnTop() {
|
||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
|
|||||||
@@ -110,7 +110,10 @@ public class AccountActivationFragment extends ToolbarFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onToolbarNavigationClick(){
|
public void onToolbarNavigationClick(){
|
||||||
new AccountSwitcherSheet(getActivity()).show();
|
new AccountSwitcherSheet(getActivity(), true, true, false, accountSession -> {
|
||||||
|
getActivity().finish();
|
||||||
|
getActivity().startActivity(new Intent(getActivity(), MainActivity.class));
|
||||||
|
}).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -248,6 +251,6 @@ public class AccountActivationFragment extends ToolbarFragment{
|
|||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
// Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
// Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||||
Nav.goClearingStack(getActivity(), OnboardingProfileSetupFragment.class, args);
|
Nav.goClearingStack(getActivity(), OnboardingFollowSuggestionsFragment.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,25 +5,22 @@ import android.app.ProgressDialog;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.LocaleList;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.RadioButton;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
import org.joinmastodon.android.api.MastodonErrorResponse;
|
import org.joinmastodon.android.api.MastodonErrorResponse;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||||
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
@@ -31,6 +28,8 @@ import org.xml.sax.InputSource;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.IDN;
|
import java.net.IDN;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -46,16 +45,14 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInstance>{
|
abstract class InstanceCatalogFragment extends RecyclerFragment<CatalogInstance> {
|
||||||
protected RecyclerView.Adapter adapter;
|
protected RecyclerView.Adapter adapter;
|
||||||
protected MergeRecyclerAdapter mergeAdapter;
|
protected MergeRecyclerAdapter mergeAdapter;
|
||||||
protected CatalogInstance chosenInstance;
|
protected CatalogInstance chosenInstance;
|
||||||
@@ -112,46 +109,10 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected List<CatalogInstance> sortInstances(List<CatalogInstance> result){
|
protected List<CatalogInstance> sortInstances(List<CatalogInstance> result){
|
||||||
Map<String, List<CatalogInstance>> byLang=result.stream().collect(Collectors.groupingBy(ci->ci.language));
|
Map<Boolean, List<CatalogInstance>> byLang=result.stream().sorted(Comparator.comparingInt((CatalogInstance ci)->ci.lastWeekUsers).reversed()).collect(Collectors.groupingBy(ci->ci.approvalRequired));
|
||||||
for(List<CatalogInstance> group:byLang.values()){
|
|
||||||
Collections.sort(group, (a, b)->{
|
|
||||||
double aa=Math.abs(DUNBAR-Math.log(a.lastWeekUsers));
|
|
||||||
double bb=Math.abs(DUNBAR-Math.log(b.lastWeekUsers));
|
|
||||||
return Double.compare(aa, bb);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// get the list of user-configured system languages
|
|
||||||
List<String> userLangs;
|
|
||||||
if(Build.VERSION.SDK_INT<24){
|
|
||||||
userLangs=Collections.singletonList(getResources().getConfiguration().locale.getLanguage());
|
|
||||||
}else{
|
|
||||||
LocaleList ll=getResources().getConfiguration().getLocales();
|
|
||||||
userLangs=new ArrayList<>(ll.size());
|
|
||||||
for(int i=0;i<ll.size();i++){
|
|
||||||
userLangs.add(ll.get(i).getLanguage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add instances in preferred languages to the top of the list, in the order of preference
|
|
||||||
ArrayList<CatalogInstance> sortedList=new ArrayList<>();
|
ArrayList<CatalogInstance> sortedList=new ArrayList<>();
|
||||||
for(String lang:userLangs){
|
sortedList.addAll(byLang.getOrDefault(false, Collections.emptyList()));
|
||||||
List<CatalogInstance> langInstances=byLang.remove(lang);
|
sortedList.addAll(byLang.getOrDefault(true, Collections.emptyList()));
|
||||||
if(langInstances!=null){
|
|
||||||
sortedList.addAll(langInstances);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// sort the remaining language groups by aggregate lastWeekUsers
|
|
||||||
class InstanceGroup{
|
|
||||||
public int activeUsers;
|
|
||||||
public List<CatalogInstance> instances;
|
|
||||||
}
|
|
||||||
byLang.values().stream().map(il->{
|
|
||||||
InstanceGroup group=new InstanceGroup();
|
|
||||||
group.instances=il;
|
|
||||||
for(CatalogInstance instance:il){
|
|
||||||
group.activeUsers+=instance.lastWeekUsers;
|
|
||||||
}
|
|
||||||
return group;
|
|
||||||
}).sorted(Comparator.comparingInt((InstanceGroup g)->g.activeUsers).reversed()).forEachOrdered(ig->sortedList.addAll(ig.instances));
|
|
||||||
return sortedList;
|
return sortedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +169,20 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
|||||||
cancelLoadingInstanceInfo();
|
cancelLoadingInstanceInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try{
|
||||||
|
new URI("https://"+domain+"/api/v1/instance"); // Validate the host by trying to parse the URI
|
||||||
|
}catch(URISyntaxException x){
|
||||||
|
showInstanceInfoLoadError(domain, x);
|
||||||
|
if(fakeInstance!=null){
|
||||||
|
fakeInstance.description=getString(R.string.error);
|
||||||
|
if(filteredData.size()>0 && filteredData.get(0)==fakeInstance){
|
||||||
|
if(list.findViewHolderForAdapterPosition(1) instanceof BindableViewHolder<?> ivh){
|
||||||
|
ivh.rebind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
loadingInstanceDomain=domain;
|
loadingInstanceDomain=domain;
|
||||||
loadingInstanceRequest=new GetInstance();
|
loadingInstanceRequest=new GetInstance();
|
||||||
loadingInstanceRequest.setCallback(new Callback<>(){
|
loadingInstanceRequest.setCallback(new Callback<>(){
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
|||||||
|
|
||||||
private List<String> languages=Collections.emptyList();
|
private List<String> languages=Collections.emptyList();
|
||||||
private PopupMenu langFilterMenu, speedFilterMenu;
|
private PopupMenu langFilterMenu, speedFilterMenu;
|
||||||
private SignupSpeedFilter currentSignupSpeedFilter=SignupSpeedFilter.INSTANT;
|
private SignupSpeedFilter currentSignupSpeedFilter=SignupSpeedFilter.ANY;
|
||||||
private String currentLanguage=null;
|
private String currentLanguage=null;
|
||||||
private boolean searchQueryMode;
|
private boolean searchQueryMode;
|
||||||
private LinearLayout filtersWrap;
|
private LinearLayout filtersWrap;
|
||||||
@@ -75,7 +75,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
|||||||
private FilterChipView categoryGeneral, categorySpecialInterests;
|
private FilterChipView categoryGeneral, categorySpecialInterests;
|
||||||
private List<FilterChipView> regionalFilters;
|
private List<FilterChipView> regionalFilters;
|
||||||
private CatalogInstance.Region chosenRegion;
|
private CatalogInstance.Region chosenRegion;
|
||||||
private CategoryChoice categoryChoice;
|
private CategoryChoice categoryChoice=CategoryChoice.GENERAL;
|
||||||
|
|
||||||
public InstanceCatalogSignupFragment(){
|
public InstanceCatalogSignupFragment(){
|
||||||
super(R.layout.fragment_onboarding_common, 10);
|
super(R.layout.fragment_onboarding_common, 10);
|
||||||
@@ -371,6 +371,9 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
|||||||
if(instances.isEmpty()){
|
if(instances.isEmpty()){
|
||||||
instances=data.stream().filter(ci->!ci.approvalRequired && ("general".equals(ci.category) || (ci.categories!=null && ci.categories.contains("general")))).collect(Collectors.toList());
|
instances=data.stream().filter(ci->!ci.approvalRequired && ("general".equals(ci.category) || (ci.categories!=null && ci.categories.contains("general")))).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
if(instances.isEmpty()){
|
||||||
|
instances=data.stream().filter(ci->("general".equals(ci.category) || (ci.categories!=null && ci.categories.contains("general")))).collect(Collectors.toList());
|
||||||
|
}
|
||||||
if(instances.isEmpty()){
|
if(instances.isEmpty()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,14 @@ package org.joinmastodon.android.fragments.onboarding;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.style.StyleSpan;
|
||||||
|
import android.text.style.TypefaceSpan;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -64,7 +70,7 @@ public class InstanceRulesFragment extends ToolbarFragment{
|
|||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
||||||
TextView text=headerView.findViewById(R.id.text);
|
TextView text=headerView.findViewById(R.id.text);
|
||||||
text.setText(getString(R.string.instance_rules_subtitle, instance.uri));
|
text.setText(Html.fromHtml(getString(R.string.instance_rules_subtitle, "<b>"+Html.escapeHtml(instance.uri)+"</b>")));
|
||||||
|
|
||||||
adapter=new MergeRecyclerAdapter();
|
adapter=new MergeRecyclerAdapter();
|
||||||
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||||
import org.joinmastodon.android.fragments.HomeFragment;
|
import org.joinmastodon.android.fragments.HomeFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.model.FollowSuggestion;
|
import org.joinmastodon.android.model.FollowSuggestion;
|
||||||
import org.joinmastodon.android.model.ParsedAccount;
|
import org.joinmastodon.android.model.ParsedAccount;
|
||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
@@ -43,7 +44,6 @@ import me.grishka.appkit.Nav;
|
|||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
@@ -52,7 +52,7 @@ import me.grishka.appkit.utils.V;
|
|||||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class OnboardingFollowSuggestionsFragment extends BaseRecyclerFragment<ParsedAccount>{
|
public class OnboardingFollowSuggestionsFragment extends RecyclerFragment<ParsedAccount> {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||||
private GetAccountRelationships relationshipsRequest;
|
private GetAccountRelationships relationshipsRequest;
|
||||||
@@ -191,6 +191,13 @@ public class OnboardingFollowSuggestionsFragment extends BaseRecyclerFragment<Pa
|
|||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Relationship result){
|
public void onSuccess(Relationship result){
|
||||||
|
relationships.put(id, result);
|
||||||
|
for(int i=0;i<list.getChildCount();i++){
|
||||||
|
if(list.getChildViewHolder(list.getChildAt(i)) instanceof SuggestionViewHolder svh && svh.getItem().account.id.equals(id)){
|
||||||
|
svh.rebind();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
numRunningFollowRequests--;
|
numRunningFollowRequests--;
|
||||||
progress.setProgress(progress.getMax()-accountIdsToFollow.size()-numRunningFollowRequests);
|
progress.setProgress(progress.getMax()-accountIdsToFollow.size()-numRunningFollowRequests);
|
||||||
followNextAccount(accountIdsToFollow, progress);
|
followNextAccount(accountIdsToFollow, progress);
|
||||||
@@ -209,20 +216,7 @@ public class OnboardingFollowSuggestionsFragment extends BaseRecyclerFragment<Pa
|
|||||||
private void proceed(){
|
private void proceed(){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
Nav.go(getActivity(), HomeFragment.class, args);
|
Nav.go(getActivity(), OnboardingProfileSetupFragment.class, args);
|
||||||
getActivity().getWindow().getDecorView().postDelayed(()->Nav.finish(this), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canGoBack(){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onToolbarNavigationClick(){
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
args.putString("account", accountID);
|
|
||||||
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SuggestionsAdapter extends UsableRecyclerView.Adapter<SuggestionViewHolder> implements ImageLoaderRecyclerAdapter{
|
private class SuggestionsAdapter extends UsableRecyclerView.Adapter<SuggestionViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|||||||
@@ -151,8 +151,7 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
|
|||||||
AccountSessionManager.getInstance().updateAccountInfo(accountID, result);
|
AccountSessionManager.getInstance().updateAccountInfo(accountID, result);
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
Nav.go(getActivity(), OnboardingFollowSuggestionsFragment.class, args);
|
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||||
getActivity().getWindow().getDecorView().postDelayed(()->Nav.finish(OnboardingProfileSetupFragment.this), 500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -182,6 +181,11 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
|
|||||||
profileFieldsLayout.startDragging(view);
|
profileFieldsLayout.startDragging(view);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
view.findViewById(R.id.delete).setOnClickListener(v->{
|
||||||
|
profileFieldsLayout.removeView(view);
|
||||||
|
if(addRow.getVisibility()==View.GONE)
|
||||||
|
addRow.setVisibility(View.VISIBLE);
|
||||||
|
});
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,16 +226,4 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
|
|||||||
img.setForeground(null);
|
img.setForeground(null);
|
||||||
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, size, size));
|
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, size, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canGoBack(){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onToolbarNavigationClick(){
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
args.putString("account", accountID);
|
|
||||||
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,8 @@ import org.joinmastodon.android.fragments.StatusListFragment;
|
|||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
@@ -133,22 +131,7 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
if(holder.getAbsoluteAdapterPosition()==0)
|
if(holder.getAbsoluteAdapterPosition()==0)
|
||||||
return;
|
return;
|
||||||
outRect.left=V.dp(40);
|
outRect.left=V.dp(40);
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
if(holder instanceof AudioStatusDisplayItem.Holder){
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=imgHolder.getItem().tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
|
||||||
String siblingID;
|
|
||||||
if(holder.getAbsoluteAdapterPosition()<parent.getAdapter().getItemCount()-1){
|
|
||||||
siblingID=displayItems.get(holder.getAbsoluteAdapterPosition()-getMainAdapterOffset()+1).parentID;
|
|
||||||
}else{
|
|
||||||
siblingID=null;
|
|
||||||
}
|
|
||||||
if(tile.startCol>0)
|
|
||||||
outRect.left=0;
|
|
||||||
outRect.left+=V.dp(16);
|
|
||||||
outRect.right=V.dp(16);
|
|
||||||
if(!imgHolder.getItemID().equals(siblingID) || tile.startRow+tile.rowSpan==layout.rowSizes.length)
|
|
||||||
outRect.bottom=V.dp(16);
|
|
||||||
}else if(holder instanceof AudioStatusDisplayItem.Holder){
|
|
||||||
outRect.bottom=V.dp(16);
|
outRect.bottom=V.dp(16);
|
||||||
}else if(holder instanceof LinkCardStatusDisplayItem.Holder){
|
}else if(holder instanceof LinkCardStatusDisplayItem.Holder){
|
||||||
outRect.bottom=V.dp(16);
|
outRect.bottom=V.dp(16);
|
||||||
@@ -167,10 +150,6 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||||
String id=sdiHolder.getItemID();
|
String id=sdiHolder.getItemID();
|
||||||
int height=tmpRect.height();
|
int height=tmpRect.height();
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
||||||
if(imgHolder.getItem().thisTile.startCol+imgHolder.getItem().thisTile.colSpan<imgHolder.getItem().tiledLayout.columnSizes.length)
|
|
||||||
height=0;
|
|
||||||
}
|
|
||||||
if(!(holder instanceof HeaderStatusDisplayItem.Holder) && !(holder instanceof ReblogOrReplyLineStatusDisplayItem.Holder))
|
if(!(holder instanceof HeaderStatusDisplayItem.Holder) && !(holder instanceof ReblogOrReplyLineStatusDisplayItem.Holder))
|
||||||
postsWithKnownNonHeaderHeights.add(id);
|
postsWithKnownNonHeaderHeights.add(id);
|
||||||
knownDisplayItemHeights.put(holder.getAbsoluteAdapterPosition(), height);
|
knownDisplayItemHeights.put(holder.getAbsoluteAdapterPosition(), height);
|
||||||
@@ -237,17 +216,6 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
|
||||||
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null, Filter.FilterContext.HOME);
|
|
||||||
for(StatusDisplayItem item:items){
|
|
||||||
if(item instanceof ImageStatusDisplayItem isdi){
|
|
||||||
isdi.horizontalInset=V.dp(40+32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void drawDivider(View child, View bottomSibling, RecyclerView.ViewHolder holder, RecyclerView.ViewHolder siblingHolder, RecyclerView parent, Canvas c, Paint paint){
|
protected void drawDivider(View child, View bottomSibling, RecyclerView.ViewHolder holder, RecyclerView.ViewHolder siblingHolder, RecyclerView parent, Canvas c, Paint paint){
|
||||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||||
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import java.util.List;
|
|||||||
* Represents a user of Mastodon and their associated profile.
|
* Represents a user of Mastodon and their associated profile.
|
||||||
*/
|
*/
|
||||||
@Parcel
|
@Parcel
|
||||||
public class Account extends BaseModel{
|
public class Account extends BaseModel implements Searchable{
|
||||||
// Base attributes
|
// Base attributes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +43,7 @@ public class Account extends BaseModel{
|
|||||||
/**
|
/**
|
||||||
* The profile's display name.
|
* The profile's display name.
|
||||||
*/
|
*/
|
||||||
@RequiredField
|
// @RequiredField
|
||||||
public String displayName;
|
public String displayName;
|
||||||
/**
|
/**
|
||||||
* The profile's bio / description.
|
* The profile's bio / description.
|
||||||
@@ -86,7 +86,7 @@ public class Account extends BaseModel{
|
|||||||
/**
|
/**
|
||||||
* When the account was created.
|
* When the account was created.
|
||||||
*/
|
*/
|
||||||
@RequiredField
|
// @RequiredField
|
||||||
public Instant createdAt;
|
public Instant createdAt;
|
||||||
/**
|
/**
|
||||||
* When the most recent status was posted.
|
* When the most recent status was posted.
|
||||||
@@ -134,6 +134,12 @@ public class Account extends BaseModel{
|
|||||||
public Instant muteExpiresAt;
|
public Instant muteExpiresAt;
|
||||||
|
|
||||||
public List<Role> roles;
|
public List<Role> roles;
|
||||||
|
public boolean reloadWhenClicked;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getQuery() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
public static class Role {
|
public static class Role {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public class CustomLocalTimeline extends BaseModel{
|
||||||
|
@RequiredField
|
||||||
|
public String domain;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "Hashtag{"+
|
||||||
|
", url='"+domain+'\''+
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -121,7 +121,7 @@ public class Instance extends BaseModel{
|
|||||||
ci.domain=uri;
|
ci.domain=uri;
|
||||||
ci.normalizedDomain=IDN.toUnicode(uri);
|
ci.normalizedDomain=IDN.toUnicode(uri);
|
||||||
ci.description=Html.fromHtml(shortDescription).toString().trim();
|
ci.description=Html.fromHtml(shortDescription).toString().trim();
|
||||||
if(languages!=null){
|
if(languages!=null && languages.size() > 0){
|
||||||
ci.language=languages.get(0);
|
ci.language=languages.get(0);
|
||||||
ci.languages=languages;
|
ci.languages=languages;
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.joinmastodon.android.model;
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.AllFieldsAreRequired;
|
import org.joinmastodon.android.api.AllFieldsAreRequired;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -18,4 +20,11 @@ public class Marker extends BaseModel{
|
|||||||
", updatedAt="+updatedAt+
|
", updatedAt="+updatedAt+
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
@SerializedName("home")
|
||||||
|
HOME,
|
||||||
|
@SerializedName("notifications")
|
||||||
|
NOTIFICATIONS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
public class Markers {
|
||||||
|
public Marker notifications;
|
||||||
|
public Marker home;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Markers{" +
|
||||||
|
"notifications=" + notifications +
|
||||||
|
", home=" + home +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
public enum NotificationAction {
|
||||||
|
FAVORITE,
|
||||||
|
BOOST,
|
||||||
|
UNBOOST,
|
||||||
|
BOOKMARK,
|
||||||
|
REPLY,
|
||||||
|
}
|
||||||
@@ -16,12 +16,13 @@ public class Poll extends BaseModel{
|
|||||||
private boolean expired;
|
private boolean expired;
|
||||||
public boolean multiple;
|
public boolean multiple;
|
||||||
public int votersCount;
|
public int votersCount;
|
||||||
|
public int votesCount;
|
||||||
public boolean voted;
|
public boolean voted;
|
||||||
@RequiredField
|
// @RequiredField
|
||||||
public List<Integer> ownVotes;
|
public List<Integer> ownVotes;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public List<Option> options;
|
public List<Option> options;
|
||||||
@RequiredField
|
// @RequiredField
|
||||||
public List<Emoji> emojis;
|
public List<Emoji> emojis;
|
||||||
|
|
||||||
public transient ArrayList<Option> selectedOptions;
|
public transient ArrayList<Option> selectedOptions;
|
||||||
@@ -29,6 +30,8 @@ public class Poll extends BaseModel{
|
|||||||
@Override
|
@Override
|
||||||
public void postprocess() throws ObjectValidationException{
|
public void postprocess() throws ObjectValidationException{
|
||||||
super.postprocess();
|
super.postprocess();
|
||||||
|
if (emojis == null) emojis = List.of();
|
||||||
|
if (ownVotes == null) ownVotes = List.of();
|
||||||
for(Emoji e:emojis)
|
for(Emoji e:emojis)
|
||||||
e.postprocess();
|
e.postprocess();
|
||||||
}
|
}
|
||||||
@@ -41,10 +44,12 @@ public class Poll extends BaseModel{
|
|||||||
", expired="+expired+
|
", expired="+expired+
|
||||||
", multiple="+multiple+
|
", multiple="+multiple+
|
||||||
", votersCount="+votersCount+
|
", votersCount="+votersCount+
|
||||||
|
", votesCount="+votesCount+
|
||||||
", voted="+voted+
|
", voted="+voted+
|
||||||
", ownVotes="+ownVotes+
|
", ownVotes="+ownVotes+
|
||||||
", options="+options+
|
", options="+options+
|
||||||
", emojis="+emojis+
|
", emojis="+emojis+
|
||||||
|
", selectedOptions="+selectedOptions+
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
public interface Searchable {
|
||||||
|
String getQuery();
|
||||||
|
}
|
||||||
@@ -1,5 +1,14 @@
|
|||||||
package org.joinmastodon.android.model;
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import static org.joinmastodon.android.api.MastodonAPIController.gson;
|
||||||
|
import static org.joinmastodon.android.api.MastodonAPIController.gsonWithoutDeserializer;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.api.ObjectValidationException;
|
import org.joinmastodon.android.api.ObjectValidationException;
|
||||||
import org.joinmastodon.android.api.RequiredField;
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
@@ -7,16 +16,17 @@ import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
|||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
public class Status extends BaseModel implements DisplayItemsParent{
|
public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public String id;
|
public String id;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public String uri;
|
public String uri;
|
||||||
@RequiredField
|
// @RequiredField // sometimes null on calckey
|
||||||
public Instant createdAt;
|
public Instant createdAt;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public Account account;
|
public Account account;
|
||||||
@@ -58,14 +68,22 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
|||||||
public boolean bookmarked;
|
public boolean bookmarked;
|
||||||
public boolean pinned;
|
public boolean pinned;
|
||||||
|
|
||||||
|
public Status quote; // can be boolean in calckey
|
||||||
|
|
||||||
public transient boolean filterRevealed;
|
public transient boolean filterRevealed;
|
||||||
public transient boolean spoilerRevealed;
|
public transient boolean spoilerRevealed;
|
||||||
public transient boolean textExpanded, textExpandable;
|
public transient boolean textExpanded, textExpandable;
|
||||||
public transient boolean hasGapAfter;
|
public transient boolean hasGapAfter;
|
||||||
|
public transient TranslatedStatus translation;
|
||||||
|
public transient boolean translationShown;
|
||||||
|
public boolean reloadWhenClicked;
|
||||||
private transient String strippedText;
|
private transient String strippedText;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postprocess() throws ObjectValidationException{
|
public void postprocess() throws ObjectValidationException{
|
||||||
|
if(spoilerText!=null && !spoilerText.isEmpty() && !sensitive)
|
||||||
|
sensitive=true;
|
||||||
|
|
||||||
super.postprocess();
|
super.postprocess();
|
||||||
if(application!=null)
|
if(application!=null)
|
||||||
application.postprocess();
|
application.postprocess();
|
||||||
@@ -163,4 +181,33 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
|||||||
s.filtered = List.of();
|
s.filtered = List.of();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getQuery() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StatusDeserializer implements JsonDeserializer<Status> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject obj = json.getAsJsonObject();
|
||||||
|
|
||||||
|
Status quote = null;
|
||||||
|
if (obj.has("quote") && obj.get("quote").isJsonObject())
|
||||||
|
quote = gson.fromJson(obj.get("quote"), Status.class);
|
||||||
|
obj.remove("quote");
|
||||||
|
|
||||||
|
Status reblog = null;
|
||||||
|
if (obj.has("reblog"))
|
||||||
|
reblog = gson.fromJson(obj.get("reblog"), Status.class);
|
||||||
|
obj.remove("reblog");
|
||||||
|
|
||||||
|
Status status = gsonWithoutDeserializer.fromJson(json, Status.class);
|
||||||
|
status.quote = quote;
|
||||||
|
status.reblog = reblog;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.annotation.StringRes;
|
|||||||
|
|
||||||
import org.joinmastodon.android.BuildConfig;
|
import org.joinmastodon.android.BuildConfig;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.fragments.CustomLocalTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.HomeTimelineFragment;
|
import org.joinmastodon.android.fragments.HomeTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
||||||
@@ -27,7 +28,7 @@ public class TimelineDefinition {
|
|||||||
|
|
||||||
private @Nullable String listId;
|
private @Nullable String listId;
|
||||||
private @Nullable String listTitle;
|
private @Nullable String listTitle;
|
||||||
|
private @Nullable String domain;
|
||||||
private @Nullable String hashtagName;
|
private @Nullable String hashtagName;
|
||||||
|
|
||||||
public static TimelineDefinition ofList(String listId, String listTitle) {
|
public static TimelineDefinition ofList(String listId, String listTitle) {
|
||||||
@@ -47,6 +48,12 @@ public class TimelineDefinition {
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TimelineDefinition ofCustomLocalTimeline(String domain) {
|
||||||
|
TimelineDefinition def = new TimelineDefinition(TimelineType.CUSTOM_LOCAL_TIMELINE);
|
||||||
|
def.domain = domain;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
public static TimelineDefinition ofHashtag(Hashtag hashtag) {
|
public static TimelineDefinition ofHashtag(Hashtag hashtag) {
|
||||||
return ofHashtag(hashtag.name);
|
return ofHashtag(hashtag.name);
|
||||||
}
|
}
|
||||||
@@ -78,6 +85,7 @@ public class TimelineDefinition {
|
|||||||
case POST_NOTIFICATIONS -> ctx.getString(R.string.sk_timeline_posts);
|
case POST_NOTIFICATIONS -> ctx.getString(R.string.sk_timeline_posts);
|
||||||
case LIST -> listTitle;
|
case LIST -> listTitle;
|
||||||
case HASHTAG -> hashtagName;
|
case HASHTAG -> hashtagName;
|
||||||
|
case CUSTOM_LOCAL_TIMELINE -> domain;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +97,7 @@ public class TimelineDefinition {
|
|||||||
case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS;
|
case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS;
|
||||||
case LIST -> Icon.LIST;
|
case LIST -> Icon.LIST;
|
||||||
case HASHTAG -> Icon.HASHTAG;
|
case HASHTAG -> Icon.HASHTAG;
|
||||||
|
case CUSTOM_LOCAL_TIMELINE -> Icon.CUSTOM_LOCAL_TIMELINE;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +109,7 @@ public class TimelineDefinition {
|
|||||||
case LIST -> new ListTimelineFragment();
|
case LIST -> new ListTimelineFragment();
|
||||||
case HASHTAG -> new HashtagTimelineFragment();
|
case HASHTAG -> new HashtagTimelineFragment();
|
||||||
case POST_NOTIFICATIONS -> new NotificationsListFragment();
|
case POST_NOTIFICATIONS -> new NotificationsListFragment();
|
||||||
|
case CUSTOM_LOCAL_TIMELINE -> new CustomLocalTimelineFragment();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +135,7 @@ public class TimelineDefinition {
|
|||||||
if (type != that.type) return false;
|
if (type != that.type) return false;
|
||||||
if (type == TimelineType.LIST) return Objects.equals(listId, that.listId);
|
if (type == TimelineType.LIST) return Objects.equals(listId, that.listId);
|
||||||
if (type == TimelineType.HASHTAG) return Objects.equals(hashtagName.toLowerCase(), that.hashtagName.toLowerCase());
|
if (type == TimelineType.HASHTAG) return Objects.equals(hashtagName.toLowerCase(), that.hashtagName.toLowerCase());
|
||||||
|
if (type == TimelineType.CUSTOM_LOCAL_TIMELINE) return Objects.equals(domain.toLowerCase(), that.domain.toLowerCase());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +144,8 @@ public class TimelineDefinition {
|
|||||||
int result = type.ordinal();
|
int result = type.ordinal();
|
||||||
result = 31 * result + (listId != null ? listId.hashCode() : 0);
|
result = 31 * result + (listId != null ? listId.hashCode() : 0);
|
||||||
result = 31 * result + (hashtagName.toLowerCase() != null ? hashtagName.toLowerCase().hashCode() : 0);
|
result = 31 * result + (hashtagName.toLowerCase() != null ? hashtagName.toLowerCase().hashCode() : 0);
|
||||||
|
result = 31 * result + (domain.toLowerCase() != null ? domain.toLowerCase().hashCode() : 0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +155,7 @@ public class TimelineDefinition {
|
|||||||
def.listId = listId;
|
def.listId = listId;
|
||||||
def.listTitle = listTitle;
|
def.listTitle = listTitle;
|
||||||
def.hashtagName = hashtagName;
|
def.hashtagName = hashtagName;
|
||||||
|
def.domain = domain;
|
||||||
def.icon = icon == null ? null : Icon.values()[icon.ordinal()];
|
def.icon = icon == null ? null : Icon.values()[icon.ordinal()];
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
@@ -152,11 +166,13 @@ public class TimelineDefinition {
|
|||||||
args.putString("listID", listId);
|
args.putString("listID", listId);
|
||||||
} else if (type == TimelineType.HASHTAG) {
|
} else if (type == TimelineType.HASHTAG) {
|
||||||
args.putString("hashtag", hashtagName);
|
args.putString("hashtag", hashtagName);
|
||||||
|
} else if (type == TimelineType.CUSTOM_LOCAL_TIMELINE) {
|
||||||
|
args.putString("domain", domain);
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG }
|
public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG, CUSTOM_LOCAL_TIMELINE }
|
||||||
|
|
||||||
public enum Icon {
|
public enum Icon {
|
||||||
HEART(R.drawable.ic_fluent_heart_24_regular, R.string.sk_icon_heart),
|
HEART(R.drawable.ic_fluent_heart_24_regular, R.string.sk_icon_heart),
|
||||||
@@ -219,7 +235,8 @@ public class TimelineDefinition {
|
|||||||
FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true),
|
FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true),
|
||||||
POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true),
|
POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true),
|
||||||
LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true),
|
LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true),
|
||||||
HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true);
|
HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true),
|
||||||
|
CUSTOM_LOCAL_TIMELINE(R.drawable.ic_fluent_people_community_24_regular, R.string.sk_timeline_local, true);
|
||||||
|
|
||||||
public final int iconRes, nameRes;
|
public final int iconRes, nameRes;
|
||||||
public final boolean hidden;
|
public final boolean hidden;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.joinmastodon.android.ui;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
@@ -17,21 +16,21 @@ import android.widget.ImageView;
|
|||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.MainActivity;
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
@@ -53,10 +52,14 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
private UsableRecyclerView list;
|
private UsableRecyclerView list;
|
||||||
private List<WrappedAccount> accounts;
|
private List<WrappedAccount> accounts;
|
||||||
private ListImageLoaderWrapper imgLoader;
|
private ListImageLoaderWrapper imgLoader;
|
||||||
|
private final boolean logOutEnabled;
|
||||||
|
private final Consumer<AccountSession> onClick;
|
||||||
|
|
||||||
public AccountSwitcherSheet(@NonNull Activity activity){
|
public AccountSwitcherSheet(@NonNull Activity activity, boolean logOutEnabled, boolean addAccountEnabled, boolean showOpenURL, Consumer<AccountSession> onClick){
|
||||||
super(activity);
|
super(activity);
|
||||||
this.activity=activity;
|
this.activity=activity;
|
||||||
|
this.logOutEnabled=logOutEnabled;
|
||||||
|
this.onClick=onClick;
|
||||||
|
|
||||||
accounts=AccountSessionManager.getInstance().getLoggedInAccounts().stream().map(WrappedAccount::new).collect(Collectors.toList());
|
accounts=AccountSessionManager.getInstance().getLoggedInAccounts().stream().map(WrappedAccount::new).collect(Collectors.toList());
|
||||||
|
|
||||||
@@ -70,10 +73,13 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
handle.setBackgroundResource(R.drawable.bg_bottom_sheet_handle);
|
handle.setBackgroundResource(R.drawable.bg_bottom_sheet_handle);
|
||||||
adapter.addAdapter(new SingleViewRecyclerAdapter(handle));
|
adapter.addAdapter(new SingleViewRecyclerAdapter(handle));
|
||||||
adapter.addAdapter(new AccountsAdapter());
|
adapter.addAdapter(new AccountsAdapter());
|
||||||
|
|
||||||
|
if(addAccountEnabled){
|
||||||
AccountViewHolder holder = new AccountViewHolder();
|
AccountViewHolder holder = new AccountViewHolder();
|
||||||
holder.more.setVisibility(View.GONE);
|
holder.more.setVisibility(View.GONE);
|
||||||
holder.currentIcon.setVisibility(View.GONE);
|
holder.currentIcon.setVisibility(View.GONE);
|
||||||
holder.name.setText(R.string.add_account);
|
holder.display_name.setVisibility(View.GONE);
|
||||||
|
holder.display_add_account.setVisibility(View.VISIBLE);
|
||||||
holder.avatar.setScaleType(ImageView.ScaleType.CENTER);
|
holder.avatar.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
holder.avatar.setImageResource(R.drawable.ic_fluent_add_circle_24_filled);
|
holder.avatar.setImageResource(R.drawable.ic_fluent_add_circle_24_filled);
|
||||||
holder.avatar.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(activity, android.R.attr.textColorPrimary)));
|
holder.avatar.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(activity, android.R.attr.textColorPrimary)));
|
||||||
@@ -81,6 +87,23 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
Nav.go(activity, CustomWelcomeFragment.class, null);
|
Nav.go(activity, CustomWelcomeFragment.class, null);
|
||||||
dismiss();
|
dismiss();
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(showOpenURL) {
|
||||||
|
AccountViewHolder holder = new AccountViewHolder();
|
||||||
|
holder.more.setVisibility(View.GONE);
|
||||||
|
holder.currentIcon.setVisibility(View.GONE);
|
||||||
|
holder.display_name.setVisibility(View.VISIBLE);
|
||||||
|
holder.display_add_account.setVisibility(View.VISIBLE);
|
||||||
|
holder.display_add_account.setText(R.string.mo_share_open_url);
|
||||||
|
holder.avatar.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
|
holder.avatar.setImageResource(R.drawable.ic_fluent_open_24_regular);
|
||||||
|
holder.avatar.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(activity, android.R.attr.textColorPrimary)));
|
||||||
|
adapter.addAdapter(new ClickableSingleViewRecyclerAdapter(holder.itemView, () -> {
|
||||||
|
onClick.accept(null);
|
||||||
|
dismiss();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
DividerItemDecoration divider=new DividerItemDecoration(activity, R.attr.colorPollVoted, .5f, 72, 16, DividerItemDecoration.NOT_FIRST);
|
DividerItemDecoration divider=new DividerItemDecoration(activity, R.attr.colorPollVoted, .5f, 72, 16, DividerItemDecoration.NOT_FIRST);
|
||||||
@@ -176,6 +199,8 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
|
|
||||||
private class AccountViewHolder extends BindableViewHolder<AccountSession> implements ImageLoaderViewHolder, UsableRecyclerView.Clickable{
|
private class AccountViewHolder extends BindableViewHolder<AccountSession> implements ImageLoaderViewHolder, UsableRecyclerView.Clickable{
|
||||||
private final TextView name;
|
private final TextView name;
|
||||||
|
private final TextView display_name;
|
||||||
|
private final TextView display_add_account;
|
||||||
private final ImageView avatar;
|
private final ImageView avatar;
|
||||||
private final ImageButton more;
|
private final ImageButton more;
|
||||||
private final View currentIcon;
|
private final View currentIcon;
|
||||||
@@ -184,6 +209,8 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
public AccountViewHolder(){
|
public AccountViewHolder(){
|
||||||
super(activity, R.layout.item_account_switcher, list);
|
super(activity, R.layout.item_account_switcher, list);
|
||||||
name=findViewById(R.id.name);
|
name=findViewById(R.id.name);
|
||||||
|
display_name=findViewById(R.id.display_name);
|
||||||
|
display_add_account=findViewById(R.id.add_account);
|
||||||
avatar=findViewById(R.id.avatar);
|
avatar=findViewById(R.id.avatar);
|
||||||
more=findViewById(R.id.more);
|
more=findViewById(R.id.more);
|
||||||
currentIcon=findViewById(R.id.current);
|
currentIcon=findViewById(R.id.current);
|
||||||
@@ -203,6 +230,7 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@Override
|
@Override
|
||||||
public void onBind(AccountSession item){
|
public void onBind(AccountSession item){
|
||||||
|
display_name.setText(item.self.displayName);
|
||||||
name.setText("@"+item.self.username+"@"+item.domain);
|
name.setText("@"+item.self.username+"@"+item.domain);
|
||||||
if(AccountSessionManager.getInstance().getLastActiveAccountID().equals(item.getID())){
|
if(AccountSessionManager.getInstance().getLastActiveAccountID().equals(item.getID())){
|
||||||
more.setVisibility(View.GONE);
|
more.setVisibility(View.GONE);
|
||||||
@@ -211,6 +239,11 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
more.setVisibility(View.VISIBLE);
|
more.setVisibility(View.VISIBLE);
|
||||||
currentIcon.setVisibility(View.GONE);
|
currentIcon.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!logOutEnabled){
|
||||||
|
more.setVisibility(View.GONE);
|
||||||
|
currentIcon.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
menu.getMenu().findItem(R.id.log_out).setTitle(activity.getString(R.string.log_out_account, "@"+item.self.username));
|
menu.getMenu().findItem(R.id.log_out).setTitle(activity.getString(R.string.log_out_account, "@"+item.self.username));
|
||||||
UiUtils.enablePopupMenuIcons(activity, menu);
|
UiUtils.enablePopupMenuIcons(activity, menu);
|
||||||
}
|
}
|
||||||
@@ -230,8 +263,8 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(){
|
public void onClick(){
|
||||||
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
||||||
activity.finish();
|
dismiss();
|
||||||
activity.startActivity(new Intent(activity, MainActivity.class));
|
onClick.accept(AccountSessionManager.getInstance().getAccount(item.getID()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,14 @@ import java.util.List;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class PhotoLayoutHelper{
|
public class PhotoLayoutHelper{
|
||||||
|
public static final int MAX_WIDTH=1000;
|
||||||
|
public static final int MAX_HEIGHT=1910;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static TiledLayoutResult processThumbs(int _maxW, int _maxH, List<Attachment> thumbs){
|
public static TiledLayoutResult processThumbs(List<Attachment> thumbs){
|
||||||
|
int _maxW=MAX_WIDTH;
|
||||||
|
int _maxH=MAX_HEIGHT;
|
||||||
|
|
||||||
TiledLayoutResult result=new TiledLayoutResult();
|
TiledLayoutResult result=new TiledLayoutResult();
|
||||||
if(thumbs.size()==1){
|
if(thumbs.size()==1){
|
||||||
Attachment att=thumbs.get(0);
|
Attachment att=thumbs.get(0);
|
||||||
@@ -45,13 +51,8 @@ public class PhotoLayoutHelper{
|
|||||||
float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f;
|
float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f;
|
||||||
|
|
||||||
float maxW, maxH, marginW=0, marginH=0;
|
float maxW, maxH, marginW=0, marginH=0;
|
||||||
if(_maxW>0){
|
|
||||||
maxW=_maxW;
|
maxW=_maxW;
|
||||||
maxH=_maxH;
|
maxH=_maxH;
|
||||||
}else{
|
|
||||||
maxW=510;
|
|
||||||
maxH=510;
|
|
||||||
}
|
|
||||||
|
|
||||||
float maxRatio=maxW/maxH;
|
float maxRatio=maxW/maxH;
|
||||||
|
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
|
|||||||
rejectWrap=findViewById(R.id.reject_btn_wrap);
|
rejectWrap=findViewById(R.id.reject_btn_wrap);
|
||||||
|
|
||||||
View card=findViewById(R.id.card);
|
View card=findViewById(R.id.card);
|
||||||
card.setOutlineProvider(OutlineProviders.roundedRect(6));
|
card.setOutlineProvider(OutlineProviders.roundedRect(12));
|
||||||
card.setClipToOutline(true);
|
card.setClipToOutline(true);
|
||||||
avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
|
avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
|
||||||
avatar.setClipToOutline(true);
|
avatar.setClipToOutline(true);
|
||||||
cover.setOutlineProvider(OutlineProviders.roundedRect(3));
|
cover.setOutlineProvider(OutlineProviders.roundedRect(12));
|
||||||
cover.setClipToOutline(true);
|
cover.setClipToOutline(true);
|
||||||
actionButton.setOnClickListener(this::onActionButtonClick);
|
actionButton.setOnClickListener(this::onActionButtonClick);
|
||||||
acceptButton.setOnClickListener(this::onFollowRequestButtonClick);
|
acceptButton.setOnClickListener(this::onFollowRequestButtonClick);
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}else{
|
}else{
|
||||||
editHistory.setVisibility(View.GONE);
|
editHistory.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
String timeStr=TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault()));
|
String timeStr=item.status.createdAt != null ? TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault())) : null;
|
||||||
|
|
||||||
if (item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)) {
|
if (item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)) {
|
||||||
time.setText(item.parentFragment.getString(R.string.timestamp_via_app, timeStr, ""));
|
time.setText(timeStr != null ? item.parentFragment.getString(R.string.timestamp_via_app, timeStr, "") : "");
|
||||||
applicationName.setText(item.status.application.name);
|
applicationName.setText(item.status.application.name);
|
||||||
if (item.status.application.website != null && item.status.application.website.toLowerCase().startsWith("https://")) {
|
if (item.status.application.website != null && item.status.application.website.toLowerCase().startsWith("https://")) {
|
||||||
applicationName.setOnClickListener(e -> UiUtils.openURL(context, null, item.status.application.website));
|
applicationName.setOnClickListener(e -> UiUtils.openURL(context, null, item.status.application.website));
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.joinmastodon.android.api.session.AccountSession;
|
|||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.ComposeFragment;
|
import org.joinmastodon.android.fragments.ComposeFragment;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.StatusPrivacy;
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
@@ -191,6 +192,19 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onReplyClick(View v){
|
private void onReplyClick(View v){
|
||||||
|
if(item.status.reloadWhenClicked){
|
||||||
|
UiUtils.lookupStatus(v.getContext(),
|
||||||
|
item.status, item.accountID, null,
|
||||||
|
status -> {
|
||||||
|
v.startAnimation(opacityIn);
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
args.putString("account", item.accountID);
|
||||||
|
args.putParcelable("replyTo", Parcels.wrap(status));
|
||||||
|
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
v.startAnimation(opacityIn);
|
v.startAnimation(opacityIn);
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
@@ -205,6 +219,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
String accountID = session.getID();
|
String accountID = session.getID();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
UiUtils.lookupStatus(v.getContext(), item.status, accountID, item.accountID, status -> {
|
UiUtils.lookupStatus(v.getContext(), item.status, accountID, item.accountID, status -> {
|
||||||
|
if (status == null) return;
|
||||||
args.putParcelable("replyTo", Parcels.wrap(status));
|
args.putParcelable("replyTo", Parcels.wrap(status));
|
||||||
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
||||||
});
|
});
|
||||||
@@ -213,6 +228,21 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onBoostClick(View v){
|
private void onBoostClick(View v){
|
||||||
|
if (GlobalUserPreferences.confirmBeforeReblog) {
|
||||||
|
v.startAnimation(opacityIn);
|
||||||
|
onBoostLongClick(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(item.status.reloadWhenClicked){
|
||||||
|
UiUtils.lookupStatus(v.getContext(),
|
||||||
|
item.status, item.accountID, null,
|
||||||
|
status -> {
|
||||||
|
boost.setSelected(!status.reblogged);
|
||||||
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(status, !status.reblogged, null, r->boostConsumer(v, r));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
boost.setSelected(!item.status.reblogged);
|
boost.setSelected(!item.status.reblogged);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r));
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r));
|
||||||
}
|
}
|
||||||
@@ -230,9 +260,22 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
|
|
||||||
Consumer<StatusPrivacy> doReblog = (visibility) -> {
|
Consumer<StatusPrivacy> doReblog = (visibility) -> {
|
||||||
v.startAnimation(opacityOut);
|
v.startAnimation(opacityOut);
|
||||||
|
if(item.status.reloadWhenClicked){
|
||||||
|
UiUtils.lookupStatus(v.getContext(),
|
||||||
|
item.status, item.accountID, null,
|
||||||
|
status -> {
|
||||||
|
session.getStatusInteractionController()
|
||||||
|
.setReblogged(status, !status.reblogged, visibility, r->boostConsumer(v, r));
|
||||||
|
boost.setSelected(status.reblogged);
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
session.getStatusInteractionController()
|
session.getStatusInteractionController()
|
||||||
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
|
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
|
||||||
|
boost.setSelected(item.status.reblogged);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
View separator = menu.findViewById(R.id.separator);
|
View separator = menu.findViewById(R.id.separator);
|
||||||
@@ -248,9 +291,9 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
reblogHeader.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
|
reblogHeader.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
|
||||||
reblogAs.setVisibility(AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1 ? View.VISIBLE : View.GONE);
|
reblogAs.setVisibility(AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1 ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
itemPublic.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PUBLIC) ? View.GONE : View.VISIBLE);
|
itemPublic.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
|
||||||
itemUnlisted.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) ? View.GONE : View.VISIBLE);
|
itemUnlisted.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
|
||||||
itemFollowers.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PRIVATE) ? View.GONE : View.VISIBLE);
|
itemFollowers.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
|
||||||
|
|
||||||
Drawable checkMark = ctx.getDrawable(R.drawable.ic_fluent_checkmark_circle_20_regular);
|
Drawable checkMark = ctx.getDrawable(R.drawable.ic_fluent_checkmark_circle_20_regular);
|
||||||
Drawable publicDrawable = ctx.getDrawable(R.drawable.ic_fluent_earth_24_regular);
|
Drawable publicDrawable = ctx.getDrawable(R.drawable.ic_fluent_earth_24_regular);
|
||||||
@@ -258,16 +301,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
Drawable followersDrawable = ctx.getDrawable(R.drawable.ic_fluent_lock_closed_24_regular);
|
Drawable followersDrawable = ctx.getDrawable(R.drawable.ic_fluent_lock_closed_24_regular);
|
||||||
|
|
||||||
StatusPrivacy defaultVisibility = session.preferences != null ? session.preferences.postingDefaultVisibility : null;
|
StatusPrivacy defaultVisibility = session.preferences != null ? session.preferences.postingDefaultVisibility : null;
|
||||||
// e.g. post visibility is unlisted, but default is public
|
|
||||||
// in this case, we want to display the check mark on the most visible visibility
|
|
||||||
if (defaultVisibility != null && item.status.visibility.isLessVisibleThan(defaultVisibility)) {
|
|
||||||
for (StatusPrivacy vis : StatusPrivacy.values()) {
|
|
||||||
if (vis.equals(item.status.visibility)) {
|
|
||||||
defaultVisibility = vis;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
itemPublic.setCompoundDrawablesWithIntrinsicBounds(publicDrawable, null, StatusPrivacy.PUBLIC.equals(defaultVisibility) ? checkMark : null, null);
|
itemPublic.setCompoundDrawablesWithIntrinsicBounds(publicDrawable, null, StatusPrivacy.PUBLIC.equals(defaultVisibility) ? checkMark : null, null);
|
||||||
itemUnlisted.setCompoundDrawablesWithIntrinsicBounds(unlistedDrawable, null, StatusPrivacy.UNLISTED.equals(defaultVisibility) ? checkMark : null, null);
|
itemUnlisted.setCompoundDrawablesWithIntrinsicBounds(unlistedDrawable, null, StatusPrivacy.UNLISTED.equals(defaultVisibility) ? checkMark : null, null);
|
||||||
itemFollowers.setCompoundDrawablesWithIntrinsicBounds(followersDrawable, null, StatusPrivacy.PRIVATE.equals(defaultVisibility) ? checkMark : null, null);
|
itemFollowers.setCompoundDrawablesWithIntrinsicBounds(followersDrawable, null, StatusPrivacy.PRIVATE.equals(defaultVisibility) ? checkMark : null, null);
|
||||||
@@ -295,12 +328,18 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
v.startAnimation(opacityIn);
|
v.startAnimation(opacityIn);
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
|
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(item.accountID);
|
||||||
|
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(accountSession.domain);
|
||||||
|
if(instance.pleroma == null){
|
||||||
StringBuilder prefilledText = new StringBuilder().append("\n\n");
|
StringBuilder prefilledText = new StringBuilder().append("\n\n");
|
||||||
String ownID = AccountSessionManager.getInstance().getAccount(item.accountID).self.id;
|
String ownID = AccountSessionManager.getInstance().getAccount(item.accountID).self.id;
|
||||||
if (!item.status.account.id.equals(ownID)) prefilledText.append('@').append(item.status.account.acct).append(' ');
|
if (!item.status.account.id.equals(ownID)) prefilledText.append('@').append(item.status.account.acct).append(' ');
|
||||||
prefilledText.append(item.status.url);
|
prefilledText.append(item.status.url);
|
||||||
args.putString("prefilledText", prefilledText.toString());
|
args.putString("prefilledText", prefilledText.toString());
|
||||||
args.putInt("selectionStart", 0);
|
args.putInt("selectionStart", 0);
|
||||||
|
}else{
|
||||||
|
args.putParcelable("quote", Parcels.wrap(item.status));
|
||||||
|
}
|
||||||
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -309,14 +348,27 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onFavoriteClick(View v){
|
private void onFavoriteClick(View v){
|
||||||
|
if(item.status.reloadWhenClicked){
|
||||||
|
UiUtils.lookupStatus(v.getContext(),
|
||||||
|
item.status, item.accountID, null,
|
||||||
|
status -> {
|
||||||
|
favorite.setSelected(!status.favourited);
|
||||||
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(status, !status.favourited, r->{
|
||||||
|
if (status.favourited) {
|
||||||
|
v.startAnimation(GlobalUserPreferences.reduceMotion ? opacityIn : animSet);
|
||||||
|
} else {
|
||||||
|
v.startAnimation(opacityIn);
|
||||||
|
}
|
||||||
|
bindButton(favorite, r.favouritesCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
favorite.setSelected(!item.status.favourited);
|
favorite.setSelected(!item.status.favourited);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
||||||
if (item.status.favourited) {
|
if (item.status.favourited) {
|
||||||
if(GlobalUserPreferences.reduceMotion){
|
v.startAnimation(GlobalUserPreferences.reduceMotion ? opacityIn : animSet);
|
||||||
v.startAnimation(opacityIn);
|
|
||||||
}else{
|
|
||||||
v.startAnimation(animSet);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
v.startAnimation(opacityIn);
|
v.startAnimation(opacityIn);
|
||||||
}
|
}
|
||||||
@@ -339,6 +391,18 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onBookmarkClick(View v){
|
private void onBookmarkClick(View v){
|
||||||
|
if(item.status.reloadWhenClicked){
|
||||||
|
UiUtils.lookupStatus(v.getContext(),
|
||||||
|
item.status, item.accountID, null,
|
||||||
|
status -> {
|
||||||
|
bookmark.setSelected(!status.bookmarked);
|
||||||
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(status, !status.bookmarked, r->{
|
||||||
|
v.startAnimation(opacityIn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
bookmark.setSelected(!item.status.bookmarked);
|
bookmark.setSelected(!item.status.bookmarked);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
|
||||||
v.startAnimation(opacityIn);
|
v.startAnimation(opacityIn);
|
||||||
|
|||||||