Compare commits
579 Commits
v1.1.5+for
...
v1.1.5+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
64fbbb2f07 | ||
|
|
9003f690d1 | ||
|
|
8ffaca61bd | ||
|
|
f6c3b10c2b | ||
|
|
8933c0647e | ||
|
|
333c38c64d | ||
|
|
ca5827e3f8 | ||
|
|
4884667484 | ||
|
|
a2f687898c | ||
|
|
defd038064 | ||
|
|
f88b65f479 | ||
|
|
f65d56361f | ||
|
|
255155b55a | ||
|
|
ee2e39462a | ||
|
|
32b459ae77 | ||
|
|
c1b79da4a7 | ||
|
|
65dfd8667d | ||
|
|
12558c3c18 | ||
|
|
dae347a29f | ||
|
|
c51be5f199 | ||
|
|
fc1bd14f70 | ||
|
|
bd39ed3754 | ||
|
|
50029c7f73 | ||
|
|
e2c907eb10 | ||
|
|
937747e11b | ||
|
|
d68a3a6ef5 | ||
|
|
4475bd039a | ||
|
|
98dc7d0524 | ||
|
|
85b6bc79a3 | ||
|
|
65948030a6 | ||
|
|
89edfaaa6d | ||
|
|
10372804e4 | ||
|
|
ec9d41fbbd | ||
|
|
847d966daa | ||
|
|
d1dd7d203b | ||
|
|
618840c76a | ||
|
|
33d856562d | ||
|
|
9873e9ede5 | ||
|
|
c6aed0b52e | ||
|
|
63dad42bf3 | ||
|
|
dad58f8245 | ||
|
|
647a7d70cd | ||
|
|
f49c7dff00 | ||
|
|
72f638c96c | ||
|
|
5f902d25a9 | ||
|
|
c43bed665d | ||
|
|
d70a2ae5b3 | ||
|
|
1fdf36b4d8 | ||
|
|
35e0897869 | ||
|
|
e22cb07d63 | ||
|
|
5d1cd0f4f6 | ||
|
|
c2df989217 | ||
|
|
31d0bfb434 | ||
|
|
14e639aa8a | ||
|
|
6c24e06157 | ||
|
|
53ce4276f6 | ||
|
|
423e919e16 | ||
|
|
3505460372 | ||
|
|
eeb91e867e | ||
|
|
c87062ee31 | ||
|
|
fb66fa1c6f | ||
|
|
f80af9f5bf | ||
|
|
85157ffe25 | ||
|
|
59f95159b7 | ||
|
|
c6cd424f30 | ||
|
|
703dbd4c8a | ||
|
|
e282d54f99 | ||
|
|
29ad08f2ea | ||
|
|
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 | ||
|
|
5c2f72a706 | ||
|
|
b153a64373 | ||
|
|
5452da6a65 | ||
|
|
ffb321e36f | ||
|
|
eaecff52c9 | ||
|
|
b141a9ac74 | ||
|
|
a890f21ace | ||
|
|
4e72e5c234 | ||
|
|
1def56057a | ||
|
|
d99f6c7167 | ||
|
|
0d5d169e5f | ||
|
|
90e55c1043 | ||
|
|
780c5c345c | ||
|
|
c2bc0a4055 | ||
|
|
1124486f1f | ||
|
|
8032de4595 | ||
|
|
bd3f5018ed | ||
|
|
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 | ||
|
|
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 | ||
|
|
8788fb0b27 | ||
|
|
62d4c62888 | ||
|
|
572d092f88 | ||
|
|
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 |
@@ -16,4 +16,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
android.enableJetifier=false
|
||||
@@ -9,8 +9,8 @@ android {
|
||||
applicationId "org.joinmastodon.android.sk"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 74
|
||||
versionName "1.1.5+fork.74"
|
||||
versionCode 76
|
||||
versionName "1.1.5+fork.76"
|
||||
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"
|
||||
}
|
||||
@@ -70,6 +70,7 @@ dependencies {
|
||||
implementation 'com.squareup:otto:1.3.8'
|
||||
implementation 'de.psdev:async-otto:1.0.3'
|
||||
implementation 'org.parceler:parceler-api:1.1.12'
|
||||
implementation 'com.github.bottom-software-foundation:bottom-java:2.1.0'
|
||||
annotationProcessor 'org.parceler:parceler:1.1.12'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ public class GlobalUserPreferences{
|
||||
public static boolean showAltIndicator;
|
||||
public static boolean showNoAltIndicator;
|
||||
public static boolean enablePreReleases;
|
||||
public static boolean prefixRepliesWithRe;
|
||||
public static boolean bottomEncoding;
|
||||
public static boolean collapseLongPosts;
|
||||
public static boolean spectatorMode;
|
||||
public static String publishButtonText;
|
||||
public static ThemePreference theme;
|
||||
public static ColorPreference color;
|
||||
@@ -83,6 +87,10 @@ public class GlobalUserPreferences{
|
||||
showAltIndicator=prefs.getBoolean("showAltIndicator", true);
|
||||
showNoAltIndicator=prefs.getBoolean("showNoAltIndicator", true);
|
||||
enablePreReleases=prefs.getBoolean("enablePreReleases", false);
|
||||
prefixRepliesWithRe=prefs.getBoolean("prefixRepliesWithRe", false);
|
||||
bottomEncoding=prefs.getBoolean("bottomEncoding", false);
|
||||
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
|
||||
spectatorMode=prefs.getBoolean("spectatorMode", false);
|
||||
publishButtonText=prefs.getString("publishButtonText", "");
|
||||
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
|
||||
recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new HashMap<>());
|
||||
@@ -120,7 +128,11 @@ public class GlobalUserPreferences{
|
||||
.putBoolean("showAltIndicator", showAltIndicator)
|
||||
.putBoolean("showNoAltIndicator", showNoAltIndicator)
|
||||
.putBoolean("enablePreReleases", enablePreReleases)
|
||||
.putBoolean("prefixRepliesWithRe", prefixRepliesWithRe)
|
||||
.putBoolean("collapseLongPosts", collapseLongPosts)
|
||||
.putBoolean("spectatorMode", spectatorMode)
|
||||
.putString("publishButtonText", publishButtonText)
|
||||
.putBoolean("bottomEncoding", bottomEncoding)
|
||||
.putInt("theme", theme.ordinal())
|
||||
.putString("color", color.name())
|
||||
.putString("recentLanguages", gson.toJson(recentLanguages))
|
||||
|
||||
@@ -154,6 +154,7 @@ public class MainActivity extends FragmentStackActivity{
|
||||
);
|
||||
Bundle currentArgs = currentFragment.getArguments();
|
||||
if (this.fragmentContainers.size() == 1
|
||||
&& currentArgs != null
|
||||
&& currentArgs.getBoolean("_can_go_back", false)
|
||||
&& currentArgs.containsKey("account")) {
|
||||
Bundle args = new Bundle();
|
||||
|
||||
@@ -4,6 +4,10 @@ import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
|
||||
public class SetAccountFollowed extends MastodonAPIRequest<Relationship>{
|
||||
public SetAccountFollowed(String id, boolean followed, boolean showReblogs){
|
||||
this(id, followed, showReblogs, false);
|
||||
}
|
||||
|
||||
public SetAccountFollowed(String id, boolean followed, boolean showReblogs, boolean notify){
|
||||
super(HttpMethod.POST, "/accounts/"+id+"/"+(followed ? "follow" : "unfollow"), Relationship.class);
|
||||
if(followed)
|
||||
|
||||
@@ -11,12 +11,15 @@ import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
@@ -57,6 +60,7 @@ public class AccountTimelineFragment extends StatusListFragment{
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(getActivity()==null) return;
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.ACCOUNT)).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,6 +16,7 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
@@ -40,6 +41,7 @@ import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
@@ -56,6 +58,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
@@ -74,9 +78,15 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||
protected Rect tmpRect=new Rect();
|
||||
protected ImageButton fab;
|
||||
|
||||
public BaseStatusListFragment(){
|
||||
super(20);
|
||||
if (withComposeButton()) setListLayoutId(R.layout.recycler_fragment_with_fab);
|
||||
}
|
||||
|
||||
protected boolean withComposeButton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,6 +100,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter getAdapter(){
|
||||
return adapter=new DisplayItemsAdapter();
|
||||
@@ -313,6 +325,13 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
list.setItemAnimator(new BetterItemAnimator());
|
||||
((UsableRecyclerView) list).setIncludeMarginsInItemHitbox(true);
|
||||
updateToolbar();
|
||||
|
||||
if (withComposeButton()) {
|
||||
fab = view.findViewById(R.id.fab);
|
||||
fab.setVisibility(View.VISIBLE);
|
||||
fab.setOnClickListener(this::onFabClick);
|
||||
fab.setOnLongClickListener(this::onFabLongClick);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -478,7 +497,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
Status status=holder.getItem().status;
|
||||
status.spoilerRevealed=!status.spoilerRevealed;
|
||||
if(!TextUtils.isEmpty(status.spoilerText)){
|
||||
TextStatusDisplayItem.Holder text=findHolderOfType(holder.getItemID(), TextStatusDisplayItem.Holder.class);
|
||||
TextStatusDisplayItem.Holder text = findHolderOfType(holder.getItemID(), TextStatusDisplayItem.Holder.class);
|
||||
if(text!=null){
|
||||
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition());
|
||||
}
|
||||
@@ -487,6 +506,23 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
updateImagesSpoilerState(status, holder.getItemID());
|
||||
}
|
||||
|
||||
public void onEnableExpandable(TextStatusDisplayItem.Holder holder, boolean expandable) {
|
||||
if (holder.getItem().status.textExpandable != expandable && list != null) {
|
||||
holder.getItem().status.textExpandable = expandable;
|
||||
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
||||
if (header != null) header.rebind();
|
||||
holder.rebind();
|
||||
}
|
||||
}
|
||||
|
||||
public void onToggleExpanded(Status status, String itemID) {
|
||||
status.textExpanded = !status.textExpanded;
|
||||
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
|
||||
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
|
||||
if (text != null) text.rebind();
|
||||
if (header != null) header.rebind();
|
||||
}
|
||||
|
||||
protected void updateImagesSpoilerState(Status status, String itemID){
|
||||
ArrayList<Integer> updatedPositions=new ArrayList<>();
|
||||
for(ImageStatusDisplayItem.Holder photo:(List<ImageStatusDisplayItem.Holder>)findAllHoldersOfType(itemID, ImageStatusDisplayItem.Holder.class)){
|
||||
@@ -504,6 +540,15 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
|
||||
public void onGapClick(GapStatusDisplayItem.Holder item){}
|
||||
|
||||
public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warning){
|
||||
int startPos = warning.getAbsoluteAdapterPosition();
|
||||
displayItems.remove(startPos);
|
||||
displayItems.addAll(startPos, warning.filteredItems);
|
||||
adapter.notifyItemRangeInserted(startPos, warning.filteredItems.size() - 1);
|
||||
if (startPos == 0) scrollToTop();
|
||||
warning.getItem().status.filterRevealed = true;
|
||||
}
|
||||
|
||||
public String getAccountID(){
|
||||
return accountID;
|
||||
}
|
||||
@@ -619,6 +664,16 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
currentPhotoViewer.onPause();
|
||||
}
|
||||
|
||||
protected void onFabClick(View v){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
Nav.go(getActivity(), ComposeFragment.class, args);
|
||||
}
|
||||
|
||||
protected boolean onFabLongClick(View v) {
|
||||
return UiUtils.pickAccountForCompose(getActivity(), accountID);
|
||||
}
|
||||
|
||||
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
||||
|
||||
public DisplayItemsAdapter(){
|
||||
|
||||
@@ -3,9 +3,9 @@ package org.joinmastodon.android.fragments;
|
||||
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
|
||||
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.DRAFTS_AFTER_INSTANT;
|
||||
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.getDraftInstant;
|
||||
import static org.joinmastodon.android.ui.utils.UiUtils.isPhotoPickerAvailable;
|
||||
import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages;
|
||||
import static org.joinmastodon.android.utils.MastodonLanguage.defaultRecentLanguages;
|
||||
import static android.os.ext.SdkExtensions.getExtensionVersion;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
@@ -42,6 +42,7 @@ import android.text.TextWatcher;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@@ -66,6 +67,7 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.bottomSoftwareFoundation.bottom.Bottom;
|
||||
import com.twitter.twittertext.TwitterTextEmojiRegex;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
@@ -115,6 +117,7 @@ import org.joinmastodon.android.ui.views.LinkedTextView;
|
||||
import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
|
||||
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
|
||||
import org.joinmastodon.android.utils.MastodonLanguage;
|
||||
import org.joinmastodon.android.utils.StatusTextEncoder;
|
||||
import org.parceler.Parcel;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
@@ -155,11 +158,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private static final Pattern GLITCH_LOCAL_ONLY_PATTERN = Pattern.compile("[\\s\\S]*" + GLITCH_LOCAL_ONLY_SUFFIX + "[\uFE00-\uFE0F]*");
|
||||
private static final String TAG="ComposeFragment";
|
||||
|
||||
private static final Pattern MENTION_PATTERN=Pattern.compile("(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)", Pattern.CASE_INSENSITIVE);
|
||||
public static final Pattern MENTION_PATTERN=Pattern.compile("(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
// from https://github.com/mastodon/mastodon-ios/blob/main/Mastodon/Helper/MastodonRegex.swift
|
||||
private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))");
|
||||
private static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))");
|
||||
public static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))");
|
||||
public static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))");
|
||||
|
||||
@SuppressLint("NewApi") // this class actually exists on 6.0
|
||||
private final BreakIterator breakIterator=BreakIterator.getCharacterInstance();
|
||||
@@ -229,7 +232,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private boolean ignoreSelectionChanges=false;
|
||||
private Runnable updateUploadEtaRunnable;
|
||||
|
||||
private String language;
|
||||
private String language, encoding;
|
||||
private MastodonLanguage.LanguageResolver languageResolver;
|
||||
|
||||
@Override
|
||||
@@ -710,7 +713,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
if(!TextUtils.isEmpty(replyTo.spoilerText)){
|
||||
hasSpoiler=true;
|
||||
spoilerEdit.setVisibility(View.VISIBLE);
|
||||
spoilerEdit.setText(replyTo.spoilerText);
|
||||
if(GlobalUserPreferences.prefixRepliesWithRe && !replyTo.spoilerText.startsWith("re: ")){
|
||||
spoilerEdit.setText("re: " + replyTo.spoilerText);
|
||||
}else{
|
||||
spoilerEdit.setText(replyTo.spoilerText);
|
||||
}
|
||||
spoilerBtn.setSelected(true);
|
||||
}
|
||||
if (replyTo.language != null && !replyTo.language.isEmpty()) updateLanguage(replyTo.language);
|
||||
@@ -835,9 +842,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
}
|
||||
|
||||
private void updateLanguage(MastodonLanguage loc) {
|
||||
language = loc.getLanguage();
|
||||
languageButton.setText(loc.getLanguageName());
|
||||
languageButton.setContentDescription(getActivity().getString(R.string.sk_post_language, loc.getDefaultName()));
|
||||
updateLanguage(loc.getLanguage(), loc.getLanguageName(), loc.getDefaultName());
|
||||
}
|
||||
|
||||
private void updateLanguage(String languageTag, String languageName, String defaultName) {
|
||||
language = languageTag;
|
||||
languageButton.setText(languageName);
|
||||
languageButton.setContentDescription(getActivity().getString(R.string.sk_post_language, defaultName));
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@@ -854,8 +865,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
|
||||
Menu languageMenu = languagePopup.getMenu();
|
||||
for (String recentLanguage : Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages)) {
|
||||
MastodonLanguage l = languageResolver.from(recentLanguage);
|
||||
languageMenu.add(0, allLanguages.indexOf(l), Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
|
||||
if (recentLanguage.equals("bottom")) {
|
||||
addBottomLanguage(languageMenu);
|
||||
} else {
|
||||
MastodonLanguage l = languageResolver.from(recentLanguage);
|
||||
languageMenu.add(0, allLanguages.indexOf(l), Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
|
||||
}
|
||||
}
|
||||
|
||||
SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.sk_available_languages);
|
||||
@@ -864,13 +879,33 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
allLanguagesMenu.add(0, i, Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
|
||||
}
|
||||
|
||||
if (GlobalUserPreferences.bottomEncoding) addBottomLanguage(allLanguagesMenu);
|
||||
|
||||
btn.setOnLongClickListener(v->{
|
||||
btn.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
if (!GlobalUserPreferences.bottomEncoding) addBottomLanguage(allLanguagesMenu);
|
||||
return false;
|
||||
});
|
||||
|
||||
languagePopup.setOnMenuItemClickListener(i->{
|
||||
if (i.hasSubMenu()) return false;
|
||||
updateLanguage(allLanguages.get(i.getItemId()));
|
||||
if (i.getItemId() == allLanguages.size()) {
|
||||
updateLanguage(language, "\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48", "bottom");
|
||||
encoding = "bottom";
|
||||
} else {
|
||||
updateLanguage(allLanguages.get(i.getItemId()));
|
||||
encoding = null;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void addBottomLanguage(Menu menu) {
|
||||
if (menu.findItem(allLanguages.size()) == null) {
|
||||
menu.add(0, allLanguages.size(), Menu.NONE, "bottom (\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48)");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item){
|
||||
return true;
|
||||
@@ -995,6 +1030,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private void publish(boolean force){
|
||||
String text=mainEditText.getText().toString();
|
||||
CreateStatus.Request req=new CreateStatus.Request();
|
||||
if ("bottom".equals(encoding)) {
|
||||
text = new StatusTextEncoder(Bottom::encode).encode(text);
|
||||
req.spoilerText = "bottom-encoded emoji spam";
|
||||
}
|
||||
if (localOnly &&
|
||||
GlobalUserPreferences.accountsInGlitchMode.contains(accountID) &&
|
||||
!GLITCH_LOCAL_ONLY_PATTERN.matcher(text).matches()) {
|
||||
@@ -1136,6 +1175,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
List<String> newRecentLanguages = new ArrayList<>(Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages));
|
||||
newRecentLanguages.remove(language);
|
||||
newRecentLanguages.add(0, language);
|
||||
if (encoding != null) {
|
||||
newRecentLanguages.remove(encoding);
|
||||
newRecentLanguages.add(0, encoding);
|
||||
}
|
||||
if ("bottom".equals(encoding) && !GlobalUserPreferences.bottomEncoding) {
|
||||
GlobalUserPreferences.bottomEncoding = true;
|
||||
GlobalUserPreferences.save();
|
||||
}
|
||||
recentLanguages.put(accountID, newRecentLanguages.stream().limit(4).collect(Collectors.toList()));
|
||||
GlobalUserPreferences.save();
|
||||
}
|
||||
@@ -1201,7 +1248,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
}
|
||||
|
||||
private void confirmDiscardDraftAndFinish(){
|
||||
new M3AlertDialogBuilder(getActivity())
|
||||
boolean attachmentsPending = attachments.stream().anyMatch(att -> att.state != AttachmentUploadState.DONE);
|
||||
if (attachmentsPending) new M3AlertDialogBuilder(getActivity())
|
||||
.setTitle(R.string.sk_unfinished_attachments)
|
||||
.setMessage(R.string.sk_unfinished_attachments_message)
|
||||
.setPositiveButton(R.string.edit, (d, w) -> {})
|
||||
.setNegativeButton(R.string.discard, (d, w) -> Nav.finish(this))
|
||||
.show();
|
||||
else new M3AlertDialogBuilder(getActivity())
|
||||
.setTitle(editingStatus != null ? R.string.sk_confirm_save_changes : R.string.sk_confirm_save_draft)
|
||||
.setPositiveButton(R.string.save, (d, w) -> {
|
||||
updateScheduledAt(scheduledAt == null ? getDraftInstant() : scheduledAt);
|
||||
@@ -1211,18 +1265,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if Android platform photopicker is available on the device\
|
||||
* @return whether the device supports photopicker intents.
|
||||
*/
|
||||
private boolean isPhotoPickerAvailable() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return true;
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
return getExtensionVersion(Build.VERSION_CODES.R) >= 2;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the correct intent for the device version to select media.
|
||||
@@ -1234,24 +1276,24 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
*/
|
||||
private void openFilePicker(boolean photoPicker){
|
||||
Intent intent;
|
||||
boolean usePhotoPicker = photoPicker && isPhotoPickerAvailable();
|
||||
if (usePhotoPicker) {
|
||||
intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
|
||||
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
|
||||
} else {
|
||||
intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
boolean usePhotoPicker=photoPicker && isPhotoPickerAvailable();
|
||||
if(usePhotoPicker){
|
||||
intent=new Intent(MediaStore.ACTION_PICK_IMAGES);
|
||||
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MAX_ATTACHMENTS-getMediaAttachmentsCount());
|
||||
}else{
|
||||
intent=new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
}
|
||||
if (!usePhotoPicker && instance.configuration != null &&
|
||||
instance.configuration.mediaAttachments != null &&
|
||||
instance.configuration.mediaAttachments.supportedMimeTypes != null &&
|
||||
!instance.configuration.mediaAttachments.supportedMimeTypes.isEmpty()) {
|
||||
if(!usePhotoPicker && instance.configuration!=null &&
|
||||
instance.configuration.mediaAttachments!=null &&
|
||||
instance.configuration.mediaAttachments.supportedMimeTypes!=null &&
|
||||
!instance.configuration.mediaAttachments.supportedMimeTypes.isEmpty()){
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES,
|
||||
instance.configuration.mediaAttachments.supportedMimeTypes.toArray(
|
||||
new String[0]));
|
||||
} else {
|
||||
if (!usePhotoPicker) {
|
||||
}else{
|
||||
if(!usePhotoPicker){
|
||||
// If photo picker is being used these are the default mimetypes.
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"});
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
|
||||
public abstract class FabStatusListFragment extends StatusListFragment {
|
||||
protected ImageButton fab;
|
||||
|
||||
public FabStatusListFragment() {
|
||||
setListLayoutId(R.layout.recycler_fragment_with_fab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
fab = view.findViewById(R.id.fab);
|
||||
fab.setOnClickListener(this::onFabClick);
|
||||
fab.setOnLongClickListener(this::onFabLongClick);
|
||||
}
|
||||
|
||||
protected void onFabClick(View v){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
Nav.go(getActivity(), ComposeFragment.class, args);
|
||||
}
|
||||
|
||||
protected boolean onFabLongClick(View v) {
|
||||
return UiUtils.pickAccountForCompose(getActivity(), accountID);
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,15 @@ import org.joinmastodon.android.api.requests.tags.GetHashtag;
|
||||
import org.joinmastodon.android.api.requests.tags.SetHashtagFollowed;
|
||||
import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline;
|
||||
import org.joinmastodon.android.events.HashtagUpdatedEvent;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Hashtag;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.TimelineDefinition;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
@@ -33,11 +36,11 @@ import me.grishka.appkit.utils.V;
|
||||
public class HashtagTimelineFragment extends PinnableStatusListFragment {
|
||||
private String hashtag;
|
||||
private boolean following;
|
||||
private ImageButton fab;
|
||||
private MenuItem followButton;
|
||||
|
||||
public HashtagTimelineFragment(){
|
||||
setListLayoutId(R.layout.recycler_fragment_with_fab);
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,6 +123,7 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if (getActivity() == null) return;
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
@@ -134,14 +138,12 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
fab=view.findViewById(R.id.fab);
|
||||
fab.setOnClickListener(this::onFabClick);
|
||||
fab.setOnLongClickListener(v -> UiUtils.pickAccountForCompose(getActivity(), accountID, '#'+hashtag+' '));
|
||||
protected boolean onFabLongClick(View v) {
|
||||
return UiUtils.pickAccountForCompose(getActivity(), accountID, '#'+hashtag+' ');
|
||||
}
|
||||
|
||||
private void onFabClick(View v){
|
||||
@Override
|
||||
protected void onFabClick(View v){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putString("prefilledText", '#'+hashtag+' ');
|
||||
|
||||
@@ -16,12 +16,10 @@ import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.joinmastodon.android.PushNotificationReceiver;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
|
||||
import org.joinmastodon.android.fragments.discover.SearchFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
@@ -375,7 +375,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
||||
}
|
||||
|
||||
private <T> void updateList(List<T> addItems, Map<Integer, T> items) {
|
||||
if (addItems.size() == 0) return;
|
||||
if (addItems.size() == 0 || getActivity() == null) return;
|
||||
for (int i = 0; i < addItems.size(); i++) items.put(View.generateViewId(), addItems.get(i));
|
||||
updateOverflowMenu();
|
||||
}
|
||||
@@ -662,7 +662,8 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
||||
@Override
|
||||
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
FrameLayout tabView = tabViews[viewType % getItemCount()];
|
||||
((ViewGroup)tabView.getParent()).removeView(tabView);
|
||||
ViewGroup tabParent = (ViewGroup) tabView.getParent();
|
||||
if (tabParent != null) tabParent.removeView(tabView);
|
||||
tabView.setVisibility(View.VISIBLE);
|
||||
return new SimpleViewHolder(tabView);
|
||||
}
|
||||
|
||||
@@ -32,11 +32,16 @@ import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class HomeTimelineFragment extends FabStatusListFragment {
|
||||
public class HomeTimelineFragment extends StatusListFragment {
|
||||
private HomeTabFragment parent;
|
||||
private String maxID;
|
||||
private String lastSavedMarkerID;
|
||||
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
|
||||
@@ -18,14 +18,17 @@ import org.joinmastodon.android.api.requests.lists.UpdateList;
|
||||
import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
|
||||
import org.joinmastodon.android.events.ListDeletedEvent;
|
||||
import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.ListTimeline;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.TimelineDefinition;
|
||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.ListTimelineEditor;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
@@ -39,10 +42,10 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
||||
private String listTitle;
|
||||
@Nullable
|
||||
private ListTimeline.RepliesPolicy repliesPolicy;
|
||||
private ImageButton fab;
|
||||
|
||||
public ListTimelineFragment() {
|
||||
setListLayoutId(R.layout.recycler_fragment_with_fab);
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,10 +137,11 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
||||
@Override
|
||||
public void onSuccess(List<Status> result) {
|
||||
if (getActivity() == null) return;
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.HOME)).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,14 +152,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
fab=view.findViewById(R.id.fab);
|
||||
fab.setOnClickListener(this::onFabClick);
|
||||
fab.setOnLongClickListener(v -> UiUtils.pickAccountForCompose(getActivity(), accountID));
|
||||
}
|
||||
|
||||
private void onFabClick(View v){
|
||||
protected void onFabClick(View v){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
Nav.go(getActivity(), ComposeFragment.class, args);
|
||||
|
||||
@@ -99,7 +99,6 @@ public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> im
|
||||
new CreateList(editor.getTitle(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(ListTimeline list) {
|
||||
saveListMembership(list.id, true);
|
||||
data.add(0, list);
|
||||
adapter.notifyItemRangeInserted(0, 1);
|
||||
E.post(new ListUpdatedCreatedEvent(list.id, list.title, list.repliesPolicy));
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Notification;
|
||||
import org.joinmastodon.android.model.PaginatedResponse;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -47,6 +48,11 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
||||
private String maxID;
|
||||
private final DiscoverInfoBannerHelper bannerHelper = new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.POST_NOTIFICATIONS);
|
||||
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -91,7 +97,7 @@ 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;
|
||||
if(n.status!=null){
|
||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n);
|
||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS, titleItem);
|
||||
if(titleItem!=null){
|
||||
for(StatusDisplayItem item:items){
|
||||
if(item instanceof ImageStatusDisplayItem imgItem){
|
||||
@@ -99,8 +105,6 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
||||
}
|
||||
}
|
||||
}
|
||||
if(titleItem!=null)
|
||||
items.add(0, titleItem);
|
||||
return items;
|
||||
}else if(titleItem!=null){
|
||||
AccountCardStatusDisplayItem card=new AccountCardStatusDisplayItem(n.id, this,
|
||||
@@ -192,6 +196,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
list.addItemDecoration(new InsetStatusItemDecoration(this));
|
||||
if (getParentFragment() instanceof NotificationsFragment) fab.setVisibility(View.GONE);
|
||||
if (onlyPosts) bannerHelper.maybeAddBanner(contentWrap);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import static android.content.Context.CLIPBOARD_SERVICE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ImageSpan;
|
||||
@@ -34,15 +29,14 @@ import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
@@ -61,6 +55,7 @@ import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.AccountField;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
import org.joinmastodon.android.ui.BetterItemAnimator;
|
||||
import org.joinmastodon.android.ui.SimpleViewHolder;
|
||||
import org.joinmastodon.android.ui.SingleImagePhotoViewerListener;
|
||||
import org.joinmastodon.android.ui.drawables.CoverOverlayGradientDrawable;
|
||||
@@ -69,8 +64,10 @@ import org.joinmastodon.android.ui.tabs.TabLayout;
|
||||
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
||||
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.CoverImageView;
|
||||
import org.joinmastodon.android.ui.views.LinkedTextView;
|
||||
import org.joinmastodon.android.ui.views.NestedRecyclerScrollView;
|
||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||
import org.parceler.Parcels;
|
||||
@@ -84,6 +81,9 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
@@ -94,10 +94,17 @@ import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.fragments.LoaderFragment;
|
||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
||||
import me.grishka.appkit.imageloader.RecyclerViewDelegate;
|
||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class ProfileFragment extends LoaderFragment implements OnBackPressedListener, ScrollableToTop{
|
||||
private static final int AVATAR_RESULT=722;
|
||||
@@ -105,23 +112,24 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
|
||||
private ImageView avatar;
|
||||
private CoverImageView cover;
|
||||
private View avatarBorder;
|
||||
private View avatarBorder, nameWrap;
|
||||
private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel, postsCount, postsLabel;
|
||||
private ProgressBarButton actionButton, notifyButton;
|
||||
private ViewPager2 pager;
|
||||
private NestedRecyclerScrollView scrollView;
|
||||
private AccountTimelineFragment postsFragment, postsWithRepliesFragment, pinnedPostsFragment, mediaFragment;
|
||||
private ProfileAboutFragment aboutFragment;
|
||||
// private ProfileAboutFragment aboutFragment;
|
||||
private TabLayout tabbar;
|
||||
private SwipeRefreshLayout refreshLayout;
|
||||
private CoverOverlayGradientDrawable coverGradient=new CoverOverlayGradientDrawable();
|
||||
private float titleTransY;
|
||||
private View postsBtn, followersBtn, followingBtn;
|
||||
private View postsBtn, followersBtn, followingBtn, profileCounters;
|
||||
private EditText nameEdit, bioEdit;
|
||||
private ProgressBar actionProgress, notifyProgress;
|
||||
private FrameLayout[] tabViews;
|
||||
private TabLayoutMediator tabLayoutMediator;
|
||||
private TextView followsYouView;
|
||||
private ViewGroup rolesView;
|
||||
|
||||
private Account account;
|
||||
private String accountID;
|
||||
@@ -139,6 +147,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
private PhotoViewer currentPhotoViewer;
|
||||
private boolean editModeLoading;
|
||||
|
||||
private static final int MAX_FIELDS=4;
|
||||
|
||||
// from ProfileAboutFragment
|
||||
public UsableRecyclerView list;
|
||||
private List<AccountField> metadataListData=Collections.emptyList();
|
||||
private MetadataAdapter adapter;
|
||||
private ItemTouchHelper dragHelper=new ItemTouchHelper(new ReorderCallback());
|
||||
private RecyclerView.ViewHolder draggedViewHolder;
|
||||
private ListImageLoaderWrapper imgLoader;
|
||||
|
||||
public ProfileFragment(){
|
||||
super(R.layout.loader_fragment_overlay_toolbar);
|
||||
}
|
||||
@@ -183,8 +201,10 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
cover=content.findViewById(R.id.cover);
|
||||
avatarBorder=content.findViewById(R.id.avatar_border);
|
||||
name=content.findViewById(R.id.name);
|
||||
nameWrap=content.findViewById(R.id.name_wrap);
|
||||
username=content.findViewById(R.id.username);
|
||||
bio=content.findViewById(R.id.bio);
|
||||
profileCounters=content.findViewById(R.id.profile_counters);
|
||||
followersCount=content.findViewById(R.id.followers_count);
|
||||
followersLabel=content.findViewById(R.id.followers_label);
|
||||
followersBtn=content.findViewById(R.id.followers_btn);
|
||||
@@ -206,6 +226,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
notifyProgress=content.findViewById(R.id.notify_progress);
|
||||
fab=content.findViewById(R.id.fab);
|
||||
followsYouView=content.findViewById(R.id.follows_you);
|
||||
list=content.findViewById(R.id.metadata);
|
||||
rolesView=content.findViewById(R.id.roles);
|
||||
|
||||
avatar.setOutlineProvider(new ViewOutlineProvider(){
|
||||
@Override
|
||||
@@ -225,7 +247,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
}
|
||||
};
|
||||
|
||||
tabViews=new FrameLayout[5];
|
||||
tabViews=new FrameLayout[4];
|
||||
for(int i=0;i<tabViews.length;i++){
|
||||
FrameLayout tabView=new FrameLayout(getActivity());
|
||||
tabView.setId(switch(i){
|
||||
@@ -242,7 +264,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
}
|
||||
|
||||
UiUtils.reduceSwipeSensitivity(pager);
|
||||
pager.setOffscreenPageLimit(5);
|
||||
pager.setOffscreenPageLimit(4);
|
||||
pager.setUserInputEnabled(!GlobalUserPreferences.disableSwipe);
|
||||
pager.setAdapter(new ProfilePagerAdapter());
|
||||
pager.getLayoutParams().height=getResources().getDisplayMetrics().heightPixels;
|
||||
@@ -303,6 +325,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
return true;
|
||||
});
|
||||
|
||||
// from ProfileAboutFragment
|
||||
list.setItemAnimator(new BetterItemAnimator());
|
||||
list.setDrawSelectorOnTop(true);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
imgLoader=new ListImageLoaderWrapper(getActivity(), list, new RecyclerViewDelegate(list), null);
|
||||
list.setAdapter(adapter=new MetadataAdapter());
|
||||
list.setClipToPadding(false);
|
||||
|
||||
return sizeWrapper;
|
||||
}
|
||||
|
||||
@@ -358,8 +388,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
postsWithRepliesFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.INCLUDE_REPLIES, false);
|
||||
pinnedPostsFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.PINNED, false);
|
||||
mediaFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.MEDIA, false);
|
||||
aboutFragment=new ProfileAboutFragment();
|
||||
aboutFragment.setFields(fields);
|
||||
// aboutFragment=new ProfileAboutFragment();
|
||||
setFields(fields);
|
||||
}
|
||||
pager.getAdapter().notifyDataSetChanged();
|
||||
super.dataLoaded();
|
||||
@@ -452,6 +482,19 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
name.setText(ssb);
|
||||
setTitle(ssb);
|
||||
|
||||
if (account.roles != null && !account.roles.isEmpty()) {
|
||||
rolesView.setVisibility(View.VISIBLE);
|
||||
rolesView.removeAllViews();
|
||||
name.setPadding(0, 0, V.dp(12), 0);
|
||||
for (Account.Role role : account.roles) {
|
||||
TextView roleText = new TextView(getActivity(), null, 0, R.style.role_label);
|
||||
roleText.setText(role.name);
|
||||
GradientDrawable bg = (GradientDrawable) roleText.getBackground().mutate();
|
||||
bg.setStroke(V.dp(2), Color.parseColor(role.color));
|
||||
rolesView.addView(roleText);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSelf=AccountSessionManager.getInstance().isSelf(accountID, account);
|
||||
|
||||
if(account.locked){
|
||||
@@ -519,9 +562,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
fields.add(field);
|
||||
}
|
||||
|
||||
if(aboutFragment!=null){
|
||||
aboutFragment.setFields(fields);
|
||||
}
|
||||
setFields(fields);
|
||||
}
|
||||
|
||||
private void updateToolbar(){
|
||||
@@ -713,8 +754,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
coverGradient.setTopOffset(scrollY);
|
||||
cover.invalidate();
|
||||
titleTransY=getToolbar().getHeight();
|
||||
if(scrollY>name.getTop()-topBarsH){
|
||||
titleTransY=Math.max(0f, titleTransY-(scrollY-(name.getTop()-topBarsH)));
|
||||
if(scrollY>nameWrap.getTop()-topBarsH){
|
||||
titleTransY=Math.max(0f, titleTransY-(scrollY-(nameWrap.getTop()-topBarsH)));
|
||||
}
|
||||
if(toolbarTitleView!=null){
|
||||
toolbarTitleView.setTranslationY(titleTransY);
|
||||
@@ -731,7 +772,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
case 1 -> postsWithRepliesFragment;
|
||||
case 2 -> pinnedPostsFragment;
|
||||
case 3 -> mediaFragment;
|
||||
case 4 -> aboutFragment;
|
||||
// case 4 -> aboutFragment;
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
@@ -796,16 +837,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
invalidateOptionsMenu();
|
||||
pager.setUserInputEnabled(false);
|
||||
actionButton.setText(R.string.done);
|
||||
pager.setCurrentItem(4);
|
||||
ArrayList<Animator> animators=new ArrayList<>();
|
||||
for(int i=0;i<tabViews.length-1;i++){
|
||||
animators.add(ObjectAnimator.ofFloat(tabbar.getTabAt(i).view, View.ALPHA, .3f));
|
||||
tabbar.getTabAt(i).view.setEnabled(false);
|
||||
}
|
||||
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);
|
||||
animators.add(ObjectAnimator.ofInt(overlay, "alpha", 0, 255));
|
||||
|
||||
nameWrap.setVisibility(View.GONE);
|
||||
nameEdit.setVisibility(View.VISIBLE);
|
||||
nameEdit.setText(account.displayName);
|
||||
RelativeLayout.LayoutParams lp=(RelativeLayout.LayoutParams) username.getLayoutParams();
|
||||
@@ -817,10 +854,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
bioEdit.setText(account.source.note);
|
||||
animators.add(ObjectAnimator.ofFloat(bioEdit, View.ALPHA, 0f, 1f));
|
||||
animators.add(ObjectAnimator.ofFloat(bio, View.ALPHA, 0f));
|
||||
|
||||
animators.add(ObjectAnimator.ofFloat(postsBtn, View.ALPHA, .3f));
|
||||
animators.add(ObjectAnimator.ofFloat(followersBtn, View.ALPHA, .3f));
|
||||
animators.add(ObjectAnimator.ofFloat(followingBtn, View.ALPHA, .3f));
|
||||
profileCounters.setVisibility(View.GONE);
|
||||
pager.setVisibility(View.GONE);
|
||||
tabbar.setVisibility(View.GONE);
|
||||
|
||||
AnimatorSet set=new AnimatorSet();
|
||||
set.playTogether(animators);
|
||||
@@ -828,7 +864,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
set.start();
|
||||
|
||||
aboutFragment.enterEditMode(account.source.fields);
|
||||
// aboutFragment.enterEditMode(account.source.fields);
|
||||
|
||||
V.setVisibilityAnimated(fab, View.GONE);
|
||||
metadataListData=account.source.fields;
|
||||
adapter.notifyDataSetChanged();
|
||||
dragHelper.attachToRecyclerView(list);
|
||||
}
|
||||
|
||||
private void exitEditMode(){
|
||||
@@ -839,16 +880,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
invalidateOptionsMenu();
|
||||
ArrayList<Animator> animators=new ArrayList<>();
|
||||
actionButton.setText(R.string.edit_profile);
|
||||
for(int i=0;i<tabViews.length-1;i++){
|
||||
animators.add(ObjectAnimator.ofFloat(tabbar.getTabAt(i).view, View.ALPHA, 1f));
|
||||
}
|
||||
animators.add(ObjectAnimator.ofInt(avatar.getForeground(), "alpha", 0));
|
||||
animators.add(ObjectAnimator.ofFloat(nameEdit, View.ALPHA, 0f));
|
||||
animators.add(ObjectAnimator.ofFloat(bioEdit, View.ALPHA, 0f));
|
||||
animators.add(ObjectAnimator.ofFloat(bio, View.ALPHA, 1f));
|
||||
animators.add(ObjectAnimator.ofFloat(postsBtn, View.ALPHA, 1f));
|
||||
animators.add(ObjectAnimator.ofFloat(followersBtn, View.ALPHA, 1f));
|
||||
animators.add(ObjectAnimator.ofFloat(followingBtn, View.ALPHA, 1f));
|
||||
profileCounters.setVisibility(View.VISIBLE);
|
||||
pager.setVisibility(View.VISIBLE);
|
||||
tabbar.setVisibility(View.VISIBLE);
|
||||
V.setVisibilityAnimated(nameWrap, View.VISIBLE);
|
||||
|
||||
AnimatorSet set=new AnimatorSet();
|
||||
set.playTogether(animators);
|
||||
@@ -857,20 +896,21 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
set.addListener(new AnimatorListenerAdapter(){
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation){
|
||||
for(int i=0;i<tabViews.length-1;i++){
|
||||
tabbar.getTabAt(i).view.setEnabled(true);
|
||||
}
|
||||
pager.setUserInputEnabled(true);
|
||||
nameEdit.setVisibility(View.GONE);
|
||||
bioEdit.setVisibility(View.GONE);
|
||||
RelativeLayout.LayoutParams lp=(RelativeLayout.LayoutParams) username.getLayoutParams();
|
||||
lp.addRule(RelativeLayout.BELOW, R.id.name);
|
||||
lp.addRule(RelativeLayout.BELOW, R.id.name_wrap);
|
||||
username.getParent().requestLayout();
|
||||
avatar.setForeground(null);
|
||||
scrollToTop();
|
||||
}
|
||||
});
|
||||
set.start();
|
||||
|
||||
InputMethodManager imm=getActivity().getSystemService(InputMethodManager.class);
|
||||
imm.hideSoftInputFromWindow(content.getWindowToken(), 0);
|
||||
V.setVisibilityAnimated(fab, View.VISIBLE);
|
||||
bindHeaderView();
|
||||
}
|
||||
|
||||
@@ -878,7 +918,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
if(!isInEditMode)
|
||||
throw new IllegalStateException();
|
||||
setActionProgressVisible(true);
|
||||
new UpdateAccountCredentials(nameEdit.getText().toString(), bioEdit.getText().toString(), editNewAvatar, editNewCover, aboutFragment.getFields())
|
||||
new UpdateAccountCredentials(nameEdit.getText().toString(), bioEdit.getText().toString(), editNewAvatar, editNewCover, metadataListData)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Account result){
|
||||
@@ -1049,4 +1089,227 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
// from ProfileAboutFragment
|
||||
public void setFields(ArrayList<AccountField> fields){
|
||||
metadataListData=fields;
|
||||
if (isInEditMode) {
|
||||
isInEditMode=false;
|
||||
dragHelper.attachToRecyclerView(null);
|
||||
}
|
||||
if (adapter != null) adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private class MetadataAdapter extends UsableRecyclerView.Adapter<BaseViewHolder> implements ImageLoaderRecyclerAdapter {
|
||||
public MetadataAdapter(){
|
||||
super(imgLoader);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return switch(viewType){
|
||||
case 0 -> new AboutViewHolder();
|
||||
case 1 -> new EditableAboutViewHolder();
|
||||
case 2 -> new AddRowViewHolder();
|
||||
default -> throw new IllegalStateException("Unexpected value: "+viewType);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(BaseViewHolder holder, int position){
|
||||
if(position<metadataListData.size()){
|
||||
holder.bind(metadataListData.get(position));
|
||||
}else{
|
||||
holder.bind(null);
|
||||
}
|
||||
super.onBindViewHolder(holder, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
if(isInEditMode){
|
||||
int size=metadataListData.size();
|
||||
if(size<MAX_FIELDS)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
return metadataListData.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
if(isInEditMode){
|
||||
return position==metadataListData.size() ? 2 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageCountForItem(int position){
|
||||
return isInEditMode || metadataListData.get(position).emojiRequests==null
|
||||
? 0 : metadataListData.get(position).emojiRequests.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||
return metadataListData.get(position).emojiRequests.get(image);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class BaseViewHolder extends BindableViewHolder<AccountField> {
|
||||
public BaseViewHolder(int layout){
|
||||
super(getActivity(), layout, list);
|
||||
}
|
||||
}
|
||||
|
||||
private class AboutViewHolder extends BaseViewHolder implements ImageLoaderViewHolder {
|
||||
private TextView title;
|
||||
private LinkedTextView value;
|
||||
|
||||
public AboutViewHolder(){
|
||||
super(R.layout.item_profile_about);
|
||||
title=findViewById(R.id.title);
|
||||
value=findViewById(R.id.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(AccountField item){
|
||||
title.setText(item.parsedName);
|
||||
value.setText(item.parsedValue);
|
||||
if(item.verifiedAt!=null){
|
||||
int textColor=UiUtils.isDarkTheme() ? 0xFF89bb9c : 0xFF5b8e63;
|
||||
value.setTextColor(textColor);
|
||||
value.setLinkTextColor(textColor);
|
||||
Drawable check=getResources().getDrawable(R.drawable.ic_fluent_checkmark_24_regular, getActivity().getTheme()).mutate();
|
||||
check.setTint(textColor);
|
||||
value.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, check, null);
|
||||
}else{
|
||||
value.setTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary));
|
||||
value.setLinkTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.colorAccent));
|
||||
value.setCompoundDrawables(null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(int index, Drawable image){
|
||||
CustomEmojiSpan span=index>=item.nameEmojis.length ? item.valueEmojis[index-item.nameEmojis.length] : item.nameEmojis[index];
|
||||
span.setDrawable(image);
|
||||
title.invalidate();
|
||||
value.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearImage(int index){
|
||||
setImage(index, null);
|
||||
}
|
||||
}
|
||||
|
||||
private class EditableAboutViewHolder extends BaseViewHolder {
|
||||
private EditText title;
|
||||
private EditText value;
|
||||
|
||||
public EditableAboutViewHolder(){
|
||||
super(R.layout.item_profile_about_editable);
|
||||
title=findViewById(R.id.title);
|
||||
value=findViewById(R.id.value);
|
||||
findViewById(R.id.dragger_thingy).setOnLongClickListener(v->{
|
||||
dragHelper.startDrag(this);
|
||||
return true;
|
||||
});
|
||||
title.addTextChangedListener(new SimpleTextWatcher(e->item.name=e.toString()));
|
||||
value.addTextChangedListener(new SimpleTextWatcher(e->item.value=e.toString()));
|
||||
findViewById(R.id.remove_row_btn).setOnClickListener(this::onRemoveRowClick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(AccountField item){
|
||||
title.setText(item.name);
|
||||
value.setText(item.value);
|
||||
}
|
||||
|
||||
private void onRemoveRowClick(View v){
|
||||
int pos=getAbsoluteAdapterPosition();
|
||||
metadataListData.remove(pos);
|
||||
adapter.notifyItemRemoved(pos);
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
BaseViewHolder vh=(BaseViewHolder) list.getChildViewHolder(list.getChildAt(i));
|
||||
vh.rebind();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AddRowViewHolder extends BaseViewHolder implements UsableRecyclerView.Clickable{
|
||||
public AddRowViewHolder(){
|
||||
super(R.layout.item_profile_about_add_row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(){
|
||||
metadataListData.add(new AccountField());
|
||||
if(metadataListData.size()==MAX_FIELDS){ // replace this row with new row
|
||||
adapter.notifyItemChanged(metadataListData.size()-1);
|
||||
}else{
|
||||
adapter.notifyItemInserted(metadataListData.size()-1);
|
||||
rebind();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(AccountField item) {}
|
||||
}
|
||||
|
||||
private class ReorderCallback extends ItemTouchHelper.SimpleCallback{
|
||||
public ReorderCallback(){
|
||||
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target){
|
||||
if(target instanceof AddRowViewHolder)
|
||||
return false;
|
||||
int fromPosition=viewHolder.getAbsoluteAdapterPosition();
|
||||
int toPosition=target.getAbsoluteAdapterPosition();
|
||||
if (fromPosition<toPosition) {
|
||||
for (int i=fromPosition;i<toPosition;i++) {
|
||||
Collections.swap(metadataListData, i, i+1);
|
||||
}
|
||||
} else {
|
||||
for (int i=fromPosition;i>toPosition;i--) {
|
||||
Collections.swap(metadataListData, i, i-1);
|
||||
}
|
||||
}
|
||||
adapter.notifyItemMoved(fromPosition, toPosition);
|
||||
((BindableViewHolder)viewHolder).rebind();
|
||||
((BindableViewHolder)target).rebind();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState){
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
if(actionState==ItemTouchHelper.ACTION_STATE_DRAG){
|
||||
viewHolder.itemView.setTag(R.id.item_touch_helper_previous_elevation, viewHolder.itemView.getElevation()); // prevents the default behavior of changing elevation in onDraw()
|
||||
viewHolder.itemView.animate().translationZ(V.dp(1)).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||
draggedViewHolder=viewHolder;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder){
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
viewHolder.itemView.animate().translationZ(0).setDuration(100).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||
draggedViewHolder=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled(){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
public class ScheduledStatusListFragment extends BaseStatusListFragment<ScheduledStatus> {
|
||||
private String nextMaxID;
|
||||
private ImageButton fab;
|
||||
private static final int SCHEDULED_STATUS_LIST_OPENED = 161;
|
||||
|
||||
public ScheduledStatusListFragment() {
|
||||
setListLayoutId(R.layout.recycler_fragment_with_fab);
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,14 +56,24 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
fab=view.findViewById(R.id.fab);
|
||||
protected void onFabClick(View v) {
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putSerializable("scheduledAt", CreateStatus.getDraftInstant());
|
||||
fab.setOnClickListener(v -> Nav.go(getActivity(), ComposeFragment.class, args));
|
||||
fab.setOnLongClickListener(v -> UiUtils.pickAccountForCompose(getActivity(), accountID, args));
|
||||
Nav.go(getActivity(), ComposeFragment.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onFabLongClick(View v) {
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putSerializable("scheduledAt", CreateStatus.getDraftInstant());
|
||||
return UiUtils.pickAccountForCompose(getActivity(), accountID, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (getArguments().getBoolean("hide_fab", false)) fab.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,13 @@ import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.PushSubscriptionManager;
|
||||
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
||||
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.SelfUpdateStateChangedEvent;
|
||||
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
|
||||
import org.joinmastodon.android.model.PushNotification;
|
||||
import org.joinmastodon.android.model.PushSubscription;
|
||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||
@@ -65,7 +67,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
@@ -202,6 +203,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
GlobalUserPreferences.keepOnlyLatestNotification=i.checked;
|
||||
GlobalUserPreferences.save();
|
||||
}));
|
||||
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.save();
|
||||
}));
|
||||
|
||||
items.add(new HeaderItem(R.string.sk_timelines));
|
||||
items.add(new SwitchItem(R.string.sk_settings_show_replies, R.drawable.ic_fluent_chat_multiple_24_regular, GlobalUserPreferences.showReplies, i->{
|
||||
@@ -234,6 +239,15 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
GlobalUserPreferences.showNoAltIndicator=i.checked;
|
||||
GlobalUserPreferences.save();
|
||||
}));
|
||||
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.save();
|
||||
}));
|
||||
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.save();
|
||||
needAppRestart=true;
|
||||
}));
|
||||
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.save();
|
||||
@@ -320,6 +334,19 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
items.add(checkForUpdateItem);
|
||||
}
|
||||
|
||||
if(BuildConfig.DEBUG){
|
||||
items.add(new RedHeaderItem("Debug options"));
|
||||
items.add(new TextItem("Test e-mail confirmation flow", ()->{
|
||||
AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID);
|
||||
sess.activated=false;
|
||||
sess.activationInfo=new AccountActivationInfo("test@email", System.currentTimeMillis());
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putBoolean("debug", true);
|
||||
Nav.goClearingStack(getActivity(), AccountActivationFragment.class, args);
|
||||
}));
|
||||
}
|
||||
|
||||
items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
|
||||
}
|
||||
|
||||
@@ -597,7 +624,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
this.text=getString(text);
|
||||
}
|
||||
|
||||
public HeaderItem(String text) {
|
||||
public HeaderItem(String text){
|
||||
this.text=text;
|
||||
}
|
||||
|
||||
@@ -708,6 +735,11 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
this.secondaryText = secondaryText;
|
||||
}
|
||||
|
||||
public TextItem(String text, Runnable onClick){
|
||||
this.text=text;
|
||||
this.onClick=onClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType(){
|
||||
return 4;
|
||||
@@ -720,6 +752,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
super(text);
|
||||
}
|
||||
|
||||
public RedHeaderItem(String text){
|
||||
super(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType(){
|
||||
return 5;
|
||||
|
||||
@@ -6,12 +6,14 @@ import android.os.Bundle;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||
import org.joinmastodon.android.events.StatusUpdatedEvent;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||
@@ -30,7 +32,9 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
protected EventListener eventListener=new EventListener();
|
||||
|
||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, false, true, null);
|
||||
boolean addFooter = !GlobalUserPreferences.spectatorMode ||
|
||||
(this instanceof ThreadFragment t && s.id.equals(t.mainStatus.id));
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, false, addFooter, null, Filter.FilterContext.HOME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,6 +60,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
Status status=getContentStatusByID(id);
|
||||
if(status==null)
|
||||
return;
|
||||
status.filterRevealed = true;
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("status", Parcels.wrap(status));
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.stream.Collectors;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
public class ThreadFragment extends StatusListFragment{
|
||||
private Status mainStatus;
|
||||
protected Status mainStatus;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
|
||||
@@ -129,7 +129,8 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
// list.setPadding(0, V.dp(16), 0, V.dp(16));
|
||||
list.setClipToPadding(false);
|
||||
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 72, 16));
|
||||
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1,
|
||||
Math.round(16f + 56f * getResources().getConfiguration().fontScale), 16));
|
||||
updateToolbar();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,13 @@ import android.view.View;
|
||||
import org.joinmastodon.android.api.requests.trends.GetTrendingStatuses;
|
||||
import org.joinmastodon.android.fragments.IsOnTop;
|
||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
@@ -23,6 +26,7 @@ public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if (getActivity() == null) return;
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
}).exec(accountID);
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.view.View;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||
import org.joinmastodon.android.fragments.FabStatusListFragment;
|
||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -17,10 +16,16 @@ import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
public class FederatedTimelineFragment extends FabStatusListFragment {
|
||||
public class FederatedTimelineFragment extends StatusListFragment {
|
||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.FEDERATED_TIMELINE);
|
||||
private String maxID;
|
||||
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
currentRequest=new GetPublicTimeline(false, false, refreshing ? null : maxID, count)
|
||||
@@ -30,7 +35,8 @@ public class FederatedTimelineFragment extends FabStatusListFragment {
|
||||
if(!result.isEmpty())
|
||||
maxID=result.get(result.size()-1).id;
|
||||
if (getActivity() == null) return;
|
||||
onDataLoaded(result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList()), !result.isEmpty());
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
|
||||
@@ -3,9 +3,7 @@ package org.joinmastodon.android.fragments.discover;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||
import org.joinmastodon.android.fragments.FabStatusListFragment;
|
||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -17,10 +15,16 @@ import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
public class LocalTimelineFragment extends FabStatusListFragment {
|
||||
public class LocalTimelineFragment extends StatusListFragment {
|
||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.LOCAL_TIMELINE);
|
||||
private String maxID;
|
||||
|
||||
@Override
|
||||
protected boolean withComposeButton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count)
|
||||
@@ -30,7 +34,8 @@ public class LocalTimelineFragment extends FabStatusListFragment {
|
||||
if(!result.isEmpty())
|
||||
maxID=result.get(result.size()-1).id;
|
||||
if (getActivity() == null) return;
|
||||
onDataLoaded(result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList()), !result.isEmpty());
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
|
||||
@@ -193,30 +193,24 @@ public class AccountActivationFragment extends ToolbarFragment{
|
||||
mgr.removeAccount(accountID);
|
||||
mgr.addAccount(mgr.getInstanceInfo(session.domain), session.token, result, session.app, null);
|
||||
String newID=mgr.getLastActiveAccountID();
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", newID);
|
||||
if(session.self.avatar!=null || session.self.displayName!=null){
|
||||
File avaFile=session.self.avatar!=null ? new File(session.self.avatar) : null;
|
||||
new UpdateAccountCredentials(session.self.displayName, "", avaFile, null, Collections.emptyList())
|
||||
accountID=newID;
|
||||
if((session.self.avatar!=null || session.self.displayName!=null) && !getArguments().getBoolean("debug")){
|
||||
new UpdateAccountCredentials(session.self.displayName, "", (File)null, null, Collections.emptyList())
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Account result){
|
||||
if(avaFile!=null)
|
||||
avaFile.delete();
|
||||
mgr.updateAccountInfo(newID, result);
|
||||
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||
proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
if(avaFile!=null)
|
||||
avaFile.delete();
|
||||
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||
proceed();
|
||||
}
|
||||
})
|
||||
.exec(newID);
|
||||
}else{
|
||||
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||
proceed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,4 +243,11 @@ public class AccountActivationFragment extends ToolbarFragment{
|
||||
super.onDestroyView();
|
||||
resendBtn.removeCallbacks(resendTimer);
|
||||
}
|
||||
|
||||
private void proceed(){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
// Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||
Nav.goClearingStack(getActivity(), OnboardingFollowSuggestionsFragment.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
|
||||
private ItemsAdapter itemsAdapter;
|
||||
private ElevationOnScrollListener onScrollListener;
|
||||
|
||||
private static final int SIGNUP_REQUEST=722;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -139,7 +141,16 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
|
||||
protected void onButtonClick(){
|
||||
Bundle args=new Bundle();
|
||||
args.putParcelable("instance", Parcels.wrap(instance));
|
||||
Nav.go(getActivity(), SignupFragment.class, args);
|
||||
Nav.goForResult(getActivity(), SignupFragment.class, args, SIGNUP_REQUEST, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFragmentResult(int reqCode, boolean success, Bundle result){
|
||||
super.onFragmentResult(reqCode, success, result);
|
||||
if(reqCode==SIGNUP_REQUEST && !success){
|
||||
setResult(false, null);
|
||||
Nav.finish(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,15 +5,12 @@ import android.app.ProgressDialog;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.LocaleList;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
@@ -23,7 +20,6 @@ import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -31,6 +27,8 @@ import org.xml.sax.InputSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.IDN;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -50,7 +48,6 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
@@ -92,7 +89,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
||||
protected boolean onSearchEnterPressed(TextView v, int actionId, KeyEvent event){
|
||||
if(event!=null && event.getAction()!=KeyEvent.ACTION_DOWN)
|
||||
return true;
|
||||
currentSearchQuery=searchEdit.getText().toString().toLowerCase();
|
||||
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
|
||||
updateFilteredList();
|
||||
searchEdit.removeCallbacks(searchDebouncer);
|
||||
Instance instance=instancesCache.get(normalizeInstanceDomain(currentSearchQuery));
|
||||
@@ -106,52 +103,16 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
||||
}
|
||||
|
||||
protected void onSearchChangedDebounced(){
|
||||
currentSearchQuery=searchEdit.getText().toString().toLowerCase();
|
||||
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
|
||||
updateFilteredList();
|
||||
loadInstanceInfo(currentSearchQuery, false);
|
||||
}
|
||||
|
||||
protected List<CatalogInstance> sortInstances(List<CatalogInstance> result){
|
||||
Map<String, List<CatalogInstance>> byLang=result.stream().collect(Collectors.groupingBy(ci->ci.language));
|
||||
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
|
||||
Map<Boolean, List<CatalogInstance>> byLang=result.stream().sorted(Comparator.comparingInt((CatalogInstance ci)->ci.lastWeekUsers).reversed()).collect(Collectors.groupingBy(ci->ci.approvalRequired));
|
||||
ArrayList<CatalogInstance> sortedList=new ArrayList<>();
|
||||
for(String lang:userLangs){
|
||||
List<CatalogInstance> langInstances=byLang.remove(lang);
|
||||
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));
|
||||
sortedList.addAll(byLang.getOrDefault(false, Collections.emptyList()));
|
||||
sortedList.addAll(byLang.getOrDefault(true, Collections.emptyList()));
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
@@ -208,6 +169,20 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
||||
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;
|
||||
loadingInstanceRequest=new GetInstance();
|
||||
loadingInstanceRequest.setCallback(new Callback<>(){
|
||||
|
||||
@@ -64,7 +64,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
||||
|
||||
private List<String> languages=Collections.emptyList();
|
||||
private PopupMenu langFilterMenu, speedFilterMenu;
|
||||
private SignupSpeedFilter currentSignupSpeedFilter=SignupSpeedFilter.INSTANT;
|
||||
private SignupSpeedFilter currentSignupSpeedFilter=SignupSpeedFilter.ANY;
|
||||
private String currentLanguage=null;
|
||||
private boolean searchQueryMode;
|
||||
private LinearLayout filtersWrap;
|
||||
@@ -75,7 +75,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
||||
private FilterChipView categoryGeneral, categorySpecialInterests;
|
||||
private List<FilterChipView> regionalFilters;
|
||||
private CatalogInstance.Region chosenRegion;
|
||||
private CategoryChoice categoryChoice;
|
||||
private CategoryChoice categoryChoice=CategoryChoice.GENERAL;
|
||||
|
||||
public InstanceCatalogSignupFragment(){
|
||||
super(R.layout.fragment_onboarding_common, 10);
|
||||
@@ -371,6 +371,9 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
||||
if(instances.isEmpty()){
|
||||
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()){
|
||||
return;
|
||||
}
|
||||
@@ -527,6 +530,15 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment imple
|
||||
updateFilteredList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShown(){
|
||||
super.onShown();
|
||||
if(!searchQueryMode){
|
||||
// Prevent search view automatically getting focused when the user returns to this fragment
|
||||
focusThing.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private class InstancesAdapter extends UsableRecyclerView.Adapter<InstanceCatalogSignupFragment.InstanceViewHolder>{
|
||||
public InstancesAdapter(){
|
||||
super(imgLoader);
|
||||
|
||||
@@ -2,8 +2,14 @@ package org.joinmastodon.android.fragments.onboarding;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
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.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -64,7 +70,7 @@ public class InstanceRulesFragment extends ToolbarFragment{
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
||||
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.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
package org.joinmastodon.android.fragments.onboarding;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||
import org.joinmastodon.android.fragments.HomeFragment;
|
||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||
import org.joinmastodon.android.model.FollowSuggestion;
|
||||
import org.joinmastodon.android.model.ParsedAccount;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
import org.joinmastodon.android.ui.OutlineProviders;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class OnboardingFollowSuggestionsFragment extends BaseRecyclerFragment<ParsedAccount>{
|
||||
private String accountID;
|
||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||
private GetAccountRelationships relationshipsRequest;
|
||||
private View buttonBar;
|
||||
private ElevationOnScrollListener onScrollListener;
|
||||
private int numRunningFollowRequests=0;
|
||||
|
||||
public OnboardingFollowSuggestionsFragment(){
|
||||
super(R.layout.fragment_onboarding_follow_suggestions, 40);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
setTitle(R.string.popular_on_mastodon);
|
||||
accountID=getArguments().getString("account");
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||
list.addOnScrollListener(onScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, buttonBar, getToolbar()));
|
||||
|
||||
view.findViewById(R.id.btn_next).setOnClickListener(UiUtils.rateLimitedClickListener(this::onFollowAllClick));
|
||||
view.findViewById(R.id.btn_skip).setOnClickListener(UiUtils.rateLimitedClickListener(v->proceed()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdateToolbar(){
|
||||
super.onUpdateToolbar();
|
||||
getToolbar().setBackgroundResource(R.drawable.bg_onboarding_panel);
|
||||
getToolbar().setElevation(0);
|
||||
if(onScrollListener!=null){
|
||||
onScrollListener.setViews(buttonBar, getToolbar());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
new GetFollowSuggestions(40)
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<FollowSuggestion> result){
|
||||
onDataLoaded(result.stream().map(fs->new ParsedAccount(fs.account, accountID)).collect(Collectors.toList()), false);
|
||||
loadRelationships();
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
private void loadRelationships(){
|
||||
relationships=Collections.emptyMap();
|
||||
relationshipsRequest=new GetAccountRelationships(data.stream().map(fs->fs.account.id).collect(Collectors.toList()));
|
||||
relationshipsRequest.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(List<Relationship> result){
|
||||
relationshipsRequest=null;
|
||||
relationships=result.stream().collect(Collectors.toMap(rel->rel.id, Function.identity()));
|
||||
if(list==null)
|
||||
return;
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof SuggestionViewHolder svh)
|
||||
svh.rebind();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
relationshipsRequest=null;
|
||||
}
|
||||
}).exec(accountID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyWindowInsets(WindowInsets insets){
|
||||
if(Build.VERSION.SDK_INT>=27){
|
||||
int inset=insets.getSystemWindowInsetBottom();
|
||||
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
|
||||
}else{
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter getAdapter(){
|
||||
return new SuggestionsAdapter();
|
||||
}
|
||||
|
||||
private void onFollowAllClick(View v){
|
||||
if(!loaded || relationships.isEmpty())
|
||||
return;
|
||||
if(data.isEmpty()){
|
||||
proceed();
|
||||
return;
|
||||
}
|
||||
ArrayList<String> accountIdsToFollow=new ArrayList<>();
|
||||
for(ParsedAccount acc:data){
|
||||
Relationship rel=relationships.get(acc.account.id);
|
||||
if(rel==null)
|
||||
continue;
|
||||
if(rel.canFollow())
|
||||
accountIdsToFollow.add(acc.account.id);
|
||||
}
|
||||
|
||||
final ProgressDialog progress=new ProgressDialog(getActivity());
|
||||
progress.setIndeterminate(false);
|
||||
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
progress.setMax(accountIdsToFollow.size());
|
||||
progress.setCancelable(false);
|
||||
progress.setMessage(getString(R.string.sending_follows));
|
||||
progress.show();
|
||||
|
||||
for(int i=0;i<Math.min(accountIdsToFollow.size(), 5);i++){ // Send up to 5 requests in parallel
|
||||
followNextAccount(accountIdsToFollow, progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void followNextAccount(ArrayList<String> accountIdsToFollow, ProgressDialog progress){
|
||||
if(accountIdsToFollow.isEmpty()){
|
||||
if(numRunningFollowRequests==0){
|
||||
progress.dismiss();
|
||||
proceed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
numRunningFollowRequests++;
|
||||
String id=accountIdsToFollow.remove(0);
|
||||
new SetAccountFollowed(id, true, true)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
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--;
|
||||
progress.setProgress(progress.getMax()-accountIdsToFollow.size()-numRunningFollowRequests);
|
||||
followNextAccount(accountIdsToFollow, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
numRunningFollowRequests--;
|
||||
progress.setProgress(progress.getMax()-accountIdsToFollow.size()-numRunningFollowRequests);
|
||||
followNextAccount(accountIdsToFollow, progress);
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
private void proceed(){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
Nav.go(getActivity(), OnboardingProfileSetupFragment.class, args);
|
||||
}
|
||||
|
||||
private class SuggestionsAdapter extends UsableRecyclerView.Adapter<SuggestionViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||
|
||||
public SuggestionsAdapter(){
|
||||
super(imgLoader);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SuggestionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return new SuggestionViewHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return data.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(SuggestionViewHolder holder, int position){
|
||||
holder.bind(data.get(position));
|
||||
super.onBindViewHolder(holder, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageCountForItem(int position){
|
||||
return data.get(position).emojiHelper.getImageCount()+1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||
ParsedAccount account=data.get(position);
|
||||
if(image==0)
|
||||
return account.avatarRequest;
|
||||
return account.emojiHelper.getImageRequest(image-1);
|
||||
}
|
||||
}
|
||||
|
||||
private class SuggestionViewHolder extends BindableViewHolder<ParsedAccount> implements ImageLoaderViewHolder, UsableRecyclerView.Clickable{
|
||||
private final TextView name, username, bio;
|
||||
private final ImageView avatar;
|
||||
private final ProgressBarButton actionButton;
|
||||
private final ProgressBar actionProgress;
|
||||
private final View actionWrap;
|
||||
|
||||
private Relationship relationship;
|
||||
|
||||
public SuggestionViewHolder(){
|
||||
super(getActivity(), R.layout.item_user_row_m3, list);
|
||||
name=findViewById(R.id.name);
|
||||
username=findViewById(R.id.username);
|
||||
bio=findViewById(R.id.bio);
|
||||
avatar=findViewById(R.id.avatar);
|
||||
actionButton=findViewById(R.id.action_btn);
|
||||
actionProgress=findViewById(R.id.action_progress);
|
||||
actionWrap=findViewById(R.id.action_btn_wrap);
|
||||
|
||||
avatar.setOutlineProvider(OutlineProviders.roundedRect(10));
|
||||
avatar.setClipToOutline(true);
|
||||
actionButton.setOnClickListener(UiUtils.rateLimitedClickListener(this::onActionButtonClick));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(ParsedAccount item){
|
||||
name.setText(item.parsedName);
|
||||
username.setText(item.account.getDisplayUsername());
|
||||
if(TextUtils.isEmpty(item.parsedBio)){
|
||||
bio.setVisibility(View.GONE);
|
||||
}else{
|
||||
bio.setVisibility(View.VISIBLE);
|
||||
bio.setText(item.parsedBio);
|
||||
}
|
||||
|
||||
relationship=relationships.get(item.account.id);
|
||||
if(relationship==null){
|
||||
actionWrap.setVisibility(View.GONE);
|
||||
}else{
|
||||
actionWrap.setVisibility(View.VISIBLE);
|
||||
UiUtils.setRelationshipToActionButtonM3(relationship, actionButton);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(int index, Drawable image){
|
||||
if(index==0){
|
||||
avatar.setImageDrawable(image);
|
||||
}else{
|
||||
item.emojiHelper.setImageDrawable(index-1, image);
|
||||
name.invalidate();
|
||||
bio.invalidate();
|
||||
}
|
||||
if(image instanceof Animatable a && !a.isRunning())
|
||||
a.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearImage(int index){
|
||||
setImage(index, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("profileAccount", Parcels.wrap(item.account));
|
||||
Nav.go(getActivity(), ProfileFragment.class, args);
|
||||
}
|
||||
|
||||
private void onActionButtonClick(View v){
|
||||
itemView.setHasTransientState(true);
|
||||
UiUtils.performAccountAction(getActivity(), item.account, accountID, relationship, actionButton, this::setActionProgressVisible, rel->{
|
||||
itemView.setHasTransientState(false);
|
||||
relationships.put(item.account.id, rel);
|
||||
rebind();
|
||||
});
|
||||
}
|
||||
|
||||
private void setActionProgressVisible(boolean visible){
|
||||
actionButton.setTextVisible(!visible);
|
||||
actionProgress.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
actionButton.setClickable(!visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package org.joinmastodon.android.fragments.onboarding;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.fragments.HomeFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.AccountField;
|
||||
import org.joinmastodon.android.ui.OutlineProviders;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
|
||||
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||
|
||||
public class OnboardingProfileSetupFragment extends ToolbarFragment implements ReorderableLinearLayout.OnDragListener{
|
||||
private Button btn;
|
||||
private View buttonBar;
|
||||
private String accountID;
|
||||
private ElevationOnScrollListener onScrollListener;
|
||||
private ScrollView scroller;
|
||||
private EditText nameEdit, bioEdit;
|
||||
private ImageView avaImage, coverImage;
|
||||
private Button addRow;
|
||||
private ReorderableLinearLayout profileFieldsLayout;
|
||||
private Uri avatarUri, coverUri;
|
||||
|
||||
private static final int AVATAR_RESULT=348;
|
||||
private static final int COVER_RESULT=183;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
setNavigationBarColor(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground));
|
||||
accountID=getArguments().getString("account");
|
||||
setTitle(R.string.profile_setup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||
View view=inflater.inflate(R.layout.fragment_onboarding_profile_setup, container, false);
|
||||
|
||||
scroller=view.findViewById(R.id.scroller);
|
||||
nameEdit=view.findViewById(R.id.display_name);
|
||||
bioEdit=view.findViewById(R.id.bio);
|
||||
avaImage=view.findViewById(R.id.avatar);
|
||||
coverImage=view.findViewById(R.id.header);
|
||||
addRow=view.findViewById(R.id.add_row);
|
||||
profileFieldsLayout=view.findViewById(R.id.profile_fields);
|
||||
|
||||
btn=view.findViewById(R.id.btn_next);
|
||||
btn.setOnClickListener(v->onButtonClick());
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
|
||||
avaImage.setOutlineProvider(OutlineProviders.roundedRect(24));
|
||||
avaImage.setClipToOutline(true);
|
||||
|
||||
Account account=AccountSessionManager.getInstance().getAccount(accountID).self;
|
||||
if(savedInstanceState==null){
|
||||
nameEdit.setText(account.displayName);
|
||||
makeFieldsRow();
|
||||
}else{
|
||||
ArrayList<String> fieldTitles=savedInstanceState.getStringArrayList("fieldTitles");
|
||||
ArrayList<String> fieldValues=savedInstanceState.getStringArrayList("fieldValues");
|
||||
for(int i=0;i<fieldTitles.size();i++){
|
||||
View row=makeFieldsRow();
|
||||
EditText title=row.findViewById(R.id.title);
|
||||
EditText content=row.findViewById(R.id.content);
|
||||
title.setText(fieldTitles.get(i));
|
||||
content.setText(fieldValues.get(i));
|
||||
}
|
||||
if(fieldTitles.size()==4)
|
||||
addRow.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
addRow.setOnClickListener(v->{
|
||||
makeFieldsRow();
|
||||
if(profileFieldsLayout.getChildCount()==4){
|
||||
addRow.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
profileFieldsLayout.setDragListener(this);
|
||||
avaImage.setOnClickListener(v->startActivityForResult(UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1), AVATAR_RESULT));
|
||||
coverImage.setOnClickListener(v->startActivityForResult(UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1), COVER_RESULT));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||
scroller.setOnScrollChangeListener(onScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, buttonBar, getToolbar()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdateToolbar(){
|
||||
super.onUpdateToolbar();
|
||||
getToolbar().setBackgroundResource(R.drawable.bg_onboarding_panel);
|
||||
getToolbar().setElevation(0);
|
||||
if(onScrollListener!=null){
|
||||
onScrollListener.setViews(buttonBar, getToolbar());
|
||||
}
|
||||
}
|
||||
|
||||
protected void onButtonClick(){
|
||||
ArrayList<AccountField> fields=new ArrayList<>();
|
||||
for(int i=0;i<profileFieldsLayout.getChildCount();i++){
|
||||
View row=profileFieldsLayout.getChildAt(i);
|
||||
EditText title=row.findViewById(R.id.title);
|
||||
EditText content=row.findViewById(R.id.content);
|
||||
AccountField fld=new AccountField();
|
||||
fld.name=title.getText().toString();
|
||||
fld.value=content.getText().toString();
|
||||
fields.add(fld);
|
||||
}
|
||||
new UpdateAccountCredentials(nameEdit.getText().toString(), bioEdit.getText().toString(), avatarUri, coverUri, fields)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Account result){
|
||||
AccountSessionManager.getInstance().updateAccountInfo(accountID, result);
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
error.showToast(getActivity());
|
||||
}
|
||||
})
|
||||
.wrapProgress(getActivity(), R.string.saving, true)
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyWindowInsets(WindowInsets insets){
|
||||
if(Build.VERSION.SDK_INT>=27){
|
||||
int inset=insets.getSystemWindowInsetBottom();
|
||||
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
|
||||
}else{
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||
}
|
||||
}
|
||||
|
||||
private View makeFieldsRow(){
|
||||
View view=LayoutInflater.from(getActivity()).inflate(R.layout.onboarding_profile_field, profileFieldsLayout, false);
|
||||
profileFieldsLayout.addView(view);
|
||||
view.findViewById(R.id.dragger_thingy).setOnLongClickListener(v->{
|
||||
profileFieldsLayout.startDragging(view);
|
||||
return true;
|
||||
});
|
||||
view.findViewById(R.id.delete).setOnClickListener(v->{
|
||||
profileFieldsLayout.removeView(view);
|
||||
if(addRow.getVisibility()==View.GONE)
|
||||
addRow.setVisibility(View.VISIBLE);
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwapItems(int oldIndex, int newIndex){}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState){
|
||||
super.onSaveInstanceState(outState);
|
||||
ArrayList<String> fieldTitles=new ArrayList<>(), fieldValues=new ArrayList<>();
|
||||
for(int i=0;i<profileFieldsLayout.getChildCount();i++){
|
||||
View row=profileFieldsLayout.getChildAt(i);
|
||||
EditText title=row.findViewById(R.id.title);
|
||||
EditText content=row.findViewById(R.id.content);
|
||||
fieldTitles.add(title.getText().toString());
|
||||
fieldValues.add(content.getText().toString());
|
||||
}
|
||||
outState.putStringArrayList("fieldTitles", fieldTitles);
|
||||
outState.putStringArrayList("fieldValues", fieldValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data){
|
||||
if(resultCode!=Activity.RESULT_OK)
|
||||
return;
|
||||
ImageView img;
|
||||
Uri uri=data.getData();
|
||||
int size;
|
||||
if(requestCode==AVATAR_RESULT){
|
||||
img=avaImage;
|
||||
avatarUri=uri;
|
||||
size=V.dp(100);
|
||||
}else{
|
||||
img=coverImage;
|
||||
coverUri=uri;
|
||||
size=V.dp(1000);
|
||||
}
|
||||
img.setForeground(null);
|
||||
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, size, size));
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,18 @@
|
||||
package org.joinmastodon.android.fragments.onboarding;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.text.style.TypefaceSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -16,11 +20,9 @@ import android.view.ViewTreeObserver;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.MastodonDetailedErrorResponse;
|
||||
import org.joinmastodon.android.api.requests.accounts.RegisterAccount;
|
||||
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
||||
@@ -31,18 +33,22 @@ import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Application;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.Token;
|
||||
import org.joinmastodon.android.ui.text.LinkSpan;
|
||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.FloatingHintEditTextLayout;
|
||||
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.nodes.Node;
|
||||
import org.jsoup.nodes.TextNode;
|
||||
import org.jsoup.select.NodeVisitor;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -51,12 +57,10 @@ import me.grishka.appkit.api.APIRequest;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||
|
||||
public class SignupFragment extends ToolbarFragment{
|
||||
private static final int AVATAR_RESULT=198;
|
||||
private static final String TAG="SignupFragment";
|
||||
|
||||
private Instance instance;
|
||||
@@ -73,6 +77,7 @@ public class SignupFragment extends ToolbarFragment{
|
||||
private boolean submitAfterGettingToken;
|
||||
private ProgressDialog progressDialog;
|
||||
private HashSet<EditText> errorFields=new HashSet<>();
|
||||
private ElevationOnScrollListener onScrollListener;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
@@ -145,19 +150,22 @@ public class SignupFragment extends ToolbarFragment{
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||
view.findViewById(R.id.scroller).setOnScrollChangeListener(onScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, buttonBar, getToolbar()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdateToolbar(){
|
||||
super.onUpdateToolbar();
|
||||
getToolbar().setBackground(null);
|
||||
getToolbar().setBackgroundResource(R.drawable.bg_onboarding_panel);
|
||||
getToolbar().setElevation(0);
|
||||
if(onScrollListener!=null){
|
||||
onScrollListener.setViews(buttonBar, getToolbar());
|
||||
}
|
||||
}
|
||||
|
||||
private void onButtonClick(){
|
||||
if(!password.getText().toString().equals(passwordConfirm.getText().toString())){
|
||||
passwordConfirm.setError(getString(R.string.signup_passwords_dont_match));
|
||||
passwordConfirmWrap.setErrorState();
|
||||
passwordConfirmWrap.setErrorState(getString(R.string.signup_passwords_dont_match));
|
||||
return;
|
||||
}
|
||||
showProgressDialog();
|
||||
@@ -212,8 +220,22 @@ public class SignupFragment extends ToolbarFragment{
|
||||
anyFieldsSkipped=true;
|
||||
continue;
|
||||
}
|
||||
field.setError(fieldErrors.get(fieldName).stream().map(err->err.description).collect(Collectors.joining("\n")));
|
||||
getFieldWrapByName(fieldName).setErrorState();
|
||||
List<MastodonDetailedErrorResponse.FieldError> errors=Objects.requireNonNull(fieldErrors.get(fieldName));
|
||||
if(errors.size()==1){
|
||||
getFieldWrapByName(fieldName).setErrorState(getErrorDescription(errors.get(0), fieldName));
|
||||
}else{
|
||||
SpannableStringBuilder ssb=new SpannableStringBuilder();
|
||||
boolean firstErr=true;
|
||||
for(MastodonDetailedErrorResponse.FieldError err:errors){
|
||||
if(firstErr){
|
||||
firstErr=false;
|
||||
}else{
|
||||
ssb.append('\n');
|
||||
}
|
||||
ssb.append(getErrorDescription(err, fieldName));
|
||||
}
|
||||
getFieldWrapByName(fieldName).setErrorState(getErrorDescription(errors.get(0), fieldName));
|
||||
}
|
||||
errorFields.add(field);
|
||||
if(first){
|
||||
first=false;
|
||||
@@ -231,6 +253,40 @@ public class SignupFragment extends ToolbarFragment{
|
||||
.exec(instance.uri, apiToken);
|
||||
}
|
||||
|
||||
private CharSequence getErrorDescription(MastodonDetailedErrorResponse.FieldError error, String fieldName){
|
||||
return switch(fieldName){
|
||||
case "email" -> switch(error.error){
|
||||
case "ERR_BLOCKED" -> {
|
||||
String emailAddr=email.getText().toString();
|
||||
String s=getResources().getString(R.string.signup_email_domain_blocked, TextUtils.htmlEncode(instance.uri), TextUtils.htmlEncode(emailAddr.substring(emailAddr.lastIndexOf('@')+1)));
|
||||
SpannableStringBuilder ssb=new SpannableStringBuilder();
|
||||
Jsoup.parseBodyFragment(s).body().traverse(new NodeVisitor(){
|
||||
private int spanStart;
|
||||
@Override
|
||||
public void head(Node node, int depth){
|
||||
if(node instanceof TextNode tn){
|
||||
ssb.append(tn.text());
|
||||
}else if(node instanceof Element){
|
||||
spanStart=ssb.length();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tail(Node node, int depth){
|
||||
if(node instanceof Element){
|
||||
ssb.setSpan(new LinkSpan("", SignupFragment.this::onGoBackLinkClick, LinkSpan.Type.CUSTOM, null), spanStart, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
ssb.setSpan(new TypefaceSpan("sans-serif-medium"), spanStart, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
});
|
||||
yield ssb;
|
||||
}
|
||||
default -> error.description;
|
||||
};
|
||||
default -> error.description;
|
||||
};
|
||||
}
|
||||
|
||||
private EditText getFieldByName(String name){
|
||||
return switch(name){
|
||||
case "email" -> email;
|
||||
@@ -323,6 +379,11 @@ public class SignupFragment extends ToolbarFragment{
|
||||
}
|
||||
}
|
||||
|
||||
private void onGoBackLinkClick(LinkSpan span){
|
||||
setResult(false, null);
|
||||
Nav.finish(this);
|
||||
}
|
||||
|
||||
private class ErrorClearingListener implements TextWatcher{
|
||||
public final EditText editText;
|
||||
|
||||
|
||||
@@ -133,6 +133,14 @@ public class Account extends BaseModel{
|
||||
*/
|
||||
public Instant muteExpiresAt;
|
||||
|
||||
public List<Role> roles;
|
||||
|
||||
@Parcel
|
||||
public static class Role {
|
||||
public String name;
|
||||
/** #rrggbb */
|
||||
public String color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postprocess() throws ObjectValidationException{
|
||||
|
||||
@@ -19,6 +19,7 @@ public class Filter extends BaseModel{
|
||||
public String id;
|
||||
@RequiredField
|
||||
public String phrase;
|
||||
public String title;
|
||||
public transient EnumSet<FilterContext> context=EnumSet.noneOf(FilterContext.class);
|
||||
public Instant expiresAt;
|
||||
public boolean irreversible;
|
||||
@@ -50,6 +51,7 @@ public class Filter extends BaseModel{
|
||||
else
|
||||
pattern=Pattern.compile(Pattern.quote(phrase), Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
if (title == null) title = phrase;
|
||||
return pattern.matcher(text).find();
|
||||
}
|
||||
|
||||
@@ -61,6 +63,7 @@ public class Filter extends BaseModel{
|
||||
public String toString(){
|
||||
return "Filter{"+
|
||||
"id='"+id+'\''+
|
||||
", title='"+title+'\''+
|
||||
", phrase='"+phrase+'\''+
|
||||
", context="+context+
|
||||
", expiresAt="+expiresAt+
|
||||
@@ -77,7 +80,9 @@ public class Filter extends BaseModel{
|
||||
@SerializedName("public")
|
||||
PUBLIC,
|
||||
@SerializedName("thread")
|
||||
THREAD
|
||||
THREAD,
|
||||
@SerializedName("account")
|
||||
ACCOUNT
|
||||
}
|
||||
|
||||
public enum FilterAction{
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Instance extends BaseModel{
|
||||
@RequiredField
|
||||
public String version;
|
||||
/**
|
||||
* Primary langauges of the website and its staff.
|
||||
* Primary languages of the website and its staff.
|
||||
*/
|
||||
// @RequiredField
|
||||
public List<String> languages;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.joinmastodon.android.model;
|
||||
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class ParsedAccount{
|
||||
public Account account;
|
||||
public CharSequence parsedName, parsedBio;
|
||||
public CustomEmojiHelper emojiHelper;
|
||||
public ImageLoaderRequest avatarRequest;
|
||||
|
||||
public ParsedAccount(Account account, String accountID){
|
||||
this.account=account;
|
||||
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
|
||||
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
||||
|
||||
emojiHelper=new CustomEmojiHelper();
|
||||
SpannableStringBuilder ssb=new SpannableStringBuilder(parsedName);
|
||||
ssb.append(parsedBio);
|
||||
emojiHelper.setText(ssb);
|
||||
|
||||
avatarRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(40), V.dp(40));
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,10 @@ public class Relationship extends BaseModel{
|
||||
public boolean blockedBy;
|
||||
public String note;
|
||||
|
||||
public boolean canFollow(){
|
||||
return !(following || blocking || blockedBy || domainBlocking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "Relationship{"+
|
||||
|
||||
@@ -62,19 +62,13 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
|
||||
}
|
||||
|
||||
public Status toStatus() {
|
||||
Status s = new Status();
|
||||
s.id = id;
|
||||
Status s = Status.ofFake(id, params.text, scheduledAt);
|
||||
s.mediaAttachments = mediaAttachments;
|
||||
s.createdAt = scheduledAt;
|
||||
s.inReplyToId = params.inReplyToId > 0 ? "" + params.inReplyToId : null;
|
||||
s.content = s.text = params.text;
|
||||
s.spoilerText = params.spoilerText;
|
||||
s.visibility = params.visibility;
|
||||
s.language = params.language;
|
||||
s.sensitive = params.sensitive;
|
||||
s.mentions = List.of();
|
||||
s.tags = List.of();
|
||||
s.emojis = List.of();
|
||||
if (params.poll != null) s.poll = params.poll.toPoll();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,9 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
||||
public boolean bookmarked;
|
||||
public boolean pinned;
|
||||
|
||||
public transient boolean filterRevealed;
|
||||
public transient boolean spoilerRevealed;
|
||||
public transient boolean textExpanded, textExpandable;
|
||||
public transient boolean hasGapAfter;
|
||||
private transient String strippedText;
|
||||
|
||||
@@ -158,6 +160,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
||||
s.mentions = List.of();
|
||||
s.tags = List.of();
|
||||
s.emojis = List.of();
|
||||
s.filtered = List.of();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||
@@ -137,7 +139,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||
private final TextView name, username, timestamp, extraText, separator;
|
||||
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator;
|
||||
private final View collapseBtn;
|
||||
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, collapseBtnIcon;
|
||||
private final PopupMenu optionsMenu;
|
||||
private Relationship relationship;
|
||||
private APIRequest<?> currentRelationshipRequest;
|
||||
@@ -160,6 +163,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
visibility=findViewById(R.id.visibility);
|
||||
deleteNotification=findViewById(R.id.delete_notification);
|
||||
unreadIndicator=findViewById(R.id.unread_indicator);
|
||||
collapseBtn=findViewById(R.id.collapse_btn);
|
||||
collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
|
||||
extraText=findViewById(R.id.extra_text);
|
||||
avatar.setOnClickListener(this::onAvaClick);
|
||||
avatar.setOutlineProvider(roundCornersOutline);
|
||||
@@ -171,6 +176,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
fragment.removeNotification(item.notification);
|
||||
}
|
||||
}));
|
||||
collapseBtn.setOnClickListener(l -> item.parentFragment.onToggleExpanded(item.status, getItemID()));
|
||||
|
||||
optionsMenu=new PopupMenu(activity, more);
|
||||
optionsMenu.inflate(R.menu.post);
|
||||
@@ -300,7 +306,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
|
||||
timestamp.setText(item.scheduledStatus.scheduledAt.atZone(ZoneId.systemDefault()).format(formatter));
|
||||
}
|
||||
else if ((item.status==null || item.status.editedAt==null) && item.createdAt != null)
|
||||
else if ((!item.inset || item.status==null || item.status.editedAt==null) && item.createdAt != null)
|
||||
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
||||
else if (item.status != null && item.status.editedAt != null)
|
||||
timestamp.setText(item.parentFragment.getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(itemView.getContext(), item.status.editedAt)));
|
||||
@@ -373,6 +379,17 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
|
||||
more.setContentDescription(desc);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) more.setTooltipText(desc);
|
||||
|
||||
if (item.status == null || !item.status.textExpandable) {
|
||||
collapseBtn.setVisibility(View.GONE);
|
||||
} else {
|
||||
String collapseText = item.parentFragment.getString(item.status.textExpanded ? R.string.sk_collapse : R.string.sk_expand);
|
||||
collapseBtn.setVisibility(item.status.textExpandable ? View.VISIBLE : View.GONE);
|
||||
collapseBtn.setContentDescription(collapseText);
|
||||
if (GlobalUserPreferences.reduceMotion) collapseBtnIcon.setScaleY(item.status.textExpanded ? -1 : 1);
|
||||
else collapseBtnIcon.animate().scaleY(item.status.textExpanded ? -1 : 1).start();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) collapseBtn.setTooltipText(collapseText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.Activity;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
@@ -19,6 +28,7 @@ import org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||
|
||||
public abstract class ImageStatusDisplayItem extends StatusDisplayItem{
|
||||
public final int index;
|
||||
@@ -56,11 +66,35 @@ public abstract class ImageStatusDisplayItem extends StatusDisplayItem{
|
||||
private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable();
|
||||
private boolean didClear;
|
||||
|
||||
private AnimatorSet currentAnim;
|
||||
private final FrameLayout altTextWrapper;
|
||||
private final TextView altTextButton;
|
||||
private final ImageView noAltTextButton;
|
||||
private final View altTextScroller;
|
||||
private final ImageButton altTextClose;
|
||||
private final TextView altText, noAltText;
|
||||
|
||||
private View altOrNoAltButton;
|
||||
private boolean altTextShown;
|
||||
|
||||
public Holder(Activity activity, @LayoutRes int layout, ViewGroup parent){
|
||||
super(activity, layout, parent);
|
||||
photo=findViewById(R.id.photo);
|
||||
photo.setOnClickListener(this::onViewClick);
|
||||
this.layout=(ImageAttachmentFrameLayout)itemView;
|
||||
|
||||
altTextWrapper=findViewById(R.id.alt_text_wrapper);
|
||||
altTextButton=findViewById(R.id.alt_button);
|
||||
noAltTextButton=findViewById(R.id.no_alt_button);
|
||||
altTextScroller=findViewById(R.id.alt_text_scroller);
|
||||
altTextClose=findViewById(R.id.alt_text_close);
|
||||
altText=findViewById(R.id.alt_text);
|
||||
noAltText=findViewById(R.id.no_alt_text);
|
||||
|
||||
altTextButton.setOnClickListener(this::onShowHideClick);
|
||||
noAltTextButton.setOnClickListener(this::onShowHideClick);
|
||||
altTextClose.setOnClickListener(this::onShowHideClick);
|
||||
// altTextScroller.setNestedScrollingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +107,111 @@ public abstract class ImageStatusDisplayItem extends StatusDisplayItem{
|
||||
photo.setImageDrawable(crossfadeDrawable);
|
||||
photo.setContentDescription(TextUtils.isEmpty(item.attachment.description) ? item.parentFragment.getString(R.string.media_no_description) : item.attachment.description);
|
||||
didClear=false;
|
||||
|
||||
if (currentAnim != null) currentAnim.cancel();
|
||||
|
||||
boolean altTextMissing = TextUtils.isEmpty(item.attachment.description);
|
||||
altOrNoAltButton = altTextMissing ? noAltTextButton : altTextButton;
|
||||
altTextShown=false;
|
||||
|
||||
altTextScroller.setVisibility(View.GONE);
|
||||
altTextClose.setVisibility(View.GONE);
|
||||
altTextButton.setVisibility(View.VISIBLE);
|
||||
noAltTextButton.setVisibility(View.VISIBLE);
|
||||
altTextButton.setAlpha(1f);
|
||||
noAltTextButton.setAlpha(1f);
|
||||
altTextWrapper.setVisibility(View.VISIBLE);
|
||||
|
||||
if (altTextMissing){
|
||||
if (GlobalUserPreferences.showNoAltIndicator) {
|
||||
noAltTextButton.setVisibility(View.VISIBLE);
|
||||
noAltText.setVisibility(View.VISIBLE);
|
||||
altTextWrapper.setBackgroundResource(R.drawable.bg_image_no_alt_overlay);
|
||||
altTextButton.setVisibility(View.GONE);
|
||||
altText.setVisibility(View.GONE);
|
||||
} else {
|
||||
altTextWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}else{
|
||||
if (GlobalUserPreferences.showAltIndicator) {
|
||||
noAltTextButton.setVisibility(View.GONE);
|
||||
noAltText.setVisibility(View.GONE);
|
||||
altTextWrapper.setBackgroundResource(R.drawable.bg_image_alt_overlay);
|
||||
altTextButton.setVisibility(View.VISIBLE);
|
||||
altTextButton.setText(R.string.sk_alt_button);
|
||||
altText.setVisibility(View.VISIBLE);
|
||||
altText.setText(item.attachment.description);
|
||||
altText.setPadding(0, 0, 0, 0);
|
||||
} else {
|
||||
altTextWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onShowHideClick(View v){
|
||||
boolean show=v.getId()==R.id.alt_button || v.getId()==R.id.no_alt_button;
|
||||
|
||||
if(altTextShown==show)
|
||||
return;
|
||||
if(currentAnim!=null)
|
||||
currentAnim.cancel();
|
||||
|
||||
altTextShown=show;
|
||||
if(show){
|
||||
altTextScroller.setVisibility(View.VISIBLE);
|
||||
altTextClose.setVisibility(View.VISIBLE);
|
||||
}else{
|
||||
altOrNoAltButton.setVisibility(View.VISIBLE);
|
||||
// Hide these views temporarily so FrameLayout measures correctly
|
||||
altTextScroller.setVisibility(View.GONE);
|
||||
altTextClose.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// This is the current size...
|
||||
int prevLeft=altTextWrapper.getLeft();
|
||||
int prevRight=altTextWrapper.getRight();
|
||||
int prevTop=altTextWrapper.getTop();
|
||||
altTextWrapper.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
||||
@Override
|
||||
public boolean onPreDraw(){
|
||||
altTextWrapper.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
|
||||
// ...and this is after the layout pass, right now the FrameLayout has its final size, but we animate that change
|
||||
if(!show){
|
||||
// Show these views again so they're visible for the duration of the animation.
|
||||
// No one would notice they were missing during measure/layout.
|
||||
altTextScroller.setVisibility(View.VISIBLE);
|
||||
altTextClose.setVisibility(View.VISIBLE);
|
||||
}
|
||||
AnimatorSet set=new AnimatorSet();
|
||||
set.playTogether(
|
||||
ObjectAnimator.ofInt(altTextWrapper, "left", prevLeft, altTextWrapper.getLeft()),
|
||||
ObjectAnimator.ofInt(altTextWrapper, "right", prevRight, altTextWrapper.getRight()),
|
||||
ObjectAnimator.ofInt(altTextWrapper, "top", prevTop, altTextWrapper.getTop()),
|
||||
ObjectAnimator.ofFloat(altOrNoAltButton, View.ALPHA, show ? 1f : 0f, show ? 0f : 1f),
|
||||
ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f),
|
||||
ObjectAnimator.ofFloat(altTextClose, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f)
|
||||
);
|
||||
set.setDuration(300);
|
||||
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
set.addListener(new AnimatorListenerAdapter(){
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation){
|
||||
if(show){
|
||||
altOrNoAltButton.setVisibility(View.GONE);
|
||||
}else{
|
||||
altTextScroller.setVisibility(View.GONE);
|
||||
altTextClose.setVisibility(View.GONE);
|
||||
}
|
||||
currentAnim=null;
|
||||
}
|
||||
});
|
||||
set.start();
|
||||
currentAnim=set;
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,141 +37,9 @@ public class PhotoStatusDisplayItem extends ImageStatusDisplayItem{
|
||||
return Type.PHOTO;
|
||||
}
|
||||
|
||||
public static class Holder extends ImageStatusDisplayItem.Holder<PhotoStatusDisplayItem>{
|
||||
private final FrameLayout altTextWrapper;
|
||||
private final TextView altTextButton;
|
||||
private final ImageView noAltTextButton;
|
||||
private final View altTextScroller;
|
||||
private final ImageButton altTextClose;
|
||||
private final TextView altText, noAltText;
|
||||
|
||||
private View altOrNoAltButton;
|
||||
private boolean altTextShown;
|
||||
private AnimatorSet currentAnim;
|
||||
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
public static class Holder extends ImageStatusDisplayItem.Holder<PhotoStatusDisplayItem> {
|
||||
public Holder(Activity activity, ViewGroup parent) {
|
||||
super(activity, R.layout.display_item_photo, parent);
|
||||
altTextWrapper=findViewById(R.id.alt_text_wrapper);
|
||||
altTextButton=findViewById(R.id.alt_button);
|
||||
noAltTextButton=findViewById(R.id.no_alt_button);
|
||||
altTextScroller=findViewById(R.id.alt_text_scroller);
|
||||
altTextClose=findViewById(R.id.alt_text_close);
|
||||
altText=findViewById(R.id.alt_text);
|
||||
noAltText=findViewById(R.id.no_alt_text);
|
||||
|
||||
altTextButton.setOnClickListener(this::onShowHideClick);
|
||||
noAltTextButton.setOnClickListener(this::onShowHideClick);
|
||||
altTextClose.setOnClickListener(this::onShowHideClick);
|
||||
// altTextScroller.setNestedScrollingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(ImageStatusDisplayItem item){
|
||||
super.onBind(item);
|
||||
boolean altTextMissing = TextUtils.isEmpty(item.attachment.description);
|
||||
altOrNoAltButton = altTextMissing ? noAltTextButton : altTextButton;
|
||||
altTextShown=false;
|
||||
if(currentAnim!=null)
|
||||
currentAnim.cancel();
|
||||
|
||||
altTextScroller.setVisibility(View.GONE);
|
||||
altTextClose.setVisibility(View.GONE);
|
||||
altTextButton.setVisibility(View.VISIBLE);
|
||||
noAltTextButton.setVisibility(View.VISIBLE);
|
||||
altTextButton.setAlpha(1f);
|
||||
noAltTextButton.setAlpha(1f);
|
||||
altTextWrapper.setVisibility(View.VISIBLE);
|
||||
|
||||
if (altTextMissing){
|
||||
if (GlobalUserPreferences.showNoAltIndicator) {
|
||||
noAltTextButton.setVisibility(View.VISIBLE);
|
||||
noAltText.setVisibility(View.VISIBLE);
|
||||
altTextWrapper.setBackgroundResource(R.drawable.bg_image_no_alt_overlay);
|
||||
altTextButton.setVisibility(View.GONE);
|
||||
altText.setVisibility(View.GONE);
|
||||
} else {
|
||||
altTextWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}else{
|
||||
if (GlobalUserPreferences.showAltIndicator) {
|
||||
noAltTextButton.setVisibility(View.GONE);
|
||||
noAltText.setVisibility(View.GONE);
|
||||
altTextWrapper.setBackgroundResource(R.drawable.bg_image_alt_overlay);
|
||||
altTextButton.setVisibility(View.VISIBLE);
|
||||
altTextButton.setText(R.string.sk_alt_button);
|
||||
altText.setVisibility(View.VISIBLE);
|
||||
altText.setText(item.attachment.description);
|
||||
altText.setPadding(0, 0, 0, 0);
|
||||
} else {
|
||||
altTextWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onShowHideClick(View v){
|
||||
boolean show=v.getId()==R.id.alt_button || v.getId()==R.id.no_alt_button;
|
||||
|
||||
if(altTextShown==show)
|
||||
return;
|
||||
if(currentAnim!=null)
|
||||
currentAnim.cancel();
|
||||
|
||||
altTextShown=show;
|
||||
if(show){
|
||||
altTextScroller.setVisibility(View.VISIBLE);
|
||||
altTextClose.setVisibility(View.VISIBLE);
|
||||
}else{
|
||||
altOrNoAltButton.setVisibility(View.VISIBLE);
|
||||
// Hide these views temporarily so FrameLayout measures correctly
|
||||
altTextScroller.setVisibility(View.GONE);
|
||||
altTextClose.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// This is the current size...
|
||||
int prevLeft=altTextWrapper.getLeft();
|
||||
int prevRight=altTextWrapper.getRight();
|
||||
int prevTop=altTextWrapper.getTop();
|
||||
altTextWrapper.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
||||
@Override
|
||||
public boolean onPreDraw(){
|
||||
altTextWrapper.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
|
||||
// ...and this is after the layout pass, right now the FrameLayout has its final size, but we animate that change
|
||||
if(!show){
|
||||
// Show these views again so they're visible for the duration of the animation.
|
||||
// No one would notice they were missing during measure/layout.
|
||||
altTextScroller.setVisibility(View.VISIBLE);
|
||||
altTextClose.setVisibility(View.VISIBLE);
|
||||
}
|
||||
AnimatorSet set=new AnimatorSet();
|
||||
set.playTogether(
|
||||
ObjectAnimator.ofInt(altTextWrapper, "left", prevLeft, altTextWrapper.getLeft()),
|
||||
ObjectAnimator.ofInt(altTextWrapper, "right", prevRight, altTextWrapper.getRight()),
|
||||
ObjectAnimator.ofInt(altTextWrapper, "top", prevTop, altTextWrapper.getTop()),
|
||||
ObjectAnimator.ofFloat(altOrNoAltButton, View.ALPHA, show ? 1f : 0f, show ? 0f : 1f),
|
||||
ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f),
|
||||
ObjectAnimator.ofFloat(altTextClose, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f)
|
||||
);
|
||||
set.setDuration(300);
|
||||
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
set.addListener(new AnimatorListenerAdapter(){
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation){
|
||||
if(show){
|
||||
altOrNoAltButton.setVisibility(View.GONE);
|
||||
}else{
|
||||
altTextScroller.setVisibility(View.GONE);
|
||||
altTextClose.setVisibility(View.GONE);
|
||||
}
|
||||
currentAnim=null;
|
||||
}
|
||||
});
|
||||
set.start();
|
||||
currentAnim=set;
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.joinmastodon.android.fragments.ThreadFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Hashtag;
|
||||
import org.joinmastodon.android.model.Notification;
|
||||
import org.joinmastodon.android.model.Poll;
|
||||
@@ -26,9 +27,11 @@ import org.joinmastodon.android.model.ScheduledStatus;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -79,21 +82,43 @@ public abstract class StatusDisplayItem{
|
||||
case HASHTAG -> new HashtagStatusDisplayItem.Holder(activity, parent);
|
||||
case GAP -> new GapStatusDisplayItem.Holder(activity, parent);
|
||||
case EXTENDED_FOOTER -> new ExtendedFooterStatusDisplayItem.Holder(activity, parent);
|
||||
case WARNING -> new WarningFilteredStatusDisplayItem.Holder(activity, parent);
|
||||
};
|
||||
}
|
||||
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification){
|
||||
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, false);
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification){
|
||||
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, false, Filter.FilterContext.HOME);
|
||||
}
|
||||
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate){
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, Filter.FilterContext filterContext){
|
||||
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, false, filterContext);
|
||||
}
|
||||
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate){
|
||||
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, disableTranslate, Filter.FilterContext.HOME);
|
||||
}
|
||||
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate, Filter.FilterContext filterContext){
|
||||
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, disableTranslate, filterContext, null);
|
||||
}
|
||||
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate, Filter.FilterContext filterContext, StatusDisplayItem titleItem){
|
||||
String parentID=parentObject.getID();
|
||||
ArrayList<StatusDisplayItem> items=new ArrayList<>();
|
||||
|
||||
Status statusForContent=status.getContentStatus();
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus ? (ScheduledStatus) parentObject : null;
|
||||
|
||||
List<Filter> filters = AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream()
|
||||
.filter(f -> f.context.contains(filterContext)).collect(Collectors.toList());
|
||||
StatusFilterPredicate filterPredicate = new StatusFilterPredicate(filters);
|
||||
|
||||
if(!statusForContent.filterRevealed){
|
||||
statusForContent.filterRevealed = filterPredicate.testWithWarning(status);
|
||||
}
|
||||
|
||||
if(status.reblog!=null){
|
||||
boolean isOwnPost = AccountSessionManager.getInstance().isSelf(fragment.getAccountID(), status.account);
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20_filled, isOwnPost ? status.visibility : null, i->{
|
||||
@@ -170,6 +195,15 @@ public abstract class StatusDisplayItem{
|
||||
item.inset=inset;
|
||||
item.index=i++;
|
||||
}
|
||||
|
||||
if (titleItem != null) items.add(0, titleItem);
|
||||
|
||||
if (!statusForContent.filterRevealed) {
|
||||
return new ArrayList<>(List.of(
|
||||
new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)
|
||||
));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -196,6 +230,7 @@ public abstract class StatusDisplayItem{
|
||||
ACCOUNT,
|
||||
HASHTAG,
|
||||
GAP,
|
||||
WARNING,
|
||||
EXTENDED_FOOTER
|
||||
}
|
||||
|
||||
@@ -205,7 +240,7 @@ public abstract class StatusDisplayItem{
|
||||
}
|
||||
|
||||
public Holder(Context context, int layout, ViewGroup parent){
|
||||
super(context, layout, parent);
|
||||
super(context, layout, parent);
|
||||
}
|
||||
|
||||
public String getItemID(){
|
||||
|
||||
@@ -3,14 +3,17 @@ package org.joinmastodon.android.ui.displayitems;
|
||||
import android.app.Activity;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Button;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.bottomSoftwareFoundation.bottom.Bottom;
|
||||
import com.github.bottomSoftwareFoundation.bottom.TranslationError;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
@@ -20,13 +23,15 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.drawables.SpoilerStripesDrawable;
|
||||
import org.joinmastodon.android.model.StatusPrivacy;
|
||||
import org.joinmastodon.android.model.TranslatedStatus;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.LinkedTextView;
|
||||
import org.joinmastodon.android.utils.StatusTextEncoder;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
@@ -46,6 +51,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
public boolean translated = false;
|
||||
public TranslatedStatus translation = null;
|
||||
private AccountSession session;
|
||||
public static final Pattern BOTTOM_TEXT_PATTERN = Pattern.compile("(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️)(?:\uD83D\uDC49\uD83D\uDC48(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️))*\uD83D\uDC49\uD83D\uDC48");
|
||||
|
||||
public TextStatusDisplayItem(String parentID, CharSequence text, BaseStatusListFragment parentFragment, Status status, boolean disableTranslate){
|
||||
super(parentID, parentFragment);
|
||||
@@ -83,10 +89,14 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
public static class Holder extends StatusDisplayItem.Holder<TextStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||
private final LinkedTextView text;
|
||||
private final LinearLayout spoilerHeader;
|
||||
private final TextView spoilerTitle, spoilerTitleInline, translateInfo;
|
||||
private final View spoilerOverlay, borderTop, borderBottom, textWrap, translateWrap, translateProgress;
|
||||
private final TextView spoilerTitle, spoilerTitleInline, translateInfo, readMore;
|
||||
private final View spoilerOverlay, borderTop, borderBottom, textWrap, translateWrap, translateProgress, spaceBelowText;
|
||||
private final int backgroundColor, borderColor;
|
||||
private final Button translateButton;
|
||||
private final ScrollView textScrollView;
|
||||
|
||||
private final float textMaxHeight, textCollapsedHeight;
|
||||
private final LinearLayout.LayoutParams collapseParams, wrapParams;
|
||||
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
super(activity, R.layout.display_item_text, parent);
|
||||
@@ -105,6 +115,14 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
itemView.setOnClickListener(v->item.parentFragment.onRevealSpoilerClick(this));
|
||||
backgroundColor=UiUtils.getThemeColor(activity, R.attr.colorBackgroundLight);
|
||||
borderColor=UiUtils.getThemeColor(activity, R.attr.colorPollVoted);
|
||||
textScrollView=findViewById(R.id.text_scroll_view);
|
||||
readMore=findViewById(R.id.read_more);
|
||||
spaceBelowText=findViewById(R.id.space_below_text);
|
||||
textMaxHeight=activity.getResources().getDimension(R.dimen.text_max_height);
|
||||
textCollapsedHeight=activity.getResources().getDimension(R.dimen.text_collapsed_height);
|
||||
collapseParams=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) textCollapsedHeight);
|
||||
wrapParams=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
readMore.setOnClickListener(v -> item.parentFragment.onToggleExpanded(item.status, getItemID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,6 +131,9 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
|
||||
: item.text);
|
||||
text.setTextIsSelectable(item.textSelectable);
|
||||
if (item.textSelectable) {
|
||||
textScrollView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
spoilerTitleInline.setTextIsSelectable(item.textSelectable);
|
||||
text.setInvalidateOnEveryFrame(false);
|
||||
spoilerTitleInline.setBackgroundColor(item.inset ? 0 : backgroundColor);
|
||||
@@ -145,17 +166,30 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null &&
|
||||
instanceInfo.v2.configuration.translation.enabled;
|
||||
|
||||
translateWrap.setVisibility(
|
||||
(!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable) &&
|
||||
boolean isBottomText = BOTTOM_TEXT_PATTERN.matcher(item.status.getStrippedText()).find();
|
||||
boolean translateVisible = (isBottomText || (
|
||||
translateEnabled &&
|
||||
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
|
||||
item.status.language != null &&
|
||||
(item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage))
|
||||
? View.VISIBLE : View.GONE);
|
||||
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
|
||||
item.status.language != null &&
|
||||
(item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage))))
|
||||
&& (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable);
|
||||
translateWrap.setVisibility(translateVisible ? View.VISIBLE : View.GONE);
|
||||
translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post);
|
||||
translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, item.translation.provider) : "");
|
||||
translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, isBottomText ? "bottom-java" : item.translation.provider) : "");
|
||||
translateButton.setOnClickListener(v->{
|
||||
if (item.translation == null) {
|
||||
if (isBottomText) {
|
||||
try {
|
||||
item.translation = new TranslatedStatus();
|
||||
item.translation.content = new StatusTextEncoder(Bottom::decode).decode(item.status.getStrippedText(), BOTTOM_TEXT_PATTERN);
|
||||
item.translated = true;
|
||||
} catch (TranslationError err) {
|
||||
item.translation = null;
|
||||
Toast.makeText(itemView.getContext(), err.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
rebind();
|
||||
return;
|
||||
}
|
||||
translateProgress.setVisibility(View.VISIBLE);
|
||||
translateButton.setClickable(false);
|
||||
translateButton.animate().alpha(0.5f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
|
||||
@@ -184,6 +218,26 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
rebind();
|
||||
}
|
||||
});
|
||||
|
||||
readMore.setText(item.status.textExpanded ? R.string.sk_collapse : R.string.sk_expand);
|
||||
spaceBelowText.setVisibility(translateVisible ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (!GlobalUserPreferences.collapseLongPosts) {
|
||||
textScrollView.setLayoutParams(wrapParams);
|
||||
readMore.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (GlobalUserPreferences.collapseLongPosts) text.post(() -> {
|
||||
boolean tooBig = text.getMeasuredHeight() > textMaxHeight;
|
||||
boolean inTimeline = !item.textSelectable;
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(item.status.spoilerText);
|
||||
boolean expandable = inTimeline && tooBig && !hasSpoiler;
|
||||
item.parentFragment.onEnableExpandable(this, expandable);
|
||||
});
|
||||
|
||||
readMore.setVisibility(item.status.textExpandable && !item.status.textExpanded ? View.VISIBLE : View.GONE);
|
||||
textScrollView.setLayoutParams(item.status.textExpandable && !item.status.textExpanded ? collapseParams : wrapParams);
|
||||
if (item.status.textExpandable && !translateVisible) spaceBelowText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
||||
public boolean loading;
|
||||
public final Status status;
|
||||
public List<StatusDisplayItem> filteredItems;
|
||||
|
||||
public WarningFilteredStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status, List<StatusDisplayItem> filteredItems){
|
||||
super(parentID, parentFragment);
|
||||
this.status=status;
|
||||
this.filteredItems = filteredItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType(){
|
||||
return Type.WARNING;
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
|
||||
public final View warningWrap;
|
||||
public final TextView text;
|
||||
public List<StatusDisplayItem> filteredItems;
|
||||
|
||||
public Holder(Context context, ViewGroup parent) {
|
||||
super(context, R.layout.display_item_filter_warning, parent);
|
||||
warningWrap=findViewById(R.id.warning_wrap);
|
||||
text=findViewById(R.id.text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(WarningFilteredStatusDisplayItem item) {
|
||||
filteredItems = item.filteredItems;
|
||||
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.status.filtered.get(item.status.filtered.size() -1).filter.title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
item.parentFragment.onWarningClick(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,7 +602,7 @@ public class TabLayout extends HorizontalScrollView {
|
||||
* <p>If the tab indicator color is not {@code Color.TRANSPARENT}, the indicator will be wrapped
|
||||
* and tinted right before it is drawn by {@link SlidingTabIndicator#draw(Canvas)}. If you'd like
|
||||
* the inherent color or the tinted color of a custom drawable to be used, make sure this color is
|
||||
* set to {@code Color.TRANSPARENT} to avoid your color/tint being overriden.
|
||||
* set to {@code Color.TRANSPARENT} to avoid your color/tint being overridden.
|
||||
*
|
||||
* @param color color to use for the indicator
|
||||
* @attr ref com.google.android.material.R.styleable#TabLayout_tabIndicatorColor
|
||||
|
||||
@@ -16,6 +16,10 @@ public class LinkSpan extends CharacterStyle {
|
||||
private String accountID;
|
||||
private String text;
|
||||
|
||||
public LinkSpan(String link, OnLinkClickListener listener, Type type, String accountID){
|
||||
this(link, listener, type, accountID, null);
|
||||
}
|
||||
|
||||
public LinkSpan(String link, OnLinkClickListener listener, Type type, String accountID, String text){
|
||||
this.listener=listener;
|
||||
this.link=link;
|
||||
@@ -38,6 +42,7 @@ public class LinkSpan extends CharacterStyle {
|
||||
case URL -> UiUtils.openURL(context, accountID, link);
|
||||
case MENTION -> UiUtils.openProfileByID(context, accountID, link);
|
||||
case HASHTAG -> UiUtils.openHashtagTimeline(context, accountID, link, null);
|
||||
case CUSTOM -> listener.onLinkClick(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +69,7 @@ public class LinkSpan extends CharacterStyle {
|
||||
public enum Type{
|
||||
URL,
|
||||
MENTION,
|
||||
HASHTAG
|
||||
HASHTAG,
|
||||
CUSTOM
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.os.ext.SdkExtensions;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
@@ -664,6 +667,32 @@ public class UiUtils {
|
||||
}).exec(accountID);
|
||||
}
|
||||
|
||||
public static void setRelationshipToActionButtonM3(Relationship relationship, Button button){
|
||||
boolean secondaryStyle;
|
||||
if(relationship.blocking){
|
||||
button.setText(R.string.button_blocked);
|
||||
secondaryStyle=true;
|
||||
}else if(relationship.blockedBy){
|
||||
button.setText(R.string.button_follow);
|
||||
secondaryStyle=false;
|
||||
}else if(relationship.requested){
|
||||
button.setText(R.string.button_follow_pending);
|
||||
secondaryStyle=true;
|
||||
}else if(!relationship.following){
|
||||
button.setText(relationship.followedBy ? R.string.follow_back : R.string.button_follow);
|
||||
secondaryStyle=false;
|
||||
}else{
|
||||
button.setText(R.string.button_following);
|
||||
secondaryStyle=true;
|
||||
}
|
||||
|
||||
button.setEnabled(!relationship.blockedBy);
|
||||
int styleRes=secondaryStyle ? R.style.Widget_Mastodon_M3_Button_Tonal : R.style.Widget_Mastodon_M3_Button_Filled;
|
||||
TypedArray ta=button.getContext().obtainStyledAttributes(styleRes, new int[]{android.R.attr.background});
|
||||
button.setBackground(ta.getDrawable(0));
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
public static void performAccountAction(Activity activity, Account account, String accountID, Relationship relationship, Button button, Consumer<Boolean> progressCallback, Consumer<Relationship> resultCallback) {
|
||||
if (relationship.blocking) {
|
||||
confirmToggleBlockUser(activity, accountID, account, true, resultCallback);
|
||||
@@ -1176,4 +1205,63 @@ public class UiUtils {
|
||||
// fucking finally
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if Android platform photopicker is available on the device\
|
||||
*
|
||||
* @return whether the device supports photopicker intents.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
public static boolean isPhotoPickerAvailable(){
|
||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.TIRAMISU){
|
||||
return true;
|
||||
}else if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){
|
||||
return SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R)>=2;
|
||||
}else
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
public static Intent getMediaPickerIntent(String[] mimeTypes, int maxCount){
|
||||
Intent intent;
|
||||
if(isPhotoPickerAvailable()){
|
||||
intent=new Intent(MediaStore.ACTION_PICK_IMAGES);
|
||||
if(maxCount>1)
|
||||
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxCount);
|
||||
}else{
|
||||
intent=new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
}
|
||||
if(mimeTypes.length>1){
|
||||
intent.setType("*/*");
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
}else if(mimeTypes.length==1){
|
||||
intent.setType(mimeTypes[0]);
|
||||
}else{
|
||||
intent.setType("*/*");
|
||||
}
|
||||
if(maxCount>1)
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a View.OnClickListener to filter multiple clicks in succession.
|
||||
* Useful for buttons that perform some action that changes their state asynchronously.
|
||||
* @param l
|
||||
* @return
|
||||
*/
|
||||
public static View.OnClickListener rateLimitedClickListener(View.OnClickListener l){
|
||||
return new View.OnClickListener(){
|
||||
private long lastClickTime;
|
||||
|
||||
@Override
|
||||
public void onClick(View v){
|
||||
if(SystemClock.uptimeMillis()-lastClickTime>500L){
|
||||
lastClickTime=SystemClock.uptimeMillis();
|
||||
l.onClick(v);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.text.Editable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.EditText;
|
||||
@@ -47,6 +48,7 @@ public class FloatingHintEditTextLayout extends FrameLayout{
|
||||
private RectF tmpRect=new RectF();
|
||||
private ColorStateList labelColors, origHintColors;
|
||||
private boolean errorState;
|
||||
private TextView errorView;
|
||||
|
||||
public FloatingHintEditTextLayout(Context context){
|
||||
this(context, null);
|
||||
@@ -95,12 +97,22 @@ public class FloatingHintEditTextLayout extends FrameLayout{
|
||||
label.setAlpha(0f);
|
||||
|
||||
edit.addTextChangedListener(new SimpleTextWatcher(this::onTextChanged));
|
||||
|
||||
errorView=new LinkedTextView(getContext());
|
||||
errorView.setTextAppearance(R.style.m3_body_small);
|
||||
errorView.setTextColor(UiUtils.getThemeColor(getContext(), R.attr.colorM3OnSurfaceVariant));
|
||||
errorView.setLinkTextColor(UiUtils.getThemeColor(getContext(), R.attr.colorM3Primary));
|
||||
errorView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
errorView.setPadding(V.dp(16), V.dp(4), V.dp(16), 0);
|
||||
errorView.setVisibility(View.GONE);
|
||||
addView(errorView);
|
||||
}
|
||||
|
||||
private void onTextChanged(Editable text){
|
||||
if(errorState){
|
||||
errorView.setVisibility(View.GONE);
|
||||
errorState=false;
|
||||
setForeground(getResources().getDrawable(R.drawable.bg_m3_outlined_text_field));
|
||||
setForeground(getResources().getDrawable(R.drawable.bg_m3_outlined_text_field, getContext().getTheme()));
|
||||
refreshDrawableState();
|
||||
}
|
||||
boolean newHintVisible=text.length()==0;
|
||||
@@ -211,12 +223,34 @@ public class FloatingHintEditTextLayout extends FrameLayout{
|
||||
label.setTextColor(color.getColorForState(getDrawableState(), 0xff00ff00));
|
||||
}
|
||||
|
||||
public void setErrorState(){
|
||||
public void setErrorState(CharSequence error){
|
||||
if(errorState)
|
||||
return;
|
||||
errorState=true;
|
||||
setForeground(getResources().getDrawable(R.drawable.bg_m3_outlined_text_field_error, getContext().getTheme()));
|
||||
label.setTextColor(UiUtils.getThemeColor(getContext(), R.attr.colorM3Error));
|
||||
errorView.setVisibility(VISIBLE);
|
||||
errorView.setText(error);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
||||
if(errorView.getVisibility()!=GONE){
|
||||
int width=MeasureSpec.getSize(widthMeasureSpec)-getPaddingLeft()-getPaddingRight();
|
||||
LayoutParams editLP=(LayoutParams) edit.getLayoutParams();
|
||||
width-=editLP.leftMargin+editLP.rightMargin;
|
||||
errorView.measure(width | MeasureSpec.EXACTLY, MeasureSpec.UNSPECIFIED);
|
||||
LayoutParams lp=(LayoutParams) errorView.getLayoutParams();
|
||||
lp.width=width;
|
||||
lp.height=errorView.getMeasuredHeight();
|
||||
lp.gravity=Gravity.LEFT | Gravity.BOTTOM;
|
||||
lp.leftMargin=editLP.leftMargin;
|
||||
editLP.bottomMargin=errorView.getMeasuredHeight();
|
||||
}else{
|
||||
LayoutParams editLP=(LayoutParams) edit.getLayoutParams();
|
||||
editLP.bottomMargin=0;
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private class PaddedForegroundDrawable extends Drawable{
|
||||
@@ -313,8 +347,8 @@ public class FloatingHintEditTextLayout extends FrameLayout{
|
||||
@Override
|
||||
protected void onBoundsChange(@NonNull Rect bounds){
|
||||
super.onBoundsChange(bounds);
|
||||
LayoutParams lp=(LayoutParams) edit.getLayoutParams();
|
||||
wrapped.setBounds(bounds.left+lp.leftMargin-V.dp(12), bounds.top, bounds.right-lp.rightMargin+V.dp(12), bounds.bottom);
|
||||
int offset=V.dp(12);
|
||||
wrapped.setBounds(edit.getLeft()-offset, edit.getTop()-offset, edit.getRight()+offset, edit.getBottom()+offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.joinmastodon.android.ui.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
public class UntouchableScrollView extends ScrollView {
|
||||
public UntouchableScrollView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public UntouchableScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public UntouchableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public UntouchableScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
super.onTouchEvent(event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class ElevationOnScrollListener extends RecyclerView.OnScrollListener imp
|
||||
|
||||
@Override
|
||||
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY){
|
||||
handleScroll(v.getContext(), scrollY==0);
|
||||
handleScroll(v.getContext(), scrollY<=0);
|
||||
}
|
||||
|
||||
private void handleScroll(Context context, boolean newAtTop){
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.LocaleList;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -38,4 +38,22 @@ public class StatusFilterPredicate implements Predicate<Status>{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean testWithWarning(Status status) {
|
||||
if(status.filtered!=null){
|
||||
if (status.filtered.isEmpty()){
|
||||
return true;
|
||||
}
|
||||
boolean matches=status.filtered.stream()
|
||||
.map(filterResult->filterResult.filter)
|
||||
.filter(filter->filter.expiresAt==null||filter.expiresAt.isAfter(Instant.now()))
|
||||
.anyMatch(filter->filter.filterAction==Filter.FilterAction.WARN);
|
||||
return !matches;
|
||||
}
|
||||
for(Filter filter:filters){
|
||||
if(filter.matches(status))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.joinmastodon.android.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.joinmastodon.android.fragments.ComposeFragment;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.MatchResult;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// not a good class
|
||||
public class StatusTextEncoder {
|
||||
private final Function<String, String> fn;
|
||||
|
||||
// see ComposeFragment.HIGHLIGHT_PATTERN
|
||||
private final static Pattern EXCLUDE_PATTERN = Pattern.compile("\\s*(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))\\s*");
|
||||
|
||||
public StatusTextEncoder(Function<String, String> fn) {
|
||||
this.fn = fn;
|
||||
}
|
||||
|
||||
// prettiest method award winner 2023 [citation needed]
|
||||
public String encode(String content) {
|
||||
StringBuilder encodedString = new StringBuilder();
|
||||
// matches mentions and hashtags
|
||||
Matcher m = EXCLUDE_PATTERN.matcher(content);
|
||||
int previousEnd = 0;
|
||||
while (m.find()) {
|
||||
MatchResult res = m.toMatchResult();
|
||||
// everything before the match - do encode
|
||||
encodedString.append(fn.apply(content.substring(previousEnd, res.start())));
|
||||
previousEnd = res.end();
|
||||
// the match - do not encode
|
||||
encodedString.append(res.group());
|
||||
}
|
||||
// everything after the last match - do encode
|
||||
encodedString.append(fn.apply(content.substring(previousEnd)));
|
||||
return encodedString.toString();
|
||||
}
|
||||
|
||||
// prettiest almost-exact replica of a pretty function
|
||||
public String decode(String content, Pattern regex) {
|
||||
Matcher m = regex.matcher(content);
|
||||
StringBuilder decodedString = new StringBuilder();
|
||||
int previousEnd = 0;
|
||||
while (m.find()) {
|
||||
MatchResult res = m.toMatchResult();
|
||||
// everything before the match - do not decode
|
||||
decodedString.append(content.substring(previousEnd, res.start()));
|
||||
previousEnd = res.end();
|
||||
// the match - do decode
|
||||
decodedString.append(fn.apply(res.group()));
|
||||
}
|
||||
decodedString.append(content.substring(previousEnd));
|
||||
return decodedString.toString();
|
||||
}
|
||||
}
|
||||
5
mastodon/src/main/res/color/button_text_m3_tonal.xml
Normal file
5
mastodon/src/main/res/color/button_text_m3_tonal.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?colorM3OnSecondaryContainer" android:state_enabled="true"/>
|
||||
<item android:color="?colorM3OnSurface" android:alpha="0.38"/>
|
||||
</selector>
|
||||
19
mastodon/src/main/res/drawable/bg_button_m3_tonal.xml
Normal file
19
mastodon/src/main/res/drawable/bg_button_m3_tonal.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="true">
|
||||
<ripple android:color="@color/m3_on_secondary_container_overlay">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="?colorM3SecondaryContainer"/>
|
||||
<corners android:radius="20dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
</item>
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="?colorM3DisabledBackground"/>
|
||||
<corners android:radius="20dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<selector>
|
||||
<item android:state_focused="true">
|
||||
<shape>
|
||||
<stroke android:color="?colorM3Primary" android:width="2dp"/>
|
||||
<corners android:radius="4dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape>
|
||||
<stroke android:color="?colorM3Outline" android:width="1dp"/>
|
||||
<corners android:radius="4dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
</item>
|
||||
</layer-list>
|
||||
5
mastodon/src/main/res/drawable/bg_onboarding_avatar.xml
Normal file
5
mastodon/src/main/res/drawable/bg_onboarding_avatar.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="28dp"/>
|
||||
<solid android:color="?colorM3Surface"/>
|
||||
</shape>
|
||||
8
mastodon/src/main/res/drawable/bg_pill.xml
Normal file
8
mastodon/src/main/res/drawable/bg_pill.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:dither="true"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="4sp" />
|
||||
<solid android:color="?colorBackgroundLight" />
|
||||
<stroke android:width="2dp" android:color="#00ff00" />
|
||||
</shape>
|
||||
9
mastodon/src/main/res/drawable/ic_add_24px.xml
Normal file
9
mastodon/src/main/res/drawable/ic_add_24px.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11,19V13H5V11H11V5H13V11H19V13H13V19Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M29.45,6V9H9Q9,9 9,9Q9,9 9,9V39Q9,39 9,39Q9,39 9,39H39Q39,39 39,39Q39,39 39,39V18.6H42V39Q42,40.2 41.1,41.1Q40.2,42 39,42H9Q7.8,42 6.9,41.1Q6,40.2 6,39V9Q6,7.8 6.9,6.9Q7.8,6 9,6ZM38,6V10.05H42.05V13.05H38V17.1H35V13.05H30.95V10.05H35V6ZM12,33.9H36L28.8,24.3L22.45,32.65L17.75,26.45ZM9,9V14.55V18.6V39Q9,39 9,39Q9,39 9,39Q9,39 9,39Q9,39 9,39V9Q9,9 9,9Q9,9 9,9Z"/>
|
||||
</vector>
|
||||
9
mastodon/src/main/res/drawable/ic_delete_24px.xml
Normal file
9
mastodon/src/main/res/drawable/ic_delete_24px.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M7,21Q6.175,21 5.588,20.413Q5,19.825 5,19V6H4V4H9V3H15V4H20V6H19V19Q19,19.825 18.413,20.413Q17.825,21 17,21ZM17,6H7V19Q7,19 7,19Q7,19 7,19H17Q17,19 17,19Q17,19 17,19ZM9,17H11V8H9ZM13,17H15V8H13ZM7,6V19Q7,19 7,19Q7,19 7,19Q7,19 7,19Q7,19 7,19Z"/>
|
||||
</vector>
|
||||
9
mastodon/src/main/res/drawable/ic_drag_handle_24px.xml
Normal file
9
mastodon/src/main/res/drawable/ic_drag_handle_24px.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,15V13H20V15ZM4,11V9H20V11Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,3 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
|
||||
<path android:pathData="M15.794 7.733c0.286 0.3 0.274 0.774-0.026 1.06l-5.25 5.001c-0.29 0.276-0.745 0.276-1.035 0l-5.25-5c-0.3-0.287-0.312-0.761-0.026-1.061 0.286-0.3 0.76-0.312 1.06-0.026l4.734 4.509 4.733-4.51c0.3-0.285 0.774-0.273 1.06 0.027z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,3 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M4.293 8.293c0.39-0.39 1.024-0.39 1.414 0L12 14.586l6.293-6.293c0.39-0.39 1.024-0.39 1.414 0 0.39 0.39 0.39 1.024 0 1.414l-7 7c-0.39 0.39-1.024 0.39-1.414 0l-7-7c-0.39-0.39-0.39-1.024 0-1.414z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,3 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M4.22 8.47c0.293-0.293 0.767-0.293 1.06 0L12 15.19l6.72-6.72c0.293-0.293 0.767-0.293 1.06 0 0.293 0.293 0.293 0.767 0 1.06l-7.25 7.25c-0.293 0.293-0.767 0.293-1.06 0L4.22 9.53c-0.293-0.293-0.293-0.767 0-1.06z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,3 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M7.75 12c0 0.966-0.784 1.75-1.75 1.75S4.25 12.966 4.25 12 5.034 10.25 6 10.25 7.75 11.034 7.75 12zm6 0c0 0.966-0.784 1.75-1.75 1.75s-1.75-0.784-1.75-1.75 0.784-1.75 1.75-1.75 1.75 0.784 1.75 1.75zM18 13.75c0.966 0 1.75-0.784 1.75-1.75s-0.784-1.75-1.75-1.75-1.75 0.784-1.75 1.75 0.784 1.75 1.75 1.75z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
||||
79
mastodon/src/main/res/layout/alt_badge.xml
Normal file
79
mastodon/src/main/res/layout/alt_badge.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This is hidden from screenreaders because that same alt text is set as content description on the ImageView -->
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/alt_text_wrapper"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|bottom"
|
||||
android:layout_margin="12dp"
|
||||
android:importantForAccessibility="noHideDescendants"
|
||||
android:background="@drawable/bg_image_alt_overlay">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/no_alt_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:src="@drawable/ic_fluent_important_20_filled"
|
||||
android:tint="?colorGray25" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/alt_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_label_large"
|
||||
android:textColor="?colorGray25"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:paddingVertical="1dp"
|
||||
android:text="@string/sk_alt_button"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/alt_text_close"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="end|top"
|
||||
android:src="@drawable/ic_baseline_close_24"
|
||||
android:tint="#FFF"
|
||||
android:background="?android:actionBarItemBackground"/>
|
||||
|
||||
<org.joinmastodon.android.ui.views.NestableScrollView
|
||||
android:id="@+id/alt_text_scroller"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="40dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/alt_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?colorGray25"
|
||||
tools:text="Alt text goes here"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/no_alt_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:textAppearance="@style/m3_label_large"
|
||||
android:textColor="?colorGray25"
|
||||
android:text="@string/sk_no_alt_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.joinmastodon.android.ui.views.NestableScrollView>
|
||||
|
||||
</FrameLayout>
|
||||
5
mastodon/src/main/res/layout/compose_fab.xml
Normal file
5
mastodon/src/main/res/layout/compose_fab.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fab"
|
||||
android:contentDescription="@string/new_post"
|
||||
style="@style/Widget.Mastodon.Button.Compose" />
|
||||
31
mastodon/src/main/res/layout/display_item_filter_warning.xml
Normal file
31
mastodon/src/main/res/layout/display_item_filter_warning.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/warning_wrap"
|
||||
android:background="@drawable/bg_timeline_gap">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:padding="16dp"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:text="@string/sk_filtered"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reveal_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:text="@string/tap_to_reveal"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:textColorSecondary" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -88,10 +88,10 @@
|
||||
<TextView
|
||||
android:id="@+id/bookmark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:drawableStart="@drawable/ic_fluent_bookmark_24_selector"
|
||||
android:drawablePadding="8dp"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:drawableTint="@color/bookmark_icon"
|
||||
android:gravity="center_vertical"
|
||||
android:textAppearance="@style/m3_label_large" />
|
||||
@@ -109,7 +109,7 @@
|
||||
<ImageView
|
||||
android:id="@+id/share"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_fluent_share_24_regular"
|
||||
android:paddingHorizontal="8dp"
|
||||
|
||||
@@ -25,4 +25,6 @@
|
||||
android:layout_margin="8dp"
|
||||
android:background="@drawable/ic_gif"/>
|
||||
|
||||
<include layout="@layout/alt_badge" />
|
||||
|
||||
</org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout>
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="11dp"
|
||||
android:paddingTop="13dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="16dp">
|
||||
|
||||
@@ -41,11 +41,35 @@
|
||||
android:src="@drawable/ic_visibility"
|
||||
android:tint="?android:textColorSecondary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/collapse_btn"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_toStartOf="@id/visibility"
|
||||
android:background="?android:actionBarItemBackground"
|
||||
android:visibility="gone"
|
||||
android:importantForAccessibility="noHideDescendants">
|
||||
|
||||
<!-- wrapping this button so the flip animation doesn't flip the background and the tooltip
|
||||
isn't displaced by the -1 scale -->
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/collapse_btn_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_fluent_chevron_down_20_filled"
|
||||
android:tint="?android:textColorSecondary" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/unread_indicator"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_toStartOf="@id/visibility"
|
||||
android:layout_toStartOf="@id/collapse_btn"
|
||||
android:visibility="gone"
|
||||
android:tint="?android:colorAccent"
|
||||
android:scaleType="center"
|
||||
@@ -58,14 +82,15 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginTop="5dp" />
|
||||
android:layout_marginTop="3dp" />
|
||||
|
||||
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
|
||||
android:id="@+id/name_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:paddingTop="4sp"
|
||||
android:layout_toStartOf="@id/unread_indicator"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:minHeight="24sp">
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
@@ -11,81 +10,6 @@
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<!-- This is hidden from screenreaders because that same alt text is set as content description on the ImageView -->
|
||||
<FrameLayout
|
||||
android:id="@+id/alt_text_wrapper"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|bottom"
|
||||
android:layout_margin="12dp"
|
||||
android:importantForAccessibility="noHideDescendants"
|
||||
android:background="@drawable/bg_image_alt_overlay">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/no_alt_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:src="@drawable/ic_fluent_important_20_filled"
|
||||
android:tint="?colorGray25" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/alt_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_label_large"
|
||||
android:textColor="?colorGray25"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:paddingVertical="1dp"
|
||||
android:text="@string/sk_alt_button"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/alt_text_close"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="end|top"
|
||||
android:src="@drawable/ic_baseline_close_24"
|
||||
android:tint="#FFF"
|
||||
android:background="?android:actionBarItemBackground"/>
|
||||
|
||||
<org.joinmastodon.android.ui.views.NestableScrollView
|
||||
android:id="@+id/alt_text_scroller"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="40dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/alt_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?colorGray25"
|
||||
tools:text="Alt text goes here"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/no_alt_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:textAppearance="@style/m3_label_large"
|
||||
android:textColor="?colorGray25"
|
||||
android:text="@string/sk_no_alt_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.joinmastodon.android.ui.views.NestableScrollView>
|
||||
|
||||
</FrameLayout>
|
||||
<include layout="@layout/alt_badge" />
|
||||
|
||||
</org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout>
|
||||
@@ -44,19 +44,48 @@
|
||||
android:background="?attr/colorPollVoted"/>
|
||||
</LinearLayout>
|
||||
|
||||
<org.joinmastodon.android.ui.views.LinkedTextView
|
||||
android:id="@+id/text"
|
||||
<org.joinmastodon.android.ui.views.UntouchableScrollView
|
||||
android:id="@+id/text_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:textSize="16sp"
|
||||
android:textAppearance="@style/m3_body_large"/>
|
||||
android:requiresFadingEdge="vertical"
|
||||
android:scrollbars="none"
|
||||
android:fadingEdgeLength="36dp">
|
||||
|
||||
<org.joinmastodon.android.ui.views.LinkedTextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:textAppearance="@style/m3_body_large"/>
|
||||
|
||||
</org.joinmastodon.android.ui.views.UntouchableScrollView>
|
||||
|
||||
<Space
|
||||
android:id="@+id/space_below_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/read_more"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_text_button"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:textAppearance="@style/m3_label_medium"
|
||||
android:textAllCaps="true"
|
||||
android:text="@string/sk_expand"
|
||||
android:visibility="gone"
|
||||
android:importantForAccessibility="no"/>
|
||||
|
||||
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout
|
||||
android:id="@+id/translate_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
@@ -68,8 +97,7 @@
|
||||
android:clipToPadding="false">
|
||||
<org.joinmastodon.android.ui.views.ProgressBarButton
|
||||
android:id="@+id/translate_btn"
|
||||
style="?secondaryButtonStyle"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:background="@drawable/bg_text_button"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -88,13 +116,16 @@
|
||||
android:visibility="gone"/>
|
||||
</FrameLayout>
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/translate_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textAlignment="textEnd"
|
||||
tools:text="Translated using TranslateEngine" />
|
||||
@@ -129,4 +160,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -18,4 +18,6 @@
|
||||
android:elevation="3dp"
|
||||
android:background="@drawable/play_button"/>
|
||||
|
||||
<include layout="@layout/alt_badge" />
|
||||
|
||||
</org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout>
|
||||
@@ -90,7 +90,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/self_avatar"
|
||||
android:layout_marginTop="2sp"
|
||||
android:paddingTop="4sp"
|
||||
android:minHeight="24sp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
android:layout_weight="1"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -28,6 +29,11 @@
|
||||
android:textColor="?colorM3OnSurface"
|
||||
android:text="@string/confirm_email_subtitle"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="230dp"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -37,6 +43,11 @@
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/confirm_email_art"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<me.grishka.appkit.views.FragmentRootLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/appkit_loader_root"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:background="?android:colorBackground">
|
||||
|
||||
<include layout="@layout/appkit_toolbar"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/appkit_loader_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<include layout="@layout/loading"
|
||||
android:id="@+id/loading"/>
|
||||
|
||||
<ViewStub android:layout="?errorViewLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/error"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/content_stub"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:background="@drawable/bg_onboarding_panel">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_next"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
style="@style/Widget.Mastodon.M3.Button.Tonal"
|
||||
android:text="@string/follow_all"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_skip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
style="@style/Widget.Mastodon.M3.Button.Filled"
|
||||
android:text="@string/skip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</me.grishka.appkit.views.FragmentRootLinearLayout>
|
||||
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroller"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="56dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textColor="?colorM3OnSurface"
|
||||
android:text="@string/profile_setup_subtitle"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="144dp"
|
||||
android:foreground="@drawable/ic_add_photo_alternate_48px"
|
||||
android:foregroundGravity="center"
|
||||
android:foregroundTint="?colorM3OnSecondaryContainer"
|
||||
android:scaleType="centerCrop"
|
||||
android:background="?colorM3SecondaryContainer"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="104dp"
|
||||
android:layout_height="104dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="-44dp"
|
||||
android:background="@drawable/bg_onboarding_avatar">
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="96dp"
|
||||
android:layout_gravity="center"
|
||||
android:foreground="@drawable/ic_add_photo_alternate_48px"
|
||||
android:foregroundGravity="center"
|
||||
android:foregroundTint="?colorM3OnSecondaryContainer"
|
||||
android:scaleType="centerCrop"
|
||||
android:background="?colorM3SecondaryContainer"/>
|
||||
</FrameLayout>
|
||||
|
||||
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
|
||||
android:id="@+id/display_name_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:paddingTop="4dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/display_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:padding="16dp"
|
||||
android:background="@null"
|
||||
android:elevation="0dp"
|
||||
android:inputType="textPersonName|textCapWords"
|
||||
android:autofillHints="name"
|
||||
android:singleLine="true"
|
||||
android:hint="@string/display_name"/>
|
||||
|
||||
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
|
||||
|
||||
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
|
||||
android:id="@+id/bio_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginTop="-8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:paddingTop="4dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/bio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:padding="16dp"
|
||||
android:background="@null"
|
||||
android:elevation="0dp"
|
||||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:hint="@string/profile_bio"/>
|
||||
|
||||
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
|
||||
|
||||
<org.joinmastodon.android.ui.views.ReorderableLinearLayout
|
||||
android:id="@+id/profile_fields"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/add_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textColor="?colorM3OnSurface"
|
||||
android:drawableEnd="@drawable/ic_add_24px"
|
||||
android:drawableTint="?colorM3OnSurface"
|
||||
android:drawablePadding="16dp"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:stateListAnimator="@null"
|
||||
android:text="@string/profile_add_row"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:textAppearance="@style/m3_body_small"
|
||||
android:textColor="?colorM3OnSurfaceVariant"
|
||||
android:text="@string/profile_setup_explanation"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:background="@drawable/bg_onboarding_panel"
|
||||
android:id="@+id/button_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_next"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:minWidth="145dp"
|
||||
style="@style/Widget.Mastodon.M3.Button.Filled"
|
||||
android:text="@string/next" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -7,6 +7,7 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroller"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
@@ -20,7 +21,8 @@
|
||||
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
|
||||
android:id="@+id/display_name_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="80dp"
|
||||
android:paddingTop="4dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
@@ -78,12 +80,14 @@
|
||||
<TextView
|
||||
android:id="@+id/domain"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:layout_height="56dp"
|
||||
android:layout_gravity="right|top"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="16dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:gravity="center_vertical"
|
||||
tools:text="\@mastodon.social"/>
|
||||
|
||||
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
|
||||
@@ -91,8 +95,9 @@
|
||||
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
|
||||
android:id="@+id/email_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
|
||||
@@ -125,8 +130,9 @@
|
||||
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
|
||||
android:id="@+id/password_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
|
||||
@@ -160,8 +166,9 @@
|
||||
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
|
||||
android:id="@+id/password_confirm_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
|
||||
@@ -188,6 +195,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="56dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginTop="-8dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:textAppearance="@style/m3_body_small"
|
||||
android:textColor="?colorM3OnSurfaceVariant"
|
||||
android:text="@string/password_note"/>
|
||||
@@ -198,6 +208,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:labelTextColor="@color/m3_outlined_text_field_label"
|
||||
android:foreground="@drawable/bg_m3_outlined_text_field">
|
||||
|
||||
@@ -223,6 +234,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="56dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginTop="-8dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:textAppearance="@style/m3_body_small"
|
||||
android:textColor="?colorM3OnSurfaceVariant"
|
||||
android:text="@string/signup_reason_note"/>
|
||||
@@ -235,7 +249,8 @@
|
||||
android:id="@+id/button_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/bg_onboarding_panel">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_next"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<me.grishka.appkit.views.RecursiveSwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<me.grishka.appkit.views.RecursiveSwipeRefreshLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/refresh_layout"
|
||||
@@ -22,7 +23,6 @@
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="15dp"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<org.joinmastodon.android.ui.views.CoverImageView
|
||||
@@ -58,7 +58,7 @@
|
||||
android:layout_height="112dp"
|
||||
android:layout_below="@id/cover"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginTop="-40dp"
|
||||
android:layout_marginTop="-56dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:outlineProvider="@null"
|
||||
android:background="@drawable/profile_ava_bg">
|
||||
@@ -74,110 +74,18 @@
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/profile_counters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/cover"
|
||||
android:layout_toEndOf="@id/avatar_border"
|
||||
android:gravity="end">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/posts_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="4dp">
|
||||
<TextView
|
||||
android:id="@+id/posts_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="123" />
|
||||
<TextView
|
||||
android:id="@+id/posts_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_small"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="middle"
|
||||
tools:text="posts" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/following_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:padding="4dp"
|
||||
android:orientation="vertical"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:gravity="center_horizontal">
|
||||
<TextView
|
||||
android:id="@+id/following_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="123"/>
|
||||
<TextView
|
||||
android:id="@+id/following_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_small"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="middle"
|
||||
tools:text="following"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/followers_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:padding="4dp"
|
||||
android:orientation="vertical"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:gravity="center_horizontal">
|
||||
<TextView
|
||||
android:id="@+id/followers_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="123"/>
|
||||
<TextView
|
||||
android:id="@+id/followers_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_small"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="middle"
|
||||
tools:text="followers"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/profile_action_btn_wrap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/profile_counters"
|
||||
android:layout_below="@id/cover"
|
||||
android:layout_alignParentEnd="true">
|
||||
|
||||
<FrameLayout
|
||||
android:clipToPadding="false"
|
||||
android:paddingVertical="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="4dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<org.joinmastodon.android.ui.views.ProgressBarButton
|
||||
@@ -203,8 +111,8 @@
|
||||
<FrameLayout
|
||||
android:clipToPadding="false"
|
||||
android:paddingVertical="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingStart="4dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<org.joinmastodon.android.ui.views.ProgressBarButton
|
||||
@@ -227,52 +135,53 @@
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout
|
||||
android:id="@+id/name_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/avatar_border"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="17dp"
|
||||
android:layout_marginBottom="0.4dp"
|
||||
android:layout_toStartOf="@id/profile_action_btn_wrap"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/m3_headline_small"
|
||||
tools:text="Eugen" />
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/m3_headline_small"
|
||||
tools:text="Eugen" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/roles"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
</org.joinmastodon.android.ui.views.AutoOrientationLinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_below="@id/name_wrap"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="\@Gargron" />
|
||||
|
||||
<org.joinmastodon.android.ui.views.LinkedTextView
|
||||
android:id="@+id/bio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/username"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textSize="16sp"
|
||||
tools:text="Founder, CEO and lead developer @Mastodon, Germany." />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/name_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/avatar_border"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_toStartOf="@id/profile_action_btn_wrap"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textSize="16sp"
|
||||
android:background="@drawable/edit_text_border"
|
||||
@@ -281,28 +190,152 @@
|
||||
android:elevation="0dp"
|
||||
tools:text="Eugen" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/bio_edit"
|
||||
<FrameLayout
|
||||
android:id="@+id/bio_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/username"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textSize="16sp"
|
||||
android:background="@drawable/edit_text_border"
|
||||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:visibility="gone"
|
||||
android:elevation="0dp"
|
||||
tools:text="Founder, CEO and lead developer @Mastodon, Germany." />
|
||||
android:layout_marginHorizontal="16dp">
|
||||
|
||||
<org.joinmastodon.android.ui.views.LinkedTextView
|
||||
android:id="@+id/bio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textSize="16sp"
|
||||
tools:text="Founder, CEO and lead developer @Mastodon, Germany." />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/bio_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textSize="16sp"
|
||||
android:background="@drawable/edit_text_border"
|
||||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:visibility="gone"
|
||||
android:elevation="0dp"
|
||||
tools:text="Founder, CEO and lead developer @Mastodon, Germany." />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/border_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_below="@id/bio_container"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="?attr/colorPollVoted"/>
|
||||
|
||||
<me.grishka.appkit.views.UsableRecyclerView
|
||||
android:id="@+id/metadata"
|
||||
android:background="?colorBackgroundLightest"
|
||||
android:layout_below="@id/border_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp" />
|
||||
|
||||
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout
|
||||
android:id="@+id/profile_counters"
|
||||
android:background="?colorBackgroundLightest"
|
||||
android:layout_below="@id/metadata"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingHorizontal="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/posts_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:minHeight="36dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/posts_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="123" />
|
||||
<TextView
|
||||
android:id="@+id/posts_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4sp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="middle"
|
||||
tools:text="posts" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/following_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:minHeight="36dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@drawable/bg_text_button">
|
||||
<TextView
|
||||
android:id="@+id/following_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="123"/>
|
||||
<TextView
|
||||
android:id="@+id/following_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4sp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="middle"
|
||||
tools:text="following"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/followers_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:minHeight="36dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@drawable/bg_text_button">
|
||||
<TextView
|
||||
android:id="@+id/followers_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="123"/>
|
||||
<TextView
|
||||
android:id="@+id/followers_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4sp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="middle"
|
||||
tools:text="followers"/>
|
||||
</LinearLayout>
|
||||
</org.joinmastodon.android.ui.views.AutoOrientationLinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<org.joinmastodon.android.ui.tabs.TabLayout
|
||||
android:id="@+id/tabbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:paddingHorizontal="4dp"
|
||||
android:background="?colorBackgroundLightest"
|
||||
app:tabPaddingStart="12dp"
|
||||
app:tabPaddingEnd="12dp"
|
||||
app:tabMinWidth="0dp"
|
||||
@@ -311,6 +344,14 @@
|
||||
app:tabIndicatorColor="?android:textColorPrimary"
|
||||
app:tabMode="scrollable"
|
||||
app:tabGravity="start"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/border_bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginTop="-0.5dp"
|
||||
android:background="?attr/colorPollVoted"/>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
@@ -318,7 +359,7 @@
|
||||
</LinearLayout>
|
||||
</org.joinmastodon.android.ui.views.NestedRecyclerScrollView>
|
||||
|
||||
<ImageButton android:id="@+id/fab" style="@style/Widget.Mastodon.Button.Compose"/>
|
||||
<include layout="@layout/compose_fab" />
|
||||
</FrameLayout>
|
||||
|
||||
</me.grishka.appkit.views.RecursiveSwipeRefreshLayout>
|
||||
@@ -64,6 +64,7 @@
|
||||
android:contentDescription="@string/clear"
|
||||
android:stateListAnimator="@null"
|
||||
android:elevation="0dp"
|
||||
android:tint="?colorM3OnSurfaceVariant"
|
||||
android:src="@drawable/ic_m3_cancel"/>
|
||||
|
||||
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="62dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="8dp"
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="46dp"
|
||||
android:layout_height="46dp"
|
||||
android:layout_width="46sp"
|
||||
android:layout_height="46sp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:importantForAccessibility="no"
|
||||
tools:src="#0f0"/>
|
||||
@@ -29,9 +29,10 @@
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="24dp"
|
||||
android:layout_height="24sp"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:layout_toStartOf="@id/button"
|
||||
android:layout_marginTop="2sp"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
@@ -41,7 +42,7 @@
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_height="20sp"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:layout_toStartOf="@id/button"
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorBackgroundLight"
|
||||
android:elevation="2dp"
|
||||
android:outlineProvider="background"
|
||||
android:padding="16dp">
|
||||
android:paddingHorizontal="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_label_medium"
|
||||
android:minHeight="16dp"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="12sp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
tools:text="Field title"/>
|
||||
|
||||
<org.joinmastodon.android.ui.views.LinkedTextView
|
||||
android:id="@+id/value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="2"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textSize="16sp"
|
||||
android:textIsSelectable="true"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="2dp"
|
||||
tools:text="Field value"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -4,9 +4,7 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorBackgroundLight"
|
||||
android:elevation="2dp"
|
||||
android:outlineProvider="background">
|
||||
android:layout_marginBottom="4dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/remove_row_btn"
|
||||
@@ -26,11 +24,12 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/dragger_thingy"
|
||||
android:layout_toEndOf="@id/remove_row_btn"
|
||||
android:layout_marginTop="16dp"
|
||||
android:minHeight="24dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:gravity="bottom"
|
||||
android:textAppearance="@style/m3_label_medium"
|
||||
android:background="@drawable/bg_profile_field_edit_text"
|
||||
android:hint="@string/field_label"
|
||||
android:minHeight="16dp"
|
||||
android:inputType="textCapSentences"
|
||||
tools:text="Field title"/>
|
||||
|
||||
@@ -41,7 +40,9 @@
|
||||
android:layout_below="@id/title"
|
||||
android:layout_toStartOf="@id/dragger_thingy"
|
||||
android:layout_toEndOf="@id/remove_row_btn"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:minHeight="28dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:gravity="bottom"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:background="@drawable/bg_profile_field_edit_text"
|
||||
android:hint="@string/field_content"
|
||||
@@ -55,7 +56,6 @@
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignBottom="@id/value"
|
||||
android:layout_marginBottom="-16dp"
|
||||
android:scaleType="center"
|
||||
android:contentDescription="@string/reorder"
|
||||
android:src="@drawable/ic_fluent_re_order_dots_vertical_24_regular"/>
|
||||
|
||||
94
mastodon/src/main/res/layout/item_user_row_m3.xml
Normal file
94
mastodon/src/main/res/layout/item_user_row_m3.xml
Normal file
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:importantForAccessibility="no"
|
||||
tools:src="#0f0"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/action_btn_wrap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginStart="-8dp">
|
||||
|
||||
<org.joinmastodon.android.ui.views.ProgressBarButton
|
||||
android:id="@+id/action_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
style="@style/Widget.Mastodon.M3.Button.Filled"
|
||||
tools:text="Follow"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/action_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
style="?android:progressBarStyleSmall"
|
||||
android:elevation="10dp"
|
||||
android:outlineProvider="none"
|
||||
android:indeterminateTint="?colorM3OnPrimary"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="24dp"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:layout_toStartOf="@id/action_btn_wrap"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:textColor="?colorM3OnSurface"
|
||||
tools:text="User Name"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_toStartOf="@id/action_btn_wrap"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:textAppearance="@style/m3_title_small"
|
||||
android:textColor="?colorM3OnSurfaceVariant"
|
||||
tools:text="\@username@server.social"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/avatar"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?colorM3OnSurface"
|
||||
tools:text="Description"/>
|
||||
|
||||
</RelativeLayout>
|
||||
62
mastodon/src/main/res/layout/onboarding_profile_field.xml
Normal file
62
mastodon/src/main/res/layout/onboarding_profile_field.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:clipToPadding="false"
|
||||
android:background="?colorM3Background">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dragger_thingy"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:scaleType="center"
|
||||
android:tint="?colorM3OnSurface"
|
||||
android:contentDescription="@string/reorder"
|
||||
android:src="@drawable/ic_drag_handle_24px"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:scaleType="center"
|
||||
android:tint="?colorM3OnSurface"
|
||||
android:background="?android:actionBarItemBackground"
|
||||
android:contentDescription="@string/delete"
|
||||
android:src="@drawable/ic_delete_24px"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_toEndOf="@id/dragger_thingy"
|
||||
android:layout_toStartOf="@id/delete"
|
||||
style="@style/Widget.Mastodon.M3.EditText"
|
||||
android:inputType="textCapSentences"
|
||||
android:hint="@string/field_content"
|
||||
android:saveEnabled="false"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_toEndOf="@id/dragger_thingy"
|
||||
android:layout_toStartOf="@id/delete"
|
||||
android:layout_below="@id/content"
|
||||
style="@style/Widget.Mastodon.M3.EditText"
|
||||
android:inputType="textCapSentences"
|
||||
android:hint="@string/field_label"
|
||||
android:saveEnabled="false"
|
||||
android:singleLine="true"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -20,6 +20,6 @@
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/empty"/>
|
||||
|
||||
<ImageButton android:id="@+id/fab" style="@style/Widget.Mastodon.Button.Compose"/>
|
||||
<include layout="@layout/compose_fab" />
|
||||
</FrameLayout>
|
||||
</me.grishka.appkit.views.RecursiveSwipeRefreshLayout>
|
||||
@@ -1,9 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">الخطوات الأولى</string>
|
||||
<string name="get_started">إنشاء حساب</string>
|
||||
<string name="already_have_account">لدي حساب بالفعل</string>
|
||||
<string name="log_in">تسجيلُ الدخول</string>
|
||||
<string name="next">التالي</string>
|
||||
<string name="loading_instance">جارٍ جلب معلومات الخادم…</string>
|
||||
<string name="error">خطأ</string>
|
||||
<string name="not_a_mastodon_instance">لا يبدو أنّ %s كخادم ماستدون.</string>
|
||||
<string name="ok">حسنًا</string>
|
||||
<string name="preparing_auth">جَارٍ الإعدَادُ لِلمُصادَقَة…</string>
|
||||
<string name="finishing_auth">يُنهي المصادقة…</string>
|
||||
@@ -226,15 +229,16 @@
|
||||
<string name="back">العودة</string>
|
||||
<string name="instance_catalog_title">يتكوّن ماستدون من مستخدمين موزّعين عبر خوادم مختلفة.</string>
|
||||
<string name="instance_catalog_subtitle">اختر خادمًا بناءً على اهتماماتك، منطقتك أو يمكنك حتى اختيارُ مجتمعٍ ذي غرضٍ عام. وسيضل بامكانك التواصل مع المستخدمين من الخوادم الأخرى.</string>
|
||||
<string name="search_communities">ابحث عن خادم أو أدخل رابطه</string>
|
||||
<string name="instance_rules_title">بعض القواعد الأساسية</string>
|
||||
<string name="instance_rules_subtitle">خذ دقيقة لمراجعة القواعد التي حددها وفرضها مديروا %s.</string>
|
||||
<string name="signup_title">دعنا نجهزك في %s</string>
|
||||
<string name="search_communities">اسم الخادم أو عنوان URL</string>
|
||||
<string name="instance_rules_title">قواعد الخادم</string>
|
||||
<string name="instance_rules_subtitle">من خلال المتابعة، أنت توافق على اتباع القواعد التالية التي تم تعيينها وإنفاذها من قبل مشرفي %s.</string>
|
||||
<string name="signup_title">إنشاء حساب</string>
|
||||
<string name="edit_photo">حرّر</string>
|
||||
<string name="display_name">الاسم العلني</string>
|
||||
<string name="display_name">الاسم</string>
|
||||
<string name="username">اسم المستخدم</string>
|
||||
<string name="email">البريد الإلكتروني</string>
|
||||
<string name="password">كلمة المرور</string>
|
||||
<string name="confirm_password">تأكيد كلمة المرور</string>
|
||||
<string name="password_note">ضمّن الأحرف الكبيرة والأحرف الخاصة والأرقام لزيادة قوة كلمة المرور.</string>
|
||||
<string name="category_academia">أكاديمي</string>
|
||||
<string name="category_activism">النشطاء</string>
|
||||
@@ -249,8 +253,10 @@
|
||||
<string name="category_music">موسيقى</string>
|
||||
<string name="category_regional">إقليمي</string>
|
||||
<string name="category_tech">تقني</string>
|
||||
<string name="confirm_email_title">شيءٌ أخير</string>
|
||||
<string name="confirm_email_subtitle">أنقر على الرابط المرسل إليك لاستيثاق حسابك.</string>
|
||||
<string name="confirm_email_title">تحقق من صندوق الوارد الخاص بك</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="confirm_email_subtitle">اضغط على الرابط الذي أرسلناه لك للتحقق من %s. سننتظر هنا.</string>
|
||||
<string name="confirm_email_didnt_get">ألم تحصل على رابط؟</string>
|
||||
<string name="resend">أعد الإرسال</string>
|
||||
<string name="open_email_app">افتح تطبيق البريد الإلكتروني</string>
|
||||
<string name="resent_email">أُرسلت رسالة التأكيد</string>
|
||||
@@ -342,7 +348,7 @@
|
||||
<string name="open_in_browser">افتح في المتصفح</string>
|
||||
<string name="hide_boosts_from_user">اخف ما أعاد %s تدوينه</string>
|
||||
<string name="show_boosts_from_user">أظهر ما أعاد %s تدوينه</string>
|
||||
<string name="signup_reason">لماذا ترغب في الانضمام؟</string>
|
||||
<string name="signup_reason">لماذا تريد الانضمام؟</string>
|
||||
<string name="signup_reason_note">هذا سوف يساعدنا في مراجعة تطبيقك.</string>
|
||||
<string name="clear">امسح</string>
|
||||
<string name="profile_header">الصورة الفوقية</string>
|
||||
@@ -459,8 +465,54 @@
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">جارٍ التنزيل (%s)</string>
|
||||
<string name="install_update">تثبيت</string>
|
||||
<string name="privacy_policy_title">ماستدون وخصوصيتك</string>
|
||||
<string name="privacy_policy_subtitle">على الرغم من أن تطبيق ماستدون لا يجمع أي بيانات، فإن الخادم الذي قمت بالتسجيل من خلاله قد تكون له سياسة مختلفة. خذ دقيقة للمراجعة والموافقة على سياسة خصوصية التطبيق ماستدون وسياسة الخصوصية للخادم الخاص بك.</string>
|
||||
<string name="privacy_policy_title">خصوصيتك</string>
|
||||
<string name="privacy_policy_subtitle">على الرغم من أن تطبيق ماستدون لا يجمع أي بيانات، فإن الخادم الذي قمت بالتسجيل من خلاله قد تكون له سياسة مختلفة.\n\nإذا لم توافق على سياسة %s، يمكنك العودة واختيار خادم مختلف.</string>
|
||||
<string name="i_agree">أنا مُوافِق</string>
|
||||
<string name="empty_list">هذه القائمة فارغة</string>
|
||||
<string name="instance_signup_closed">هذا الخادم لا يقبل التسجيلات الجديدة.</string>
|
||||
<string name="text_copied">نُسِخ إلى الحافظة</string>
|
||||
<string name="add_bookmark">إضافة إلى الفواصل المرجعية</string>
|
||||
<string name="remove_bookmark">إزالة الفاصلة المرجعية</string>
|
||||
<string name="bookmarks">الفواصل المرجعية</string>
|
||||
<string name="your_favorites">مفضّلاتك</string>
|
||||
<string name="login_title">مرحبا بك مجددًا</string>
|
||||
<string name="login_subtitle">قم بتسجيل الدخول باستخدام الخادم حيث قمتَ بإنشاء حسابك فيه.</string>
|
||||
<string name="server_url">رابط الخادم</string>
|
||||
<string name="welcome_page1_title">ما هو ماستدون؟</string>
|
||||
<string name="welcome_page1_text">تخيل أن لديك عنوان بريد إلكتروني ينتهي بـ @example.com.\n\n رغم ذلك يمكنك إرسال واستقبال رسائل البريد الإلكتروني من أي شخص، حتى إذا كان بريدهم الإلكتروني الخاص ينتهي بـ @gmail.com أو @icloud.com أو @example.com.</string>
|
||||
<string name="welcome_page2_title">ماستدون هكذا.</string>
|
||||
<string name="welcome_page2_text">قد يكون مُعرّفُك @gothgirl654@example.social ، ولكنه بإمكانك متابعة وإعادة تدوين ومحادثة @fallout5ever@example.online.</string>
|
||||
<string name="welcome_page3_title">كيف يمكنني اختيار خادم؟</string>
|
||||
<string name="welcome_page3_text">يختار الأشخاص المختلفون خوادم مختلفة لأي عدد من الأسباب. يعد art.example مكانًا رائعًا للفنانين ، بينما قد يكون glasgow.example اختيارًا جيدًا للاسكتلنديين. \n\n لا يمكنك أن تخطئ في أي من الخوادم التي نوصي بها ، لذلك بغض النظر عن أي واحد تختاره (أو إذا قمت بإدخال الخادم الخاص بك في شريط البحث) ، فلن يفوتك أي شيء في أي مكان.</string>
|
||||
<string name="signup_random_server_explain">سوف نختار خادماً بناءً على لغتك إذا قمت بالمتابعة دون إجراء إختيار.</string>
|
||||
<string name="server_filter_any_language">أي لغة</string>
|
||||
<string name="server_filter_instant_signup">تسجيل فوري</string>
|
||||
<string name="server_filter_manual_review">مراجعة يدوية</string>
|
||||
<string name="server_filter_any_signup_speed">أي سرعة تسجيل</string>
|
||||
<string name="server_filter_region_europe">أوروبا</string>
|
||||
<string name="server_filter_region_north_america">أمريكا الشمالية</string>
|
||||
<string name="server_filter_region_south_america">أمريكا الجنوبية</string>
|
||||
<string name="server_filter_region_africa">أفريقيا</string>
|
||||
<string name="server_filter_region_asia">آسيا</string>
|
||||
<string name="server_filter_region_oceania">أوقيانوسيا</string>
|
||||
<string name="not_accepting_new_members">لا يقبل استقبال أعضاء جدد</string>
|
||||
<string name="category_special_interests">المصالح الخاصة</string>
|
||||
<string name="signup_passwords_dont_match">كلمات المرور غير متطابقة</string>
|
||||
<string name="pick_server_for_me">اختر لي</string>
|
||||
<string name="profile_add_row">إضافة صف</string>
|
||||
<string name="profile_setup">إعداد الملف الشخصي</string>
|
||||
<string name="profile_setup_subtitle">يمكنك دائماً إكمال هذا في وقت لاحق في علامة التبويب الملف الشخصي.</string>
|
||||
<string name="profile_setup_explanation">يمكنك إضافة ما يصل إلى أربعة حقول شخصية لأي شيء تريده. الموقع، الروابط، الضمائر - السماء هي الحد الأقصى.</string>
|
||||
<string name="popular_on_mastodon">مشهور على ماستدون</string>
|
||||
<string name="follow_all">اتبع الكل</string>
|
||||
<string name="server_rules_disagree">لا أوافق</string>
|
||||
<string name="privacy_policy_explanation">بالمختصر: نحن لا نجمع أو نعالج أي شيء.</string>
|
||||
<!-- %s is server domain -->
|
||||
<string name="server_policy_disagree">لايتفق مع %s</string>
|
||||
<string name="profile_bio">نبذة عنك</string>
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<string name="sending_follows">متابعة المستخدمين…</string>
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
<string name="signup_email_domain_blocked">%1$s لا يسمح بالتسجيلات من %2$s. جرب واحدا أو <a>اختار خادم مختلف</a>.</string>
|
||||
<string name="signup_username_taken">اِسم المُستَخدِم هذا مأخوذٌ بالفعل.</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,16 +1,432 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">Пачаць</string>
|
||||
<string name="get_started">Стварыць уліковы запіс</string>
|
||||
<string name="already_have_account">У мяне ўжо ёсць уліковы запіс</string>
|
||||
<string name="log_in">Увайсці</string>
|
||||
<string name="next">Далей</string>
|
||||
<string name="loading_instance">Атрыманне інфармацыі аб серверы…</string>
|
||||
<string name="error">Памылка</string>
|
||||
<string name="not_a_mastodon_instance">Здаецца, %s не з\'яўляецца серверам Mastodon.</string>
|
||||
<string name="ok">Добра</string>
|
||||
<string name="preparing_auth">Падрыхтоўка да аўтэнтыфікацыі…</string>
|
||||
<string name="finishing_auth">Завяршэнне аўтэнтыфікацыі…</string>
|
||||
<string name="user_boosted">%s пашырыў</string>
|
||||
<string name="in_reply_to">У адказ %s</string>
|
||||
<string name="notifications">Апавяшчэнні</string>
|
||||
<string name="user_followed_you">падпісаўся(-лася) на вас</string>
|
||||
<string name="user_sent_follow_request">адправіў запыт на падпіску</string>
|
||||
<string name="user_favorited">упадабаў(-ла) ваш допіс</string>
|
||||
<string name="notification_boosted">пашырыў(-ла) ваш допіс</string>
|
||||
<string name="poll_ended">апытанне завершана</string>
|
||||
<string name="time_seconds">%dсек</string>
|
||||
<string name="time_minutes">%dхв</string>
|
||||
<string name="time_hours">%dгадз</string>
|
||||
<string name="time_days">%dдз</string>
|
||||
<string name="share_toot_title">Абагуліць</string>
|
||||
<string name="settings">Налады</string>
|
||||
<string name="publish">Апублікаваць</string>
|
||||
<string name="discard_draft">Скасаваць чарнавік?</string>
|
||||
<string name="discard">Скасаваць</string>
|
||||
<string name="cancel">Скасаваць</string>
|
||||
<plurals name="followers">
|
||||
<item quantity="one">падпісчык</item>
|
||||
<item quantity="few">падпісчыка</item>
|
||||
<item quantity="many">падпісчыкаў</item>
|
||||
<item quantity="other">падпісчыкаў</item>
|
||||
</plurals>
|
||||
<plurals name="following">
|
||||
<item quantity="one">падпісаны</item>
|
||||
<item quantity="few">падпісаны</item>
|
||||
<item quantity="many">падпісаны</item>
|
||||
<item quantity="other">падпісаны</item>
|
||||
</plurals>
|
||||
<plurals name="posts">
|
||||
<item quantity="one">допіс</item>
|
||||
<item quantity="few">допісы</item>
|
||||
<item quantity="many">допісаў</item>
|
||||
<item quantity="other">допісаў</item>
|
||||
</plurals>
|
||||
<string name="posts">Допісы</string>
|
||||
<string name="posts_and_replies">Допісы і адказы</string>
|
||||
<string name="media">Медыя</string>
|
||||
<string name="profile_about">Інфармацыя</string>
|
||||
<string name="button_follow">Падпісацца</string>
|
||||
<string name="button_following">Вы падпісаны</string>
|
||||
<string name="edit_profile">Рэдагаваць профіль</string>
|
||||
<string name="mention_user">Згадаць %s</string>
|
||||
<string name="share_user">Абагуліць %s</string>
|
||||
<string name="mute_user">Ігнараваць %s</string>
|
||||
<string name="unmute_user">Не ігнараваць %s</string>
|
||||
<string name="block_user">Заблакіраваць %s</string>
|
||||
<string name="unblock_user">Разблакіраваць %s</string>
|
||||
<string name="report_user">Паскардзіцца на %s</string>
|
||||
<string name="block_domain">Заблакіраваць %s</string>
|
||||
<string name="unblock_domain">Разблакіраваць %s</string>
|
||||
<plurals name="x_posts">
|
||||
<item quantity="one">%,d допіс</item>
|
||||
<item quantity="few">%,d допісы</item>
|
||||
<item quantity="many">%,d допісаў</item>
|
||||
<item quantity="other">%,d допісаў</item>
|
||||
</plurals>
|
||||
<string name="profile_joined">Далучыўся</string>
|
||||
<string name="done">Гатова</string>
|
||||
<string name="loading">Загрузка…</string>
|
||||
<string name="field_label">Метка</string>
|
||||
<string name="field_content">Змесціва</string>
|
||||
<string name="saving">Захаванне…</string>
|
||||
<string name="post_from_user">Допіс ад %s</string>
|
||||
<string name="poll_option_hint">Варыянт %d</string>
|
||||
<plurals name="x_minutes">
|
||||
<item quantity="one">%d хвіліна</item>
|
||||
<item quantity="few">%d хвіліны</item>
|
||||
<item quantity="many">%d хвілін</item>
|
||||
<item quantity="other">%d хвілін</item>
|
||||
</plurals>
|
||||
<plurals name="x_hours">
|
||||
<item quantity="one">%d гадзіна</item>
|
||||
<item quantity="few">%d гадзіны</item>
|
||||
<item quantity="many">%d гадзін</item>
|
||||
<item quantity="other">%d гадзін</item>
|
||||
</plurals>
|
||||
<plurals name="x_days">
|
||||
<item quantity="one">%d дзень</item>
|
||||
<item quantity="few">%d дні</item>
|
||||
<item quantity="many">%d дзён</item>
|
||||
<item quantity="other">%d дзён</item>
|
||||
</plurals>
|
||||
<string name="compose_poll_duration">Працягласць: %s</string>
|
||||
<plurals name="x_seconds_left">
|
||||
<item quantity="one">%d секунда засталася</item>
|
||||
<item quantity="few">%d секунды засталося</item>
|
||||
<item quantity="many">%d секунд засталося</item>
|
||||
<item quantity="other">%d секунд засталося</item>
|
||||
</plurals>
|
||||
<plurals name="x_minutes_left">
|
||||
<item quantity="one">%d хвіліна засталася</item>
|
||||
<item quantity="few">%d хвіліны засталося</item>
|
||||
<item quantity="many">%d хвілін засталося</item>
|
||||
<item quantity="other">%d хвілін засталося</item>
|
||||
</plurals>
|
||||
<plurals name="x_hours_left">
|
||||
<item quantity="one">%d гадзіна засталася</item>
|
||||
<item quantity="few">%d гадзіны засталося</item>
|
||||
<item quantity="many">%d гадзін засталося</item>
|
||||
<item quantity="other">%d гадзін засталося</item>
|
||||
</plurals>
|
||||
<plurals name="x_days_left">
|
||||
<item quantity="one">%d дзень застаўся</item>
|
||||
<item quantity="few">%d дні засталося</item>
|
||||
<item quantity="many">%d дзён засталося</item>
|
||||
<item quantity="other">%d дзён засталося</item>
|
||||
</plurals>
|
||||
<plurals name="x_voters">
|
||||
<item quantity="one">%,d прагаласаваў</item>
|
||||
<item quantity="few">%,d прагаласавала</item>
|
||||
<item quantity="many">%,d прагаласавала</item>
|
||||
<item quantity="other">%,d прагаласавала</item>
|
||||
</plurals>
|
||||
<string name="poll_closed">Завершана</string>
|
||||
<string name="confirm_mute_title">Ігнараваць уліковы запіс</string>
|
||||
<string name="confirm_mute">Ігнараваць %s?</string>
|
||||
<string name="do_mute">Ігнараваць</string>
|
||||
<string name="confirm_unmute_title">Не ігнараваць уліковы запіс</string>
|
||||
<string name="confirm_unmute">Не ігнараваць %s?</string>
|
||||
<string name="do_unmute">Не ігнараваць</string>
|
||||
<string name="confirm_block_title">Заблакіраваць уліковы запіс</string>
|
||||
<string name="confirm_block_domain_title">Заблакіраваць дамен</string>
|
||||
<string name="confirm_block">Заблакіраваць %s?</string>
|
||||
<string name="do_block">Заблакіраваць</string>
|
||||
<string name="confirm_unblock_title">Разблакіраваць уліковы запіс</string>
|
||||
<string name="confirm_unblock_domain_title">Разблакіраваць дамен</string>
|
||||
<string name="confirm_unblock">Разблакіраваць %s?</string>
|
||||
<string name="do_unblock">Разблакіраваць</string>
|
||||
<string name="button_muted">Ігнаруецца</string>
|
||||
<string name="button_blocked">Заблакіраваны</string>
|
||||
<string name="action_vote">Прагаласаваць</string>
|
||||
<string name="tap_to_reveal">Націсніце, каб паказаць</string>
|
||||
<string name="delete">Выдаліць</string>
|
||||
<string name="confirm_delete_title">Выдаліць допіс</string>
|
||||
<string name="confirm_delete">Вы ўпэўненыя, што хочаце выдаліць гэты допіс?</string>
|
||||
<string name="deleting">Выдаленне…</string>
|
||||
<string name="notification_channel_audio_player">Прайграванне аўдыя</string>
|
||||
<string name="play">Прайграць</string>
|
||||
<string name="pause">Прыпыніць</string>
|
||||
<string name="log_out">Выйсці</string>
|
||||
<string name="add_account">Дадаць уліковы запіс</string>
|
||||
<string name="search_hint">Пошук</string>
|
||||
<string name="hashtags">Хэштэгі</string>
|
||||
<string name="news">Навіны</string>
|
||||
<string name="for_you">Для вас</string>
|
||||
<string name="all_notifications">Усе</string>
|
||||
<string name="mentions">Згадванні</string>
|
||||
<plurals name="x_people_talking">
|
||||
<item quantity="one">%d чалавек размаўляе</item>
|
||||
<item quantity="few">%d чалавекі размаўляе</item>
|
||||
<item quantity="many">%d чалавек размаўляе</item>
|
||||
<item quantity="other">%d чалавек размаўляе</item>
|
||||
</plurals>
|
||||
<plurals name="discussed_x_times">
|
||||
<item quantity="one">Абмяркоўвалася %d раз</item>
|
||||
<item quantity="few">Абмяркоўвалася %d разы</item>
|
||||
<item quantity="many">Абмяркоўвалася %d разоў</item>
|
||||
<item quantity="other">Абмяркоўвалася %d разоў</item>
|
||||
</plurals>
|
||||
<string name="report_title">Паскардзіцца на %s</string>
|
||||
<string name="report_choose_reason">Што не так з гэтым допісам?</string>
|
||||
<string name="report_choose_reason_account">Што не так з %s?</string>
|
||||
<string name="report_choose_reason_subtitle">Выберыце найлепшы варыянт</string>
|
||||
<string name="report_reason_personal">Мне не падабаецца</string>
|
||||
<string name="report_reason_personal_subtitle">Гэта не тое, што вы хочаце бачыць</string>
|
||||
<string name="report_reason_spam">Гэта спам</string>
|
||||
<string name="report_reason_spam_subtitle">Шкодныя спасылкі, фальшывыя ўзаемадзеянні або адказы, што паўтараюцца</string>
|
||||
<string name="report_reason_violation">Гэта парушае правілы сервера</string>
|
||||
<string name="report_reason_violation_subtitle">Вам вядома, што гэта парушае пэўныя правілы</string>
|
||||
<string name="report_reason_other">Гэта нешта іншае</string>
|
||||
<string name="report_reason_other_subtitle">Гэта праблема не падпадае ні пад адну з катэгорыі</string>
|
||||
<string name="report_choose_rule">Якія правілы былі парушаны?</string>
|
||||
<string name="report_choose_rule_subtitle">Абярыце ўсе варыянты, што падыходзяць</string>
|
||||
<string name="report_choose_posts">Ці ёсць допісы, якія пацвярджаюць гэтую скаргу?</string>
|
||||
<string name="report_choose_posts_subtitle">Абярыце ўсе варыянты, што падыходзяць</string>
|
||||
<string name="report_comment_title">Што-небудзь яшчэ, што мы павінны ведаць?</string>
|
||||
<string name="report_comment_hint">Дадатковыя каментарыі</string>
|
||||
<string name="sending_report">Адпраўка скаргі…</string>
|
||||
<string name="report_sent_title">Дзякуй за вашу скаргу, мы яе разгледзім.</string>
|
||||
<string name="report_sent_subtitle">Пакуль мы разглядаем яе, вы можаце прыняць меры супраць %s.</string>
|
||||
<string name="unfollow_user">Адпісацца ад %s</string>
|
||||
<string name="unfollow">Адпісацца</string>
|
||||
<string name="mute_user_explain">Вы не ўбачыце іх допісы або пашырэнні ў сваёй хатняй стужцы. Яны не даведаюцца, што вы іх ігнаруеце.</string>
|
||||
<string name="block_user_explain">Яны больш не змогуць падпісвацца на вас або бачыць вашыя допісы, але змогуць бачыць, што яны былі заблакіраваны.</string>
|
||||
<string name="report_personal_title">Не хочаце бачыць гэта?</string>
|
||||
<string name="report_personal_subtitle">Калі вы бачыце на Mastodon нешта, што вам не падабаецца, вы можаце выдаліць чалавека са свайго асяроддзя.</string>
|
||||
<string name="back">Назад</string>
|
||||
<string name="instance_catalog_title">Mastodon складаецца з карыстальнікаў на розных серверах.</string>
|
||||
<string name="instance_catalog_subtitle">Выбірайце сервер у залежнасці ад вашых інтарэсаў, рэгіёна або выберыце сервер агульнага прызначэння. Вы па-ранейшаму можаце ўзаемадзейнічаць з усімі, незалежна ад сервера.</string>
|
||||
<string name="edit_photo">рэдагаваць</string>
|
||||
<string name="password_note">Выкарыстоўвайце вялікія літары, спецыяльныя сімвалы і лічбы, каб павялічыць надзейнасць пароля.</string>
|
||||
<string name="category_academia">Акадэмія</string>
|
||||
<string name="category_activism">Актывізм</string>
|
||||
<string name="category_all">Усе</string>
|
||||
<string name="category_art">Мастацтва</string>
|
||||
<string name="category_food">Ежа</string>
|
||||
<string name="category_furry">Furry</string>
|
||||
<string name="category_games">Гульні</string>
|
||||
<string name="category_general">Асноўныя</string>
|
||||
<string name="category_journalism">Журналістыка</string>
|
||||
<string name="category_lgbt">ЛГБТ</string>
|
||||
<string name="category_music">Музыка</string>
|
||||
<string name="category_regional">Рэгіянальныя</string>
|
||||
<string name="category_tech">Тэхналогіі</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="resend">Адправіць паўторна</string>
|
||||
<string name="open_email_app">Адкрыць праграму для пошты</string>
|
||||
<string name="resent_email">Электронны ліст з пацвярджэннем адпраўлены</string>
|
||||
<string name="compose_hint">Напішыце тое, аб чым думаеце</string>
|
||||
<string name="content_warning">Папярэджанне аб змесціве</string>
|
||||
<string name="add_image_description">Дадаць апісанне відарыса…</string>
|
||||
<string name="retry_upload">Паўтарыць запампоўку</string>
|
||||
<string name="edit_image">Рэдагаваць відарыс</string>
|
||||
<string name="save">Захаваць</string>
|
||||
<string name="add_alt_text">Дадаць альтэрнатыўны тэкст</string>
|
||||
<string name="alt_text_subtitle">Альтэрнатыўны тэкст апісвае вашы фатаграфіі для людзей са слабым зрокам ці без яго. Паспрабуйце ўключыць дастаткова дэталяў, каб быў зразумелы кантэкст.</string>
|
||||
<string name="alt_text_hint">напрыклад, Сабака падазрона азіраецца з прыжмуранымі вачыма на камеру.</string>
|
||||
<string name="visibility_public">Публічны</string>
|
||||
<string name="visibility_followers_only">Толькі для падпісчыкаў</string>
|
||||
<string name="visibility_private">Толькі людзі, якіх я згадаў</string>
|
||||
<string name="search_all">Усе</string>
|
||||
<string name="search_people">Людзі</string>
|
||||
<string name="recent_searches">Нядаўнія запыты</string>
|
||||
<string name="step_x_of_n">Крок %1$d з %2$d</string>
|
||||
<string name="skip">Прапусціць</string>
|
||||
<string name="notification_type_follow">Новыя падпісчыкі</string>
|
||||
<string name="notification_type_favorite">Абраныя</string>
|
||||
<string name="notification_type_reblog">Пашырэнні</string>
|
||||
<string name="notification_type_mention">Згадванні</string>
|
||||
<string name="notification_type_poll">Апытанні</string>
|
||||
<string name="choose_account">Выберыце ўліковы запіс</string>
|
||||
<string name="err_not_logged_in">Спачатку ўвайдзіце ў Mastodon</string>
|
||||
<plurals name="cant_add_more_than_x_attachments">
|
||||
<item quantity="one">Вы не можаце дадаць больш за %d далучэнне</item>
|
||||
<item quantity="few">Вы не можаце дадаць больш за %d далучэнні</item>
|
||||
<item quantity="many">Вы не можаце дадаць больш за %d далучэнняў</item>
|
||||
<item quantity="other">Вы не можаце дадаць больш за %d далучэнняў</item>
|
||||
</plurals>
|
||||
<string name="media_attachment_unsupported_type">Тып файла %s не падтрымліваецца</string>
|
||||
<string name="media_attachment_too_big">Памер файла %1$s перавышае абмежаванне ў %2$s МБ</string>
|
||||
<string name="settings_theme">Знешні выгляд</string>
|
||||
<string name="theme_auto">Аўтаматычна</string>
|
||||
<string name="theme_light">Светлая</string>
|
||||
<string name="theme_dark">Цёмная</string>
|
||||
<string name="theme_true_black">Сапраўдны чорны рэжым</string>
|
||||
<string name="settings_behavior">Паводзіны</string>
|
||||
<string name="settings_gif">Прайграваць аніміраваныя аватары і эмодзі</string>
|
||||
<string name="settings_custom_tabs">Выкарыстоўваць убудаваны браўзер</string>
|
||||
<string name="settings_notifications">Апавяшчэнні</string>
|
||||
<string name="notify_me_when">Паведаміце мне, калі</string>
|
||||
<string name="notify_anyone">кожны</string>
|
||||
<string name="notify_follower">падпісчык</string>
|
||||
<string name="notify_followed">на каго я падпісаны</string>
|
||||
<string name="notify_none">ніхто</string>
|
||||
<string name="notify_favorites">Дадае мой допіс у абранае</string>
|
||||
<string name="notify_follow">Падпісаўся на мяне</string>
|
||||
<string name="notify_reblog">Пашырае мой допіс</string>
|
||||
<string name="notify_mention">Згадвае мяне</string>
|
||||
<string name="settings_boring">Нудная зона</string>
|
||||
<string name="settings_account">Налады ўліковага запісу</string>
|
||||
<string name="settings_contribute">Унесці ўклад у Mastodon</string>
|
||||
<string name="settings_tos">Умовы выкарыстання</string>
|
||||
<string name="settings_privacy_policy">Палітыка прыватнасці</string>
|
||||
<string name="settings_spicy">Вострая зона</string>
|
||||
<string name="settings_clear_cache">Ачысціць кэш медыя</string>
|
||||
<string name="settings_app_version">Mastodon для Android v%1$s (%2$d)</string>
|
||||
<string name="media_cache_cleared">Кэш медыя ачышчаны</string>
|
||||
<string name="confirm_log_out">Вы ўпэўненыя, што хочаце выйсці?</string>
|
||||
<string name="sensitive_content">Далікатны змест</string>
|
||||
<string name="sensitive_content_explain">Аўтар пазначыў гэты медыя файл як далікатны. Націсніце, каб паказаць.</string>
|
||||
<string name="media_hidden">Націсніце, каб паказаць</string>
|
||||
<string name="avatar_description">Перайсці да профілю %s</string>
|
||||
<string name="more_options">Больш опцый</string>
|
||||
<string name="reveal_content">Паказаць змест</string>
|
||||
<string name="hide_content">Схаваць змест</string>
|
||||
<string name="new_post">Новы допіс</string>
|
||||
<string name="button_reply">Адказаць</string>
|
||||
<string name="button_reblog">Пашырыць</string>
|
||||
<string name="button_favorite">Абранае</string>
|
||||
<string name="button_share">Абагуліць</string>
|
||||
<string name="media_no_description">Медыя без апісання</string>
|
||||
<string name="add_media">Дадаць медыя</string>
|
||||
<string name="add_poll">Дадаць апытанне</string>
|
||||
<string name="emoji">Эмодзі</string>
|
||||
<string name="post_visibility">Бачнасць допісу</string>
|
||||
<string name="home_timeline">Хатняя стужка</string>
|
||||
<string name="my_profile">Мой профіль</string>
|
||||
<string name="media_viewer">Праграма для прагляду медыя</string>
|
||||
<string name="follow_user">Падпісацца на %s</string>
|
||||
<string name="unfollowed_user">Адпісацца ад %s</string>
|
||||
<string name="followed_user">Цяпер вы падпісаны на %s</string>
|
||||
<string name="open_in_browser">Адкрыць у браўзеры</string>
|
||||
<string name="hide_boosts_from_user">Схаваць пашырэнні ад %s</string>
|
||||
<string name="show_boosts_from_user">Паказаць пашырэнні ад %s</string>
|
||||
<string name="signup_reason_note">Гэта дапаможа нам разгледзець вашу заяўку.</string>
|
||||
<string name="clear">Ачысціць</string>
|
||||
<string name="profile_header">Відарыс шапкі</string>
|
||||
<string name="profile_picture">Аватар</string>
|
||||
<string name="reorder">Упарадкаваць</string>
|
||||
<string name="download">Спампаваць</string>
|
||||
<string name="permission_required">Патрабуецца дазвол</string>
|
||||
<string name="storage_permission_to_download">Праграме патрэбны доступ да сховішча, каб захаваць гэты файл.</string>
|
||||
<string name="open_settings">Адкрыць налады</string>
|
||||
<string name="error_saving_file">Памылка пры захаванні файла</string>
|
||||
<string name="file_saved">Файл захаваны</string>
|
||||
<string name="downloading">Спампоўванне…</string>
|
||||
<string name="no_app_to_handle_action">Няма праграмы для выканання гэтага дзеяння</string>
|
||||
<string name="local_timeline">Супольнасць</string>
|
||||
<string name="trending_posts_info_banner">Допісы, што набіраюць папулярнасць у вашым кутку Mastodon.</string>
|
||||
<string name="trending_hashtags_info_banner">Хэштэгі, што набіраюць папулярнасць у вашым кутку Mastodon.</string>
|
||||
<string name="trending_links_info_banner">Навіна, якая найбольш абмяркоўваецца ў вашым кутку Mastodon.</string>
|
||||
<string name="local_timeline_info_banner">Гэта самыя апошнія допісы людзей, якія выкарыстоўваюць той жа сервер Mastodon, што і вы.</string>
|
||||
<string name="dismiss">Адхіліць</string>
|
||||
<string name="see_new_posts">Паказаць новыя допісы</string>
|
||||
<string name="load_missing_posts">Загрузіць адсутныя допісы</string>
|
||||
<string name="follow_back">Падпісацца ў адказ</string>
|
||||
<string name="button_follow_pending">Чакаюць</string>
|
||||
<string name="follows_you">Падпісаны(-а) на вас</string>
|
||||
<string name="manually_approves_followers">Уручную пацвярджае падпісчыкаў</string>
|
||||
<string name="current_account">Бягучы ўліковы запіс</string>
|
||||
<string name="log_out_account">Выйсці з %s</string>
|
||||
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
|
||||
<plurals name="x_followers">
|
||||
<item quantity="one">%,d падпісчык</item>
|
||||
<item quantity="few">%,d падпісчыка</item>
|
||||
<item quantity="many">%,d падпісчыкаў</item>
|
||||
<item quantity="other">%,d падпісчыкаў</item>
|
||||
</plurals>
|
||||
<plurals name="x_following">
|
||||
<item quantity="one">%,d падпіска</item>
|
||||
<item quantity="few">%,d падпіскі</item>
|
||||
<item quantity="many">%,d падпісак</item>
|
||||
<item quantity="other">%,d падпісак</item>
|
||||
</plurals>
|
||||
<plurals name="x_favorites">
|
||||
<item quantity="one">%,d абраны</item>
|
||||
<item quantity="few">%,d абраныя</item>
|
||||
<item quantity="many">%,d абраных</item>
|
||||
<item quantity="other">%,d абраных</item>
|
||||
</plurals>
|
||||
<plurals name="x_reblogs">
|
||||
<item quantity="one">%,d рэпост</item>
|
||||
<item quantity="few">%,d рэпосты</item>
|
||||
<item quantity="many">%,d пашырэнняў</item>
|
||||
<item quantity="other">%,d пашырэнняў</item>
|
||||
</plurals>
|
||||
<string name="timestamp_via_app">%1$s праз %2$s</string>
|
||||
<string name="time_now">толькі што</string>
|
||||
<string name="post_info_reblogs">Пашырэнні</string>
|
||||
<string name="post_info_favorites">Абраныя</string>
|
||||
<string name="edit_history">Гісторыя рэдагавання</string>
|
||||
<string name="last_edit_at_x">Апошняе рэдагаванне %s</string>
|
||||
<string name="time_just_now">толькі што</string>
|
||||
<plurals name="x_seconds_ago">
|
||||
<item quantity="one">%d секунду таму</item>
|
||||
<item quantity="few">%d секунды таму</item>
|
||||
<item quantity="many">%d секунд таму</item>
|
||||
<item quantity="other">%d секунд таму</item>
|
||||
</plurals>
|
||||
<plurals name="x_minutes_ago">
|
||||
<item quantity="one">%d хвіліну таму</item>
|
||||
<item quantity="few">%d хвіліны таму</item>
|
||||
<item quantity="many">%d хвілін таму</item>
|
||||
<item quantity="other">%d хвілін таму</item>
|
||||
</plurals>
|
||||
<string name="edited_timestamp">адрэдагавана %s</string>
|
||||
<string name="edit_original_post">Зыходны допіс</string>
|
||||
<string name="edit_text_edited">Тэкст адрэдагавана</string>
|
||||
<string name="edit_spoiler_added">Папярэджанне аб змесціве дададзена</string>
|
||||
<string name="edit_spoiler_edited">Папярэджанне аб змесціве адрэдагавана</string>
|
||||
<string name="edit_spoiler_removed">Папярэджанне аб змесціве выдалена</string>
|
||||
<string name="edit_poll_added">Апытанне дададзена</string>
|
||||
<string name="edit_poll_edited">Апытанне адрэдагавана</string>
|
||||
<string name="edit_poll_removed">Апытанне выдалена</string>
|
||||
<string name="edit_media_added">Медыя дададзены</string>
|
||||
<string name="edit_media_removed">Медыя выдалены</string>
|
||||
<string name="edit_media_reordered">Медыя пераўпарадкаваны</string>
|
||||
<string name="edit_marked_sensitive">Пазначаны як далікатны</string>
|
||||
<string name="edit_marked_not_sensitive">Пазначаны як неадчувальны</string>
|
||||
<string name="edit_multiple_changed">Допіс адрэдагавана</string>
|
||||
<string name="edit">Рэдагаваць</string>
|
||||
<string name="discard_changes">Скасаваць змены?</string>
|
||||
<string name="upload_failed">Не ўдалося запампаваць</string>
|
||||
<string name="file_size_bytes">%d байтаў</string>
|
||||
<string name="file_size_kb">%.2f КБ</string>
|
||||
<string name="file_size_mb">%.2f МБ</string>
|
||||
<string name="file_size_gb">%.2f ГБ</string>
|
||||
<string name="file_upload_progress">%1$s з %2$s</string>
|
||||
<string name="file_upload_time_remaining">Засталося %s</string>
|
||||
<string name="upload_error_connection_lost">Ваша прылада страціла злучэнне з Інтэрнэтам</string>
|
||||
<string name="upload_processing">Апрацоўка…</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_available">Mastodon для Android %s гатовы да спампоўкі.</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_ready">Mastodon для Android %s спампаваны і гатовы да ўсталявання.</string>
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">Спампаваць (%s)</string>
|
||||
<string name="install_update">Усталяваць</string>
|
||||
<string name="i_agree">Я згодны</string>
|
||||
<string name="empty_list">Гэты ліст пусты</string>
|
||||
<string name="instance_signup_closed">Гэты сервер не прымае новыя рэгістрацыі.</string>
|
||||
<string name="text_copied">Скапіявана ў буфер абмену</string>
|
||||
<string name="add_bookmark">Закладка</string>
|
||||
<string name="remove_bookmark">Выдаліць закладку</string>
|
||||
<string name="bookmarks">Закладкі</string>
|
||||
<string name="your_favorites">Вашы абраныя</string>
|
||||
<string name="login_title">З вяртаннем</string>
|
||||
<string name="login_subtitle">Увайдзіце з дапамогай сервера, на якім вы стварылі свой уліковы запіс.</string>
|
||||
<string name="server_url">URL-адрас сервера</string>
|
||||
<string name="welcome_page1_text">Уявіце, што ў вас ёсць адрас электроннай пошты, які заканчваецца на @example.com.\n\nВы па-ранейшаму можаце адпраўляць і атрымліваць электронныя лісты ад каго захочаце, нават калі іх электронная пошта заканчваецца на @gmail.com, @icloud.com або @example.com.</string>
|
||||
<string name="welcome_page2_title">Mastodon такі.</string>
|
||||
<string name="welcome_page2_text">Ваш ідэнтыфікатар можа быць @gothgirl654@example.social, але вы ўсё яшчэ можаце падпісвацца, пашыраць і перапісвацца з @fallout5ever@example.online.</string>
|
||||
<string name="welcome_page3_title">Як выбраць сервер?</string>
|
||||
<string name="welcome_page3_text">Розныя людзі выбіраюць розныя серверы па розных прычынах. art.example з\'яўляецца выдатным месцам для мастакоў, у той час як glasgow.example можа быць добрым выбарам для шатландцаў.\n\nВы не памыліцеся ні з адным з нашых рэкамендаваных сервераў, так што незалежна ад таго, які вы выбераце (або калі ўведзяце ваш уласны ў радку пошуку сервера), вы нідзе нічога не прапусціце.</string>
|
||||
<!-- %s is server domain -->
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
</resources>
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
<string name="sk_app_name">Megalodon</string>
|
||||
<string name="sk_delete_and_redraft">Выдаліць і паправіць</string>
|
||||
<string name="sk_confirm_delete_and_redraft_title">Выдаліць і паправіць допіс</string>
|
||||
<string name="sk_pin_post">Замацаваць у профілі</string>
|
||||
<string name="sk_confirm_pin_post_title">Замацаваць допіс у профілі</string>
|
||||
<string name="sk_confirm_pin_post">Вы хочаце замацаваць гэты допіс у сваім профілі\?</string>
|
||||
<string name="sk_pinning">Замацаванне допісу…</string>
|
||||
<string name="sk_confirm_unpin_post_title">Адмацаваць допіс ад профілю</string>
|
||||
<string name="sk_unpinning">Адмацаванне допісу…</string>
|
||||
<string name="sk_image_description">Апісанне выявы</string>
|
||||
<string name="sk_visibility_unlisted">Прыхаваны</string>
|
||||
<string name="sk_settings_show_replies">Паказваць адказы</string>
|
||||
<string name="sk_settings_show_boosts">Паказаць пашырэнні</string>
|
||||
<string name="sk_pinned_posts">Замацавана</string>
|
||||
<string name="sk_confirm_delete_and_redraft">Вы ўпэўненыя, што жадаеце выдаліць і паправіць гэты допіс\?</string>
|
||||
<string name="sk_unpin_post">Адмацаваць ад профілю</string>
|
||||
<string name="sk_confirm_unpin_post">Вы ўпэўненыя, што жадаеце адмацаваць гэты допіс\?</string>
|
||||
</resources>
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">শুরু করুন</string>
|
||||
<string name="log_in">লগ ইন করুন</string>
|
||||
<string name="next">পরবর্তী</string>
|
||||
<string name="ok">ঠিক আছে</string>
|
||||
@@ -38,8 +37,12 @@
|
||||
<string name="for_you">আপনার জন্য</string>
|
||||
<string name="all_notifications">সকল</string>
|
||||
<string name="mentions">উল্লেখ</string>
|
||||
<!-- %s is the email address -->
|
||||
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<!-- %s is file size -->
|
||||
<!-- %s is server domain -->
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
</resources>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">Kreni</string>
|
||||
<string name="log_in">Loguj se</string>
|
||||
<string name="next">Dalje</string>
|
||||
<string name="error">Greška</string>
|
||||
@@ -129,14 +128,7 @@
|
||||
<string name="report_personal_title">Ne želite ovo vidjeti?</string>
|
||||
<string name="report_personal_subtitle">Kada vidite nešto nepoželjno na Mastodon-u, možete blokirati odredjeni profil.</string>
|
||||
<string name="back">Nazad</string>
|
||||
<string name="instance_rules_title">Važna pravila</string>
|
||||
<string name="instance_rules_subtitle">Pogledajte pravila koja je odredila %s administracija.</string>
|
||||
<string name="signup_title">Krenimo sa postavkama na %s</string>
|
||||
<string name="edit_photo">uredi</string>
|
||||
<string name="display_name">vaše ime</string>
|
||||
<string name="username">korisničko ime</string>
|
||||
<string name="email">email</string>
|
||||
<string name="password">lozinka</string>
|
||||
<string name="password_note">Koristite velika slova, brojeve i oznake da bi osigurali lozinku.</string>
|
||||
<string name="category_academia">Akademija</string>
|
||||
<string name="category_activism">Aktivizam</string>
|
||||
@@ -151,8 +143,7 @@
|
||||
<string name="category_music">Muzika</string>
|
||||
<string name="category_regional">Regionalno</string>
|
||||
<string name="category_tech">Tehnika</string>
|
||||
<string name="confirm_email_title">Zadnja stvar</string>
|
||||
<string name="confirm_email_subtitle">Kliknite na link koji smo vam poslali u email-u da se verifikujete.</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="resend">Ponovo poslato</string>
|
||||
<string name="open_email_app">Otvori email</string>
|
||||
<string name="resent_email">Email za verifikaciju poslat</string>
|
||||
@@ -238,7 +229,6 @@
|
||||
<string name="unfollowed_user">Ne pratite %s</string>
|
||||
<string name="followed_user">Sada pratite %s</string>
|
||||
<string name="open_in_browser">Otvori u pregledniku</string>
|
||||
<string name="signup_reason">zašto se želite pridružiti?</string>
|
||||
<string name="signup_reason_note">Ovo nam pomaže prilikom odobravanja vašeg zahtjeva.</string>
|
||||
<string name="clear">Briši</string>
|
||||
<string name="profile_header">Slika zaglavlja</string>
|
||||
@@ -255,4 +245,7 @@
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<!-- %s is file size -->
|
||||
<!-- %s is server domain -->
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
</resources>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">Comença</string>
|
||||
<string name="get_started">Crea un compte</string>
|
||||
<string name="already_have_account">Ja tinc un compte</string>
|
||||
<string name="log_in">Inicia sessió</string>
|
||||
<string name="next">Següent</string>
|
||||
<string name="loading_instance">S\'està recuperant la informació del servidor…</string>
|
||||
<string name="error">Error</string>
|
||||
<string name="not_a_mastodon_instance">Sembla que %s no és un servidor de Mastodon.</string>
|
||||
<string name="ok">D\'acord</string>
|
||||
<string name="preparing_auth">Preparant l\'autenticació…</string>
|
||||
<string name="finishing_auth">Finalitzant l\'autenticació…</string>
|
||||
@@ -170,15 +173,15 @@
|
||||
<string name="back">Enrere</string>
|
||||
<string name="instance_catalog_title">Mastodon està format per usuaris de diferents servidors.</string>
|
||||
<string name="instance_catalog_subtitle">Tria un servidor en funció dels teus interessos, regió o un de propòsit general. Seguiràs podent connectar amb tothom, independentment del servidor.</string>
|
||||
<string name="search_communities">Cerca servidors o introdueix l\'URL</string>
|
||||
<string name="instance_rules_title">Algunes normes bàsiques</string>
|
||||
<string name="instance_rules_subtitle">Pren un minut per revisar les normes establertes i aplicades pels administradors de %s.</string>
|
||||
<string name="signup_title">Deixa que et posem en marxa a %s</string>
|
||||
<string name="search_communities">Nom del servidor o URL</string>
|
||||
<string name="instance_rules_title">Normes del servidor</string>
|
||||
<string name="signup_title">Crear un compte</string>
|
||||
<string name="edit_photo">edita</string>
|
||||
<string name="display_name">nom visible</string>
|
||||
<string name="username">nom d\'usuari</string>
|
||||
<string name="email">correu electrònic</string>
|
||||
<string name="password">contrasenya</string>
|
||||
<string name="display_name">Nom</string>
|
||||
<string name="username">Nom d\'usuari</string>
|
||||
<string name="email">Correu electrònic</string>
|
||||
<string name="password">Contrasenya</string>
|
||||
<string name="confirm_password">Confirmar contrasenya</string>
|
||||
<string name="password_note">Inclou lletres majúscules, caràcters especials i números per augmentar la seguretat de la teva contrasenya.</string>
|
||||
<string name="category_academia">Acadèmic</string>
|
||||
<string name="category_activism">Activisme</string>
|
||||
@@ -193,8 +196,9 @@
|
||||
<string name="category_music">Música</string>
|
||||
<string name="category_regional">Regional</string>
|
||||
<string name="category_tech">Tecnologia</string>
|
||||
<string name="confirm_email_title">Una última cosa</string>
|
||||
<string name="confirm_email_subtitle">Toca l\'enllaç del correu electrònic que t\'hem enviat per a confirmar el teu compte.</string>
|
||||
<string name="confirm_email_title">Comprova la teva safata d\'entrada</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="confirm_email_didnt_get">No has rebut l\'enllaç?</string>
|
||||
<string name="resend">Reenvia</string>
|
||||
<string name="open_email_app">Obre l\'aplicació de correu</string>
|
||||
<string name="resent_email">S’ha enviat el correu electrònic de confirmació</string>
|
||||
@@ -282,7 +286,6 @@
|
||||
<string name="open_in_browser">Obre al navegador</string>
|
||||
<string name="hide_boosts_from_user">Amaga els impulsos de %s</string>
|
||||
<string name="show_boosts_from_user">Mostra els impulsos de %s</string>
|
||||
<string name="signup_reason">per què vols unir-te?</string>
|
||||
<string name="signup_reason_note">Això ens ajudarà a revisar la teva petició.</string>
|
||||
<string name="clear">Esborra</string>
|
||||
<string name="profile_header">Imatge de capçalera</string>
|
||||
@@ -375,8 +378,6 @@
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">Baixa (%s)</string>
|
||||
<string name="install_update">Instal·la</string>
|
||||
<string name="privacy_policy_title">Mastodon i la teva privacitat</string>
|
||||
<string name="privacy_policy_subtitle">Tot i que l\'aplicació Mastodon no recull cap dada, el servidor mitjançant el qual et registres pot tenir una política diferent. Pren un minut per revisar i acceptar la política de privadesa de l\'aplicació Mastodon i la política de privadesa del teu servidor.</string>
|
||||
<string name="i_agree">D’acord</string>
|
||||
<string name="empty_list">Aquesta llista està buida</string>
|
||||
<string name="instance_signup_closed">Aquest servidor no accepta nous registres.</string>
|
||||
@@ -384,4 +385,11 @@
|
||||
<string name="add_bookmark">Marca</string>
|
||||
<string name="remove_bookmark">Elimina el marcador</string>
|
||||
<string name="bookmarks">Marcadors</string>
|
||||
<string name="your_favorites">Els meus preferits</string>
|
||||
<string name="login_title">Hola de nou</string>
|
||||
<string name="login_subtitle">Inicia sessió amb el servidor on vas crear el compte.</string>
|
||||
<string name="server_url">URL del servidor</string>
|
||||
<!-- %s is server domain -->
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
</resources>
|
||||
|
||||
@@ -142,4 +142,115 @@
|
||||
<string name="sk_your_lists">Llistes</string>
|
||||
<string name="sk_loading_fediverse_resource_title">Buscant-ho al Fedivers</string>
|
||||
<string name="sk_loading_resource_on_instance_title">Buscant-ho a %s</string>
|
||||
<string name="sk_pin_timeline">Fixa la línia de temps</string>
|
||||
<string name="sk_unpin_timeline">No fixes la línia de temps</string>
|
||||
<string name="sk_remove">Elimina</string>
|
||||
<string name="sk_timeline_icon">Icona</string>
|
||||
<string name="sk_unpinned_timeline">S\'ha deixat de fixar de l\'inici</string>
|
||||
<string name="sk_pinned_timeline">S\'ha fixat a l\'inici</string>
|
||||
<string name="sk_icon_heart">Cor</string>
|
||||
<string name="sk_icon_star">Estrela</string>
|
||||
<string name="sk_list">Llista</string>
|
||||
<string name="sk_icon_dog">Gos</string>
|
||||
<string name="sk_recent_searches_placeholder">Escriviu per a cercar</string>
|
||||
<string name="sk_remove_follower">Elimina el seguidor</string>
|
||||
<string name="sk_remove_follower_confirm">Voleu eliminar %s com a seguidor bloquejant-lo i desbloquejant-lo immediatament\?</string>
|
||||
<string name="sk_do_remove_follower">Elimina</string>
|
||||
<string name="sk_remove_follower_success">S\'ha eliminat el seguidor correctament</string>
|
||||
<string name="sk_changelog">Registre de canvis</string>
|
||||
<string name="sk_alt_text_missing_title">Falta el text alternatiu</string>
|
||||
<string name="sk_alt_text_missing">Almenys un adjunt no conté cap descripció.</string>
|
||||
<string name="sk_publish_anyway">Publica igualment</string>
|
||||
<string name="sk_settings_disable_alt_text_reminder">Desactiva el recordatori per a afegir text alternatiu</string>
|
||||
<string name="sk_notify_posts_info_banner">Si activeu les notificacions de publicacions d\'algunes persones, les seues publicacions noves apareixeran ací.</string>
|
||||
<string name="sk_timelines">Línies de temps</string>
|
||||
<string name="sk_timeline_posts">Publicacions</string>
|
||||
<string name="sk_timelines_add">Afegeix</string>
|
||||
<string name="sk_timeline">Línia de temps</string>
|
||||
<string name="sk_icon_city">Ciutat</string>
|
||||
<string name="sk_icon_cat">Gat</string>
|
||||
<string name="sk_icon_rabbit">Conill</string>
|
||||
<string name="sk_icon_turtle">Tortuga</string>
|
||||
<string name="sk_icon_balloon">Globus</string>
|
||||
<string name="sk_icon_image">Imatge</string>
|
||||
<string name="sk_icon_bot">Bot</string>
|
||||
<string name="sk_icon_language">Llengua</string>
|
||||
<string name="sk_icon_location">Ubicació</string>
|
||||
<string name="sk_icon_megaphone">Megàfon</string>
|
||||
<string name="sk_icon_microphone">Micròfon</string>
|
||||
<string name="sk_icon_microscope">Microscopi</string>
|
||||
<string name="sk_icon_keyboard">Piano</string>
|
||||
<string name="sk_icon_coffee">Café</string>
|
||||
<string name="sk_icon_news">Notícies</string>
|
||||
<string name="sk_icon_pi">Pi</string>
|
||||
<string name="sk_icon_color_palette">Paleta de color</string>
|
||||
<string name="sk_icon_academic_cap">Barret acadèmic</string>
|
||||
<string name="sk_icon_tag">Etiqueta</string>
|
||||
<string name="sk_icon_weather">Temps</string>
|
||||
<string name="sk_icon_games">Jocs</string>
|
||||
<string name="sk_icon_code">Codi</string>
|
||||
<string name="sk_icon_light_bulb">Bombeta</string>
|
||||
<string name="sk_icon_train">Tren</string>
|
||||
<string name="sk_icon_leaves">Fulles</string>
|
||||
<string name="sk_icon_sport">Esport</string>
|
||||
<string name="sk_icon_aperture">Obertura</string>
|
||||
<string name="sk_icon_music">Música</string>
|
||||
<string name="sk_icon_people">Persones</string>
|
||||
<string name="sk_icon_health">Salut</string>
|
||||
<string name="sk_icon_important">Important</string>
|
||||
<string name="sk_icon_chat">Xat</string>
|
||||
<string name="sk_icon_shield">Escut</string>
|
||||
<string name="sk_icon_book">Llibre</string>
|
||||
<string name="sk_icon_bicycle">Bicicleta</string>
|
||||
<string name="sk_icon_map">Mapa</string>
|
||||
<string name="sk_icon_backpack">Motxilla</string>
|
||||
<string name="sk_icon_briefcase">Maleta</string>
|
||||
<string name="sk_icon_fire">Foc</string>
|
||||
<string name="sk_icon_bug">Marieta</string>
|
||||
<string name="sk_icon_pizza">Pizza</string>
|
||||
<string name="sk_icon_stethoscope">Estetoscopi</string>
|
||||
<string name="sk_icon_gavel">Martell</string>
|
||||
<string name="sk_attach_file">Adjunta un fitxer</string>
|
||||
<string name="sk_icon_headphones">Auriculars</string>
|
||||
<string name="sk_icon_human">Humà</string>
|
||||
<string name="sk_icon_globe">Globus</string>
|
||||
<string name="sk_edit_timeline">Edita la línia de temps</string>
|
||||
<string name="sk_icon_pin">Xinxeta</string>
|
||||
<string name="sk_edit_timelines">Edita les línies de temps</string>
|
||||
<string name="sk_alt_button">ALT</string>
|
||||
<string name="sk_post_edited">editat</string>
|
||||
<string name="sk_notification_type_update">Publicacions editades</string>
|
||||
<string name="sk_notify_update">Edita una publicació impulsada</string>
|
||||
<string name="sk_no_results">Sense resultats</string>
|
||||
<string name="sk_no_alt_text">Ni hi ha cap text alternatiu</string>
|
||||
<string name="sk_settings_show_alt_indicator">Indicador dels textos alternatius</string>
|
||||
<string name="sk_save_draft_message">Voleu desar els canvis en l\'esborrany o publicar-lo ara\?</string>
|
||||
<string name="sk_updater_enable_pre_releases">Activa els prellançaments</string>
|
||||
<string name="sk_separator">·</string>
|
||||
<string name="sk_instance_features">Característiques de la instància</string>
|
||||
<string name="sk_settings_support_local_only">El servidor suporta publicacions locals</string>
|
||||
<string name="sk_settings_glitch_instance">Mode només local de Glitch</string>
|
||||
<string name="sk_settings_glitch_mode_explanation">Activeu-ho si la vostra instància d\'inici s\'executa a Glitch. No és necessari per a Hometown o Akkoma.</string>
|
||||
<string name="sk_inline_local_only">local</string>
|
||||
<string name="sk_inline_direct">només gent mencionada</string>
|
||||
<string name="sk_settings_local_only_explanation">La vostra instància d\'inici ha d\'admetre la publicació local perquè això funcione. La majoria de versions modificades de Mastodon sí que ho fan, però Mastodon no.</string>
|
||||
<string name="sk_sign_ups">Usuaris registrats</string>
|
||||
<string name="sk_local_only">Només instància local</string>
|
||||
<string name="sk_settings_see_new_posts_button">Botó de «Publicacions noves»</string>
|
||||
<string name="sk_notify_poll_results">Resultats de l\'enquesta</string>
|
||||
<string name="sk_settings_server_version">Versió del servidor: %s</string>
|
||||
<string name="sk_hashtag">Etiqueta</string>
|
||||
<string name="sk_icon_laugh">Riure</string>
|
||||
<string name="sk_icon_clapper_board">Claqueta</string>
|
||||
<string name="sk_icon_math_formula">Fòrmula matemàtica</string>
|
||||
<string name="sk_searching">Cercant…</string>
|
||||
<string name="sk_save_draft">Voleu desar l\'esborrany\?</string>
|
||||
<string name="sk_settings_show_no_alt_indicator">Indicador dels textos alternatius inexistents</string>
|
||||
<string name="sk_settings_prefix_reply_cw_with_re">Afegeix «re:» a les respostes als avisos de contingut</string>
|
||||
<string name="sk_filtered">Filtrat: %s</string>
|
||||
<string name="sk_expand">Amplia</string>
|
||||
<string name="sk_collapse">Tanca</string>
|
||||
<string name="sk_settings_collapse_long_posts">Acurta les publicacions llargues</string>
|
||||
<string name="sk_signed_up">registrat</string>
|
||||
<string name="sk_spectator_mode">Mode d\'espectador</string>
|
||||
</resources>
|
||||
@@ -1,9 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">Začínáme</string>
|
||||
<string name="get_started">Vytvořit účet</string>
|
||||
<string name="already_have_account">Již mám účet</string>
|
||||
<string name="log_in">Přihlásit se</string>
|
||||
<string name="next">Další</string>
|
||||
<string name="loading_instance">Načítání informací o serveru…</string>
|
||||
<string name="error">Chyba</string>
|
||||
<string name="not_a_mastodon_instance">%s se nezdá být Mastodon serverem.</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="preparing_auth">Příprava na autentizaci…</string>
|
||||
<string name="finishing_auth">Dokončení autentizace…</string>
|
||||
@@ -198,15 +201,7 @@
|
||||
<string name="back">Zpět</string>
|
||||
<string name="instance_catalog_title">Mastodon tvoří uživatelé z různých serverů.</string>
|
||||
<string name="instance_catalog_subtitle">Vyberte si server podle na svých zájmů, regionu nebo obecného účelu. Stále se můžete spojit se všemi bez ohledu na server.</string>
|
||||
<string name="search_communities">Hledat server nebo zadat URL</string>
|
||||
<string name="instance_rules_title">Některá základní pravidla</string>
|
||||
<string name="instance_rules_subtitle">Udělejte si chvíli čas a zkontrolujte pravidla, která admini %s nastavili a vynucují.</string>
|
||||
<string name="signup_title">Pojďme si nastavit %s</string>
|
||||
<string name="edit_photo">upravit</string>
|
||||
<string name="display_name">zobrazované jméno</string>
|
||||
<string name="username">uživatelské jméno</string>
|
||||
<string name="email">e-mail</string>
|
||||
<string name="password">heslo</string>
|
||||
<string name="password_note">Použijte velká písmena, speciální znaky a čísla, abyste zvýšili sílu hesla.</string>
|
||||
<string name="category_academia">Akademická sféra</string>
|
||||
<string name="category_activism">Aktivismus</string>
|
||||
@@ -221,8 +216,7 @@
|
||||
<string name="category_music">Hudba</string>
|
||||
<string name="category_regional">Regionální</string>
|
||||
<string name="category_tech">Technologie</string>
|
||||
<string name="confirm_email_title">Ještě jedna věc</string>
|
||||
<string name="confirm_email_subtitle">Klepněte na odkaz, který jsme vám poslali e-mailem, abyste účet ověřili.</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="resend">Poslat znovu</string>
|
||||
<string name="open_email_app">Otevřít e-mailovou aplikaci</string>
|
||||
<string name="resent_email">Potvrzující e-mail byl odeslán</string>
|
||||
@@ -312,7 +306,6 @@
|
||||
<string name="open_in_browser">Otevřít v prohlížeči</string>
|
||||
<string name="hide_boosts_from_user">Skrýt boosty od %s</string>
|
||||
<string name="show_boosts_from_user">Zobrazit boosty od %s</string>
|
||||
<string name="signup_reason">proč se chcete zaregistrovat?</string>
|
||||
<string name="signup_reason_note">Toto nám pomůže posoudit vaši žádost.</string>
|
||||
<string name="clear">Vyčistit</string>
|
||||
<string name="profile_header">Obrázek v záhlaví</string>
|
||||
@@ -417,8 +410,6 @@
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">Stáhnout (%s)</string>
|
||||
<string name="install_update">Instalovat</string>
|
||||
<string name="privacy_policy_title">Mastodon a vaše soukromí</string>
|
||||
<string name="privacy_policy_subtitle">Ačkoliv aplikace Mastodon neshromažďuje žádná data, server, na kterém se registrujete, může mít jiné zásady. Věnujte minutu kontrole a odsouhlasení zásad soukromí aplikace Mastodon a vašeho serveru.</string>
|
||||
<string name="i_agree">Souhlasím</string>
|
||||
<string name="empty_list">Tento seznam je prázdný</string>
|
||||
<string name="instance_signup_closed">Tento server nepřijímá nové registrace.</string>
|
||||
@@ -427,4 +418,15 @@
|
||||
<string name="remove_bookmark">Odstranit ze záložek</string>
|
||||
<string name="bookmarks">Záložky</string>
|
||||
<string name="your_favorites">Vaše oblíbení</string>
|
||||
<string name="login_title">Vítejte zpět</string>
|
||||
<string name="login_subtitle">Přihlaste se pomocí serveru, kde jste vytvořili svůj účet.</string>
|
||||
<string name="server_url">URL serveru</string>
|
||||
<string name="welcome_page1_text">Představte si, že máte e-mailovou adresu, která končí @example.com.\n\nStále můžete od kohokoliv odesílat a přijímat e-maily, i když jejich e-mail končí na @gmail.com nebo @icloud.com nebo @example.com.</string>
|
||||
<string name="welcome_page2_title">Takový je Mastodon.</string>
|
||||
<string name="welcome_page2_text">Vaše uživatelské jméno může být @gothgirl654@example.social, ale stále můžete sledovat, boostovat a chatovat s @fallout5ever@example.online.</string>
|
||||
<string name="welcome_page3_title">Jak si vybrat server?</string>
|
||||
<string name="welcome_page3_text">Různí lidé si vybírají různé servery z různých důvodů. Art.example je skvělým místem pro umělce, zatímco glasgow.example může být dobrou volbou pro Skoty.\n\nS žádným z našich doporučených serverů nemůžete udělat chybu, takže bez ohledu na to, který z nich si vyberete (nebo pokud zadáte svůj vlastní do vyhledávacího řádku serveru), nikde neprohloupíte.</string>
|
||||
<!-- %s is server domain -->
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
</resources>
|
||||
|
||||
@@ -146,14 +146,14 @@
|
||||
<string name="sk_compose_no_schedule">Peidiwch ag amserlennu</string>
|
||||
<string name="sk_settings_reduce_motion">Lleihau mudiant mewn animeiddiadau</string>
|
||||
<string name="sk_delete_list_confirm">Ydych chi\'n sicr eich bod eisiau dileu\'r rhestr %s\?</string>
|
||||
<string name="sk_recent_searches_placeholder">Teipiwch rhywbeth i ddechrau chwilio</string>
|
||||
<string name="sk_recent_searches_placeholder">Teipiwch i ddechrau chwilio</string>
|
||||
<string name="sk_remove_follower_confirm">Tynnu %s fel dilynwr drwy eu rhwystro a\'i ddadrwystro ar unwaith\?</string>
|
||||
<string name="sk_edit_timelines">Golygu ffrydiau…</string>
|
||||
<string name="sk_edit_timelines">Golygu ffrydiau</string>
|
||||
<string name="sk_alt_button">ALT</string>
|
||||
<string name="sk_alt_text_missing_title">Dim testun alt</string>
|
||||
<string name="sk_alt_text_missing">O leiaf un atodiad heb ei ddisgrifio.</string>
|
||||
<string name="sk_publish_anyway">Cyhoeddi beth bynnag</string>
|
||||
<string name="sk_settings_disable_alt_text_reminder">Analluogi nodyn atgoffa testun alt</string>
|
||||
<string name="sk_settings_disable_alt_text_reminder">Analluogi nodyn atgoffa i ychwanegu testun alt</string>
|
||||
<string name="sk_post_edited">Wedi\'i olygu</string>
|
||||
<string name="sk_notification_type_update">Negeseuon wedi\'u golygu</string>
|
||||
<string name="sk_notify_posts_info_banner">Os ydych chi\'n galluogi hysbysiadau post ar gyfer rhai pobl, bydd eu postiadau newydd yn ymddangos yma.</string>
|
||||
@@ -226,4 +226,28 @@
|
||||
<string name="sk_icon_pin">Pin</string>
|
||||
<string name="sk_notify_update">Golygu neges wedi\'i hybu</string>
|
||||
<string name="sk_icon_bicycle">Beic</string>
|
||||
<string name="sk_searching">Chwilio…</string>
|
||||
<string name="sk_no_results">Dim atebion</string>
|
||||
<string name="sk_save_draft">Cadw drafft\?</string>
|
||||
<string name="sk_save_draft_message">Dych chi eisiau cadw eich newidiadau i\'r drafft hwn neu gyhoeddi fe nawr\?</string>
|
||||
<string name="sk_no_alt_text">Dim testun alt ar gael</string>
|
||||
<string name="sk_settings_show_alt_indicator">Dangosydd ar gyfer testunau alt</string>
|
||||
<string name="sk_settings_show_no_alt_indicator">Dangosydd ar gyfer testunau alt ar goll</string>
|
||||
<string name="sk_updater_enable_pre_releases">Galluogi rhag-rhyddhad</string>
|
||||
<string name="sk_inline_local_only">Lleol yn unig</string>
|
||||
<string name="sk_inline_direct">crybwylliadau yn unig</string>
|
||||
<string name="sk_separator">·</string>
|
||||
<string name="sk_instance_features">Nodweddion y gweinydd</string>
|
||||
<string name="sk_settings_support_local_only">Gweinydd yn cefnogi postio yn lleol yn unig</string>
|
||||
<string name="sk_settings_local_only_explanation">Rhaid i\'ch gweinydd gefnogi postio yn lleol yn unig er mwyn i hyn weithio. Mae\'r rhan fwyaf o fersiynau wedi\'u haddasu o Mastodon yn gwneud hynny, ond nid yw Mastodon yn gwneud hynny.</string>
|
||||
<string name="sk_settings_glitch_instance">Modd lleol yn unig Glitch</string>
|
||||
<string name="sk_settings_glitch_mode_explanation">Galluogi hyn os yw eich gweinydd yn rhedeg ar Glitch. Nid oes ei angen ar gyfer Hometown neu Akkoma.</string>
|
||||
<string name="sk_signed_up">Wedi ymuno</string>
|
||||
<string name="sk_reported">Wedi\'i adrodd</string>
|
||||
<string name="sk_sign_ups">Defnyddwyr yn ymuno</string>
|
||||
<string name="sk_new_reports">Adroddiadau newydd</string>
|
||||
<string name="sk_local_only">Gweinydd lleol yn unig</string>
|
||||
<string name="sk_settings_see_new_posts_button">Botwm \"Gweld negeseuon newydd\"</string>
|
||||
<string name="sk_settings_server_version">Fersiwn y gweinydd: %s</string>
|
||||
<string name="sk_notify_poll_results">Canlyniadau\'r pôl</string>
|
||||
</resources>
|
||||
427
mastodon/src/main/res/values-da-rDK/strings.xml
Normal file
427
mastodon/src/main/res/values-da-rDK/strings.xml
Normal file
@@ -0,0 +1,427 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="get_started">Opret konto</string>
|
||||
<string name="already_have_account">Jeg har allerede en konto</string>
|
||||
<string name="log_in">Log ind</string>
|
||||
<string name="next">Næste</string>
|
||||
<string name="loading_instance">Henter serverinfo…</string>
|
||||
<string name="error">Fejl</string>
|
||||
<string name="not_a_mastodon_instance">%s ser ikke ud til at være en Mastodon-server.</string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="preparing_auth">Forbereder godkendelse…</string>
|
||||
<string name="finishing_auth">Afslutter godkendelse…</string>
|
||||
<string name="user_boosted">%s boostede</string>
|
||||
<string name="in_reply_to">Som svar til %s</string>
|
||||
<string name="notifications">Meddelelser</string>
|
||||
<string name="user_followed_you">begyndte at følge dig</string>
|
||||
<string name="user_sent_follow_request">sendte dig en følgeanmodning</string>
|
||||
<string name="user_favorited">favoritmarkerede dit indlæg</string>
|
||||
<string name="notification_boosted">boostede dit indlæg</string>
|
||||
<string name="poll_ended">afstemning afsluttet</string>
|
||||
<string name="time_seconds">%ds</string>
|
||||
<string name="time_minutes">%d m</string>
|
||||
<string name="time_hours">%d t</string>
|
||||
<string name="time_days">%d d</string>
|
||||
<string name="share_toot_title">Del</string>
|
||||
<string name="settings">Indstillinger</string>
|
||||
<string name="publish">Offentliggør</string>
|
||||
<string name="discard_draft">Kassér kladde?</string>
|
||||
<string name="discard">Kassér</string>
|
||||
<string name="cancel">Fortryd</string>
|
||||
<plurals name="followers">
|
||||
<item quantity="one">følger</item>
|
||||
<item quantity="other">følgere</item>
|
||||
</plurals>
|
||||
<plurals name="following">
|
||||
<item quantity="one">følger</item>
|
||||
<item quantity="other">følger</item>
|
||||
</plurals>
|
||||
<plurals name="posts">
|
||||
<item quantity="one">indlæg</item>
|
||||
<item quantity="other">indlæg</item>
|
||||
</plurals>
|
||||
<string name="posts">Indlæg</string>
|
||||
<string name="posts_and_replies">Indlæg og svar</string>
|
||||
<string name="media">Medier</string>
|
||||
<string name="profile_about">Om</string>
|
||||
<string name="button_follow">Følg</string>
|
||||
<string name="button_following">Følger</string>
|
||||
<string name="edit_profile">Redigér profil</string>
|
||||
<string name="mention_user">Nævn %s</string>
|
||||
<string name="share_user">Del %s</string>
|
||||
<string name="mute_user">Skjul %s (mute)</string>
|
||||
<string name="unmute_user">Vis %s igen (unmute)</string>
|
||||
<string name="block_user">Bloker %s</string>
|
||||
<string name="unblock_user">Fjern blokering af %s</string>
|
||||
<string name="report_user">Indberet %s</string>
|
||||
<string name="block_domain">Bloker %s</string>
|
||||
<string name="unblock_domain">Fjern blokering af %s</string>
|
||||
<plurals name="x_posts">
|
||||
<item quantity="one">%,d indlæg</item>
|
||||
<item quantity="other">%,d indlæg</item>
|
||||
</plurals>
|
||||
<string name="profile_joined">Tilmeldt</string>
|
||||
<string name="done">Udført</string>
|
||||
<string name="loading">Indlæser…</string>
|
||||
<string name="field_label">Mærkat</string>
|
||||
<string name="field_content">Indhold</string>
|
||||
<string name="saving">Gemmer…</string>
|
||||
<string name="post_from_user">Indlæg fra %s</string>
|
||||
<string name="poll_option_hint">Valgmulighed %d</string>
|
||||
<plurals name="x_minutes">
|
||||
<item quantity="one">%d minut</item>
|
||||
<item quantity="other">%d minutter</item>
|
||||
</plurals>
|
||||
<plurals name="x_hours">
|
||||
<item quantity="one">%d time</item>
|
||||
<item quantity="other">%d timer</item>
|
||||
</plurals>
|
||||
<plurals name="x_days">
|
||||
<item quantity="one">%d dag</item>
|
||||
<item quantity="other">%d dage</item>
|
||||
</plurals>
|
||||
<string name="compose_poll_duration">Varighed: %s</string>
|
||||
<plurals name="x_seconds_left">
|
||||
<item quantity="one">%d sekund tilbage</item>
|
||||
<item quantity="other">%d sekunder tilbage</item>
|
||||
</plurals>
|
||||
<plurals name="x_minutes_left">
|
||||
<item quantity="one">%d minut tilbage</item>
|
||||
<item quantity="other">%d minutter tilbage</item>
|
||||
</plurals>
|
||||
<plurals name="x_hours_left">
|
||||
<item quantity="one">%d time tilbage</item>
|
||||
<item quantity="other">%d timer tilbage</item>
|
||||
</plurals>
|
||||
<plurals name="x_days_left">
|
||||
<item quantity="one">%d dag tilbage</item>
|
||||
<item quantity="other">%d dage tilbage</item>
|
||||
</plurals>
|
||||
<plurals name="x_voters">
|
||||
<item quantity="one">%,d stemme</item>
|
||||
<item quantity="other">%,d stemmer</item>
|
||||
</plurals>
|
||||
<string name="poll_closed">Lukket</string>
|
||||
<string name="confirm_mute_title">Skjul konto</string>
|
||||
<string name="confirm_mute">Bekræft at du vil skjule %s</string>
|
||||
<string name="do_mute">Skjul (mute)</string>
|
||||
<string name="confirm_unmute_title">Vis bruger igen (unmute)</string>
|
||||
<string name="confirm_unmute">Bekræft at du vil se %s igen</string>
|
||||
<string name="do_unmute">Vis igen (unmute)</string>
|
||||
<string name="confirm_block_title">Bloker bruger</string>
|
||||
<string name="confirm_block_domain_title">Bloker domæne</string>
|
||||
<string name="confirm_block">Bekræft at du vil blokere %s</string>
|
||||
<string name="do_block">Bloker</string>
|
||||
<string name="confirm_unblock_title">Fjern blokering af bruger</string>
|
||||
<string name="confirm_unblock_domain_title">Fjern blokering af domæne</string>
|
||||
<string name="confirm_unblock">Bekræft at du vil fjerne blokering af %s</string>
|
||||
<string name="do_unblock">Fjern blokering</string>
|
||||
<string name="button_muted">Skjult (muted)</string>
|
||||
<string name="button_blocked">Blokeret</string>
|
||||
<string name="action_vote">Stem</string>
|
||||
<string name="tap_to_reveal">Tryk for at vise</string>
|
||||
<string name="delete">Slet</string>
|
||||
<string name="confirm_delete_title">Slet indlæg</string>
|
||||
<string name="confirm_delete">Er du sikker på, at du vil slette dette indlæg?</string>
|
||||
<string name="deleting">Sletter…</string>
|
||||
<string name="notification_channel_audio_player">Afspilning af lyd</string>
|
||||
<string name="play">Afspil</string>
|
||||
<string name="pause">Sæt på pause</string>
|
||||
<string name="log_out">Log ud</string>
|
||||
<string name="add_account">Tilføj konto</string>
|
||||
<string name="search_hint">Søg</string>
|
||||
<string name="hashtags">Hashtags</string>
|
||||
<string name="news">Nyheder</string>
|
||||
<string name="for_you">Til dig</string>
|
||||
<string name="all_notifications">Alle</string>
|
||||
<string name="mentions">Omtaler</string>
|
||||
<plurals name="x_people_talking">
|
||||
<item quantity="one">%d person deltager</item>
|
||||
<item quantity="other">%d personer deltager</item>
|
||||
</plurals>
|
||||
<plurals name="discussed_x_times">
|
||||
<item quantity="one">Diskuteret %d gang</item>
|
||||
<item quantity="other">Diskuteret %d gange</item>
|
||||
</plurals>
|
||||
<string name="report_title">Indberet %s</string>
|
||||
<string name="report_choose_reason">Hvad er der galt med dette indlæg?</string>
|
||||
<string name="report_choose_reason_account">Hvad er der galt med %s?</string>
|
||||
<string name="report_choose_reason_subtitle">Vælg en passende grund</string>
|
||||
<string name="report_reason_personal">Jeg bryder mig ikke om det</string>
|
||||
<string name="report_reason_personal_subtitle">Det er ikke noget, man ønsker at se</string>
|
||||
<string name="report_reason_spam">Det er spam</string>
|
||||
<string name="report_reason_spam_subtitle">Ondsindede links, falske interaktioner, eller gentagne svar</string>
|
||||
<string name="report_reason_violation">Det overtræder serverreglerne</string>
|
||||
<string name="report_reason_violation_subtitle">Du kender til specifikke regler som det er i strid med</string>
|
||||
<string name="report_reason_other">Det er noget andet</string>
|
||||
<string name="report_reason_other_subtitle">Problemet passer ikke ind i andre kategorier</string>
|
||||
<string name="report_choose_rule">Hvilke regler overtrædes?</string>
|
||||
<string name="report_choose_rule_subtitle">Vælg alle relevante</string>
|
||||
<string name="report_choose_posts">Er der indlæg, som kan bekræfte denne anmeldelse?</string>
|
||||
<string name="report_choose_posts_subtitle">Vælg alle relevante</string>
|
||||
<string name="report_comment_title">Er der andet, vi bør vide?</string>
|
||||
<string name="report_comment_hint">Yderligere kommentarer</string>
|
||||
<string name="sending_report">Sender rapport…</string>
|
||||
<string name="report_sent_title">Tak for anmeldelsen, der vil blive set nærmere på dette.</string>
|
||||
<string name="report_sent_subtitle">Mens dette gennemgås, kan du selv bortfiltrere indlæg fra %s.</string>
|
||||
<string name="unfollow_user">Følg ikke længere %s</string>
|
||||
<string name="unfollow">Følg ikke længere</string>
|
||||
<string name="mute_user_explain">Du vil ikke se den pågældendes indlæg eller boosts i din tidslinje. Vedkommende vil ikke få besked om dæmpningen.</string>
|
||||
<string name="block_user_explain">Vedkommende vil ikke længere kunne følge dig eller se dine indlæg, men vedkommende kan se blokeringen.</string>
|
||||
<string name="report_personal_title">Ønsker du ikke at se dette?</string>
|
||||
<string name="report_personal_subtitle">Når du ser noget, du ikke kan lide på Mastodon, kan du fjerne personen fra din tidslinje.</string>
|
||||
<string name="back">Tilbage</string>
|
||||
<string name="instance_catalog_title">Mastodon er skabt af brugere på forskellige servere.</string>
|
||||
<string name="instance_catalog_subtitle">Vælg en server baseret på dine interesser, region eller et generelt formål. Du kan stadig forbinde med alle, uanset serveren.</string>
|
||||
<string name="search_communities">Server-navn eller URL</string>
|
||||
<string name="instance_rules_title">Serverregler</string>
|
||||
<string name="instance_rules_subtitle">Ved at fortsætte accepterer du at følge følgende regler, der er vedtaget og håndhævet af %ss moderatorer.</string>
|
||||
<string name="signup_title">Opret konto</string>
|
||||
<string name="edit_photo">rediger</string>
|
||||
<string name="display_name">Navn</string>
|
||||
<string name="username">Brugernavn</string>
|
||||
<string name="email">Email</string>
|
||||
<string name="password">Adgangskode</string>
|
||||
<string name="confirm_password">Bekræft adgangskode</string>
|
||||
<string name="password_note">Inkluder store bogstaver, specialtegn og tal for at gøre din adgangskode stærkere.</string>
|
||||
<string name="category_academia">Forskning og højere uddannelser</string>
|
||||
<string name="category_activism">Aktivisme</string>
|
||||
<string name="category_all">Alt</string>
|
||||
<string name="category_art">Kunst</string>
|
||||
<string name="category_food">Mad</string>
|
||||
<string name="category_furry">Pelsdyr</string>
|
||||
<string name="category_games">Spil</string>
|
||||
<string name="category_general">Generelt</string>
|
||||
<string name="category_journalism">Journalistik</string>
|
||||
<string name="category_lgbt">LGBT</string>
|
||||
<string name="category_music">Musik</string>
|
||||
<string name="category_regional">Regionalt</string>
|
||||
<string name="category_tech">Teknologi</string>
|
||||
<string name="confirm_email_title">Tjek din indbakke</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="confirm_email_subtitle">Tryk på linket vi sendte dig for at bekræfte %s. Vi venter lige her.</string>
|
||||
<string name="confirm_email_didnt_get">Fandt du ikke et link?</string>
|
||||
<string name="resend">Send igen</string>
|
||||
<string name="open_email_app">Åben email-app</string>
|
||||
<string name="resent_email">Bekræftelses-email sendt</string>
|
||||
<string name="compose_hint">Skriv hvad du har på hjerte</string>
|
||||
<string name="content_warning">Indholdsadvarsel</string>
|
||||
<string name="add_image_description">Tilføj billede beskrivelse…</string>
|
||||
<string name="retry_upload">Forsøg upload igen</string>
|
||||
<string name="edit_image">Rediger billede</string>
|
||||
<string name="save">Gem</string>
|
||||
<string name="add_alt_text">Tilføj alternativ tekst</string>
|
||||
<string name="alt_text_subtitle">Alternativ tekst beskriver dine fotos af hensyn til svagtseende og blinde. Nøjs med at skrive lige nøjagtig så detaljeret at sammenhængen er tydelig.</string>
|
||||
<string name="alt_text_hint">f.eks. en hund, der ser sig mistænkeligt omkring med sammenknebne øjne på kameraet.</string>
|
||||
<string name="visibility_public">Offentlig</string>
|
||||
<string name="visibility_followers_only">Kun følgere</string>
|
||||
<string name="visibility_private">Kun personer jeg nævner</string>
|
||||
<string name="search_all">Alle</string>
|
||||
<string name="search_people">Personer</string>
|
||||
<string name="recent_searches">Seneste søgninger</string>
|
||||
<string name="step_x_of_n">Trin %1$d af %2$d</string>
|
||||
<string name="skip">Spring over</string>
|
||||
<string name="notification_type_follow">Nye følgere</string>
|
||||
<string name="notification_type_favorite">Favoritmarkeringer</string>
|
||||
<string name="notification_type_reblog">Boosts</string>
|
||||
<string name="notification_type_mention">Omtaler</string>
|
||||
<string name="notification_type_poll">Afstemninger</string>
|
||||
<string name="choose_account">Vælg konto</string>
|
||||
<string name="err_not_logged_in">Log venligst ind på Mastodon først</string>
|
||||
<plurals name="cant_add_more_than_x_attachments">
|
||||
<item quantity="one">Du kan ikke tilføje mere end %d medievedhæftning</item>
|
||||
<item quantity="other">Du kan ikke tilføje mere end %d medievedhæftninger</item>
|
||||
</plurals>
|
||||
<string name="media_attachment_unsupported_type">Filen %s er af en type der ikke understøttes</string>
|
||||
<string name="media_attachment_too_big">Størrelsen på filen %1$s overskrider grænsen på %2$s MB</string>
|
||||
<string name="settings_theme">Visuel fremtræden</string>
|
||||
<string name="theme_auto">Automatisk</string>
|
||||
<string name="theme_light">Lys</string>
|
||||
<string name="theme_dark">Mørk</string>
|
||||
<string name="theme_true_black">Sand sort tilstand</string>
|
||||
<string name="settings_behavior">Opførsel</string>
|
||||
<string name="settings_gif">Spil animerede avatarer og emoji</string>
|
||||
<string name="settings_custom_tabs">Benyt in-app browser</string>
|
||||
<string name="settings_notifications">Meddelelser</string>
|
||||
<string name="notify_me_when">Giv mig besked når</string>
|
||||
<string name="notify_anyone">hvem som helst</string>
|
||||
<string name="notify_follower">en følger</string>
|
||||
<string name="notify_followed">nogen jeg følger</string>
|
||||
<string name="notify_none">ingen</string>
|
||||
<string name="notify_favorites">Favoritmarkerede mit indlæg</string>
|
||||
<string name="notify_follow">Følger mig</string>
|
||||
<string name="notify_reblog">Booster mit indlæg</string>
|
||||
<string name="notify_mention">Nævner mig</string>
|
||||
<string name="settings_boring">Den kedelige zone</string>
|
||||
<string name="settings_account">Kontoindstillinger</string>
|
||||
<string name="settings_contribute">Bidrag til Mastodon</string>
|
||||
<string name="settings_tos">Vilkår og Betingelser</string>
|
||||
<string name="settings_privacy_policy">Privatlivspolitik</string>
|
||||
<string name="settings_spicy">Den krydrede zone</string>
|
||||
<string name="settings_clear_cache">Ryd mediecache</string>
|
||||
<string name="settings_app_version">Mastodon til Android v%1$s (%2$d)</string>
|
||||
<string name="media_cache_cleared">Mediecache ryddet</string>
|
||||
<string name="confirm_log_out">Er du sikker på, at du vil logge ud?</string>
|
||||
<string name="sensitive_content">Følsomt indhold</string>
|
||||
<string name="sensitive_content_explain">Forfatteren markerede dette medie som følsomt. Tryk for at afsløre.</string>
|
||||
<string name="media_hidden">Tryk for at vise</string>
|
||||
<string name="avatar_description">Gå til %ss profil</string>
|
||||
<string name="more_options">Flere muligheder</string>
|
||||
<string name="reveal_content">Afslør indhold</string>
|
||||
<string name="hide_content">Skjul indhold</string>
|
||||
<string name="new_post">Nyt indlæg</string>
|
||||
<string name="button_reply">Svar</string>
|
||||
<string name="button_reblog">Boost</string>
|
||||
<string name="button_favorite">Favorit</string>
|
||||
<string name="button_share">Del</string>
|
||||
<string name="media_no_description">Medier uden beskrivelse</string>
|
||||
<string name="add_media">Tilføj medier</string>
|
||||
<string name="add_poll">Tilføj en afstemning</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="post_visibility">Synlighed af indlæg</string>
|
||||
<string name="home_timeline">Hjemmetidslinje</string>
|
||||
<string name="my_profile">Min profil</string>
|
||||
<string name="media_viewer">Mediefremviser</string>
|
||||
<string name="follow_user">Følg %s</string>
|
||||
<string name="unfollowed_user">Følg ikke længere %s</string>
|
||||
<string name="followed_user">Du følger nu %s</string>
|
||||
<string name="open_in_browser">Åbn i browser</string>
|
||||
<string name="hide_boosts_from_user">Skjul boosts fra %s</string>
|
||||
<string name="show_boosts_from_user">Vis boosts fra %s</string>
|
||||
<string name="signup_reason">Hvorfor ønsker du at tilmelde dig?</string>
|
||||
<string name="signup_reason_note">Dette hjælper os med at vurdere din ansøgning.</string>
|
||||
<string name="clear">Ryd</string>
|
||||
<string name="profile_header">Overskriftsbillede</string>
|
||||
<string name="profile_picture">Profilbillede</string>
|
||||
<string name="reorder">Omarranger</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="permission_required">Tilladelse kræves</string>
|
||||
<string name="storage_permission_to_download">Appen skal have adgang til din lagerplads for at gemme denne fil.</string>
|
||||
<string name="open_settings">Åbn Indstillinger</string>
|
||||
<string name="error_saving_file">Fejl under lagring af fil</string>
|
||||
<string name="file_saved">Fil gemt</string>
|
||||
<string name="downloading">Downloader…</string>
|
||||
<string name="no_app_to_handle_action">Der er ingen app til at udføre denne handling</string>
|
||||
<string name="local_timeline">Fællesskab</string>
|
||||
<string name="trending_posts_info_banner">Dette er indlæg der tiltrækker sig opmærksomhed i dit hjørne af Mastodon.</string>
|
||||
<string name="trending_hashtags_info_banner">Dette er hashtags der tiltrækker sig opmærksomhed i dit hjørne af Mastodon.</string>
|
||||
<string name="trending_links_info_banner">Dette er de nyheder, der deles mest i dit hjørne af Mastodon.</string>
|
||||
<string name="local_timeline_info_banner">Disse er de seneste indlæg af medlemmer på din Mastodon-server.</string>
|
||||
<string name="dismiss">Afvis</string>
|
||||
<string name="see_new_posts">Se nye indlæg</string>
|
||||
<string name="load_missing_posts">Indlæs manglende indlæg</string>
|
||||
<string name="follow_back">Følg Tilbage</string>
|
||||
<string name="button_follow_pending">Afventer</string>
|
||||
<string name="follows_you">Følger dig</string>
|
||||
<string name="manually_approves_followers">Godkender følgere manuelt</string>
|
||||
<string name="current_account">Nuværende konto</string>
|
||||
<string name="log_out_account">Log %s ud</string>
|
||||
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
|
||||
<plurals name="x_followers">
|
||||
<item quantity="one">%,d følger</item>
|
||||
<item quantity="other">%,d følgere</item>
|
||||
</plurals>
|
||||
<plurals name="x_following">
|
||||
<item quantity="one">%,d følger</item>
|
||||
<item quantity="other">%,d følgere</item>
|
||||
</plurals>
|
||||
<plurals name="x_favorites">
|
||||
<item quantity="one">%,d favoritmarkering</item>
|
||||
<item quantity="other">%,d favoritmarkeringer</item>
|
||||
</plurals>
|
||||
<plurals name="x_reblogs">
|
||||
<item quantity="one">%,d boost</item>
|
||||
<item quantity="other">%,d boosts</item>
|
||||
</plurals>
|
||||
<string name="timestamp_via_app">%1$s via %2$s</string>
|
||||
<string name="time_now">nu</string>
|
||||
<string name="post_info_reblogs">Boosts</string>
|
||||
<string name="post_info_favorites">Favoritmarkeringer</string>
|
||||
<string name="edit_history">Rediger historik</string>
|
||||
<string name="last_edit_at_x">Senest ændret: %s</string>
|
||||
<string name="time_just_now">lige nu</string>
|
||||
<plurals name="x_seconds_ago">
|
||||
<item quantity="one">%d sekund siden</item>
|
||||
<item quantity="other">%d sekunder siden</item>
|
||||
</plurals>
|
||||
<plurals name="x_minutes_ago">
|
||||
<item quantity="one">%d minut siden</item>
|
||||
<item quantity="other">%d minutter siden</item>
|
||||
</plurals>
|
||||
<string name="edited_timestamp">redigerede %s</string>
|
||||
<string name="edit_original_post">Oprindeligt indlæg</string>
|
||||
<string name="edit_text_edited">Tekst redigeret</string>
|
||||
<string name="edit_spoiler_added">Indholdsadvarsel tilføjet</string>
|
||||
<string name="edit_spoiler_edited">Indholdsadvarsel tilføjet</string>
|
||||
<string name="edit_spoiler_removed">Indholdsadvarsel fjernet</string>
|
||||
<string name="edit_poll_added">Afstemning tilføjet</string>
|
||||
<string name="edit_poll_edited">Afstemning redigeret</string>
|
||||
<string name="edit_poll_removed">Afstemning fjernet</string>
|
||||
<string name="edit_media_added">Medier tilføjet</string>
|
||||
<string name="edit_media_removed">Medier fjernet</string>
|
||||
<string name="edit_media_reordered">Medie omarrangeret</string>
|
||||
<string name="edit_marked_sensitive">Marker som følsom</string>
|
||||
<string name="edit_marked_not_sensitive">Markeret ikke følsom</string>
|
||||
<string name="edit_multiple_changed">Indlæg redigeret</string>
|
||||
<string name="edit">Rediger</string>
|
||||
<string name="discard_changes">Fortryd ændringer?</string>
|
||||
<string name="upload_failed">Upload mislykkedes</string>
|
||||
<string name="file_size_bytes">%d bytes</string>
|
||||
<string name="file_size_kb">%.2f KB</string>
|
||||
<string name="file_size_mb">%.2f MB</string>
|
||||
<string name="file_size_gb">%.2f GB</string>
|
||||
<string name="file_upload_progress">%1$s af %2$s</string>
|
||||
<string name="file_upload_time_remaining">%s tilbage</string>
|
||||
<string name="upload_error_connection_lost">Din enhed har mistet forbindelsen til internettet</string>
|
||||
<string name="upload_processing">Behandler…</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_available">Mastodon til Android %s er klar til download.</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_ready">Mastodon til Android %s er downloadet og klar til at installere.</string>
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">Download (%s)</string>
|
||||
<string name="install_update">Installer</string>
|
||||
<string name="privacy_policy_title">Dit privatliv</string>
|
||||
<string name="i_agree">Jeg accepterer</string>
|
||||
<string name="empty_list">Denne liste er tom</string>
|
||||
<string name="instance_signup_closed">Denne server er ikke åben for nye tilmeldinger.</string>
|
||||
<string name="text_copied">Kopieret til udklipsholderen</string>
|
||||
<string name="add_bookmark">Bogmærk</string>
|
||||
<string name="remove_bookmark">Fjern bogmærke</string>
|
||||
<string name="bookmarks">Bogmærker</string>
|
||||
<string name="your_favorites">Dine Favoritter</string>
|
||||
<string name="login_title">Velkommen tilbage</string>
|
||||
<string name="login_subtitle">Log ind med serveren hvor du oprettede din bruger.</string>
|
||||
<string name="server_url">Server-URL</string>
|
||||
<string name="welcome_page1_title">Hvad er Mastodon?</string>
|
||||
<string name="welcome_page1_text">Det svarer til at du har en e-mailadresse, der slutter med @eksempel.dk.\n\nAlligevel kan du stadig både sende og modtage e-mails fra alle, selv om deres e-mail ender på @gmail.com eller @icloud.com eller @eksempel.dk.</string>
|
||||
<string name="welcome_page2_title">Mastodon er ligesådan.</string>
|
||||
<string name="welcome_page2_text">Dit brugernavn kan være @goth654@eksempel.social, men du kan stadig følge, booste, og chatte med @denanden@eksempel.online.</string>
|
||||
<string name="welcome_page3_title">Hvordan vælger jeg en server?</string>
|
||||
<string name="welcome_page3_text">Forskellige mennesker vælger forskellige servere af mange forskellige grunde. art.example er et godt sted for kunstnere, mens glasgow.example kan være et godt pluk for skotter.\n\nDu kan ikke gå galt i byen med en af vores anbefalingsservere, så uanset hvilken du vælger (eller hvis du indtaster din egen i serversøgelinjen), vil du aldrig gå glip af noget nogen steder.</string>
|
||||
<string name="signup_random_server_explain">Vi vælger en server baseret på dit sprog, hvis du fortsætter uden at foretage et valg.</string>
|
||||
<string name="server_filter_any_language">Hvilket som helst sprog</string>
|
||||
<string name="server_filter_instant_signup">Øjeblikkelig tilmelding</string>
|
||||
<string name="server_filter_manual_review">Manuel evaluering</string>
|
||||
<string name="server_filter_any_signup_speed">Hvilken som helst tilmeldingshastghed</string>
|
||||
<string name="server_filter_region_europe">Europa</string>
|
||||
<string name="server_filter_region_north_america">Nordamerika</string>
|
||||
<string name="server_filter_region_south_america">Sydamerika</string>
|
||||
<string name="server_filter_region_africa">Afrika</string>
|
||||
<string name="server_filter_region_asia">Asien</string>
|
||||
<string name="server_filter_region_oceania">Oceania</string>
|
||||
<string name="not_accepting_new_members">Ikke åben for nye medlemmer</string>
|
||||
<string name="category_special_interests">Særlige Interesser</string>
|
||||
<string name="signup_passwords_dont_match">Adgangskoderne er ikke ens</string>
|
||||
<string name="pick_server_for_me">Vælg for mig</string>
|
||||
<string name="profile_add_row">Tilføj række</string>
|
||||
<string name="profile_setup">Profilopsætning</string>
|
||||
<string name="profile_setup_subtitle">Du kan altid afslutte dette senere i fanen Profil.</string>
|
||||
<string name="profile_setup_explanation">Du kan tilføje op til fire profilfelter til lige, hvad du ønsker. Placering, links, pronomener — du bestemmer.</string>
|
||||
<string name="popular_on_mastodon">Populært på Mastodon</string>
|
||||
<string name="follow_all">Følg alle</string>
|
||||
<string name="server_rules_disagree">Ikke enig</string>
|
||||
<!-- %s is server domain -->
|
||||
<!-- Shown in a progress dialog when you tap "follow all" -->
|
||||
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user