Compare commits

..

840 Commits

Author SHA1 Message Date
sk
333c38c64d add alt badge to video/gifs
closes sk22#409
2023-02-07 15:44:40 +01:00
sk
ca5827e3f8 add null check
closes sk22#414
2023-02-07 15:29:56 +01:00
sk
4884667484 generify fab button
closes sk22#380
2023-02-07 14:10:31 +01:00
sk
a2f687898c fix wrong time in edited notifications
closes sk22#387
2023-02-07 13:34:52 +01:00
sk
defd038064 display roles in profile 2023-02-06 19:41:36 +01:00
sk
f88b65f479 add spectator mode
closes sk22#264
2023-02-06 18:16:41 +01:00
sk
f65d56361f support account filter context 2023-02-06 17:59:06 +01:00
sk
255155b55a fix filters not working in lists
closes sk22#379
2023-02-06 17:52:05 +01:00
sk
ee2e39462a remove broken auto-add user to created list 2023-02-06 17:24:05 +01:00
sk
32b459ae77 hide expand/collapse to screen reader 2023-02-06 16:54:54 +01:00
sk
c1b79da4a7 tweak profile fragment 2023-02-06 15:25:12 +01:00
sk
65dfd8667d realign post header buttons 2023-02-06 15:17:05 +01:00
sk
12558c3c18 handle saving draft when attachment not uploaded
closes sk22#402
2023-02-06 14:31:53 +01:00
sk
dae347a29f fix filtered crash in scheduled posts
closes sk22#408
2023-02-06 14:00:52 +01:00
sk
c51be5f199 add missing margin
closes sk22#407
2023-02-06 13:53:28 +01:00
sk
fc1bd14f70 tweak collapse button 2023-02-06 13:44:57 +01:00
sk
bd39ed3754 fix notifications crashing with collapse button
closes sk22#410
2023-02-06 13:26:56 +01:00
sk
50029c7f73 avoid null pointer when switching tabs
closes sk22#412
2023-02-06 13:16:17 +01:00
sk
e2c907eb10 don't hide collapse button 2023-02-06 11:04:38 +01:00
sk
937747e11b add collapse button to header 2023-02-06 10:42:27 +01:00
sk
85b6bc79a3 increase max text height 2023-02-04 14:21:14 +01:00
sk
ec9d41fbbd collapse long posts 2023-02-03 23:40:20 +01:00
sk
847d966daa only display warning when not already revealed 2023-02-03 23:08:04 +01:00
sk22
618840c76a Display filtered posts with a warning (#406)
* copy changes from @LucasGGamerM
* simplify building filter item
* fix adapter ranges
* change filter item styling

closes sk22#209 

Co-authored-by: LucasGGamerM <71328265+LucasGGamerM@users.noreply.github.com>
2023-02-03 18:33:15 +01:00
sk
33d856562d hide compose fab when editing 2023-02-03 16:54:51 +01:00
sk
9873e9ede5 fix text scaling height and margin issues 2023-02-03 16:24:30 +01:00
sk
63dad42bf3 auto-orientation counters alignment
closes sk22#381
2023-02-03 15:35:36 +01:00
sk
dad58f8245 hide tab bar when editing profile 2023-02-03 15:30:10 +01:00
sk
647a7d70cd rearrange profile items 2023-02-03 15:24:21 +01:00
sk
f49c7dff00 remove about tab 2023-02-03 15:07:15 +01:00
sk
72f638c96c move metadata to profile 2023-02-03 14:50:06 +01:00
sk
35e0897869 move profile counters down 2023-02-02 15:46:26 +01:00
sk
e22cb07d63 Revert "enable selecting text via alt badge"
This reverts commit 14e639aa8a.
2023-02-02 13:41:49 +01:00
sk
c2df989217 fix width misalignment in header 2023-02-01 11:05:50 +01:00
sk
31d0bfb434 fix footer item hitbox sizes
closes sk22#389
2023-02-01 10:59:55 +01:00
sk
14e639aa8a enable selecting text via alt badge
re: sk22#400
2023-02-01 10:36:14 +01:00
sk
6c24e06157 change string 2023-02-01 10:30:31 +01:00
sk
53ce4276f6 Merge remote-tracking branch 'origin/main' 2023-02-01 10:25:43 +01:00
sk
423e919e16 fix crash 2023-02-01 10:25:24 +01:00
aetsucore
c6cd424f30 Prefix replies with "re:" (#385)
* Prefix replies with "re:"
* Use correct quotation marks
* Avoid repeating "re: " prefix when replying to a post that already has it
2023-01-31 10:30:36 +01:00
sk
e282d54f99 Merge remote-tracking branch 'upstream/master' 2023-01-31 00:00:56 +01:00
sk
29ad08f2ea fix crashes
closes sk22#393
closes sk22#394
2023-01-30 23:46:32 +01:00
Gregory K
5c2f72a706 Merge pull request #521 from FineFindus/fix/typos
fix: typos
2023-01-30 01:54:30 +03:00
Grishka
b153a64373 Signup flow redesign WIP 2023-01-30 01:54:13 +03:00
FineFindus
1124486f1f fix(Instance): typo langauges => languages 2023-01-26 20:56:15 +01:00
sk22
c757b1ffea Translated using Weblate (German)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2023-01-26 15:52:46 +00:00
sk22
932655eeb6 Translated using Weblate (German)
Currently translated at 100.0% (251 of 251 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-26 15:52:46 +00:00
sk
21d57b25c9 bump version and update strings 2023-01-26 16:48:36 +01:00
sk
bed572f343 Merge remote-tracking branch 'weblate/main' 2023-01-26 16:43:13 +01:00
sk
c7483a6b20 update screenshots 2023-01-26 16:42:17 +01:00
sk
cdb1e26a4d move some settings around 2023-01-26 16:38:04 +01:00
Oliebol
ce1a450ccb Translated using Weblate (Dutch)
Currently translated at 93.9% (234 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-01-26 15:21:28 +00:00
gallegonovato
dfc244ff41 Translated using Weblate (Spanish)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-26 15:21:28 +00:00
gallegonovato
9c3e2f5deb Translated using Weblate (Spanish)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-01-26 15:21:28 +00:00
gallegonovato
452b286352 Translated using Weblate (Spanish)
Currently translated at 95.5% (238 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-26 15:21:28 +00:00
McKris
6deca645de Translated using Weblate (Polish)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2023-01-26 15:21:28 +00:00
ihor_ck
49fd1aba76 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-01-26 15:21:28 +00:00
tygyh
7bc951ba67 Translated using Weblate (Swedish)
Currently translated at 42.8% (6 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/sv/
2023-01-26 15:21:28 +00:00
Choukajohn
a70e73a8cb Translated using Weblate (French)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2023-01-26 15:21:28 +00:00
ihor_ck
cf345356a5 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-26 15:21:28 +00:00
tygyh
3da3967afa Translated using Weblate (Swedish)
Currently translated at 16.4% (41 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sv/
2023-01-26 15:21:28 +00:00
McKris
a12f09a38a Translated using Weblate (Polish)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-26 15:21:27 +00:00
rex07
a7302cc3e1 Translated using Weblate (Arabic)
Currently translated at 2.4% (6 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-01-26 15:21:27 +00:00
rex07
9aed2a96dc Added translation using Weblate (Arabic) 2023-01-26 15:21:27 +00:00
Linerly
dbe49134e1 Translated using Weblate (Indonesian)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2023-01-26 15:21:27 +00:00
Linerly
089d176704 Translated using Weblate (Indonesian)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-26 15:21:27 +00:00
Espasant3
4e482ef6fa Translated using Weblate (Galician)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-01-26 15:21:27 +00:00
Espasant3
c64397a613 Translated using Weblate (Galician)
Currently translated at 98.3% (245 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-26 15:21:27 +00:00
sk
6c0d4778b7 separate notification toggle for polls 2023-01-26 16:18:19 +01:00
sk
b94c1f4a82 Merge branch 'fix-notify-policy-none' 2023-01-26 16:03:54 +01:00
sk
a29a072e53 unsubscribe from notifications when policy is none
re: mastodon#520
2023-01-26 15:48:10 +01:00
sk
4f435c6957 set disabled state if policy is none
re: mastodon#520
2023-01-26 15:47:30 +01:00
sk
2a6115f6d9 add server version to settings
closes sk22#376
2023-01-26 15:01:41 +01:00
sk
4cbc1e3664 use regular lock in boost menu
closes sk22#375
2023-01-26 14:58:01 +01:00
Choukajohn
1053d2ac0c Translated using Weblate (French)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-26 00:31:07 +00:00
sk22
0123b17602 Translated using Weblate (German)
Currently translated at 92.8% (13 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2023-01-26 00:31:06 +00:00
sk22
1dace6ead9 Translated using Weblate (German)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-26 00:31:06 +00:00
sk22
3287cf69c1 Translated using Weblate (English)
Currently translated at 100.0% (14 of 14 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/en/
2023-01-26 00:31:06 +00:00
sk
a2854524a9 rename string 2023-01-26 01:13:01 +01:00
sk
71c06c0762 Merge remote-tracking branch 'weblate/main' 2023-01-26 01:09:43 +01:00
ihor_ck
e30df6067d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-26 00:09:37 +00:00
edxkl
912a354b1c Translated using Weblate (Portuguese (Brazil))
Currently translated at 90.7% (226 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-26 00:09:36 +00:00
McKris
71f830ea82 Translated using Weblate (Polish)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-26 00:09:36 +00:00
Linerly
bd109a9139 Translated using Weblate (Indonesian)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-26 00:09:36 +00:00
Choukajohn
c82b4445ff Translated using Weblate (French)
Currently translated at 100.0% (249 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-26 00:09:36 +00:00
irure
9a7d149dae Translated using Weblate (Basque)
Currently translated at 93.5% (233 of 249 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-01-26 00:09:36 +00:00
sk
c66e576461 adapt upstream changes 2023-01-26 01:09:08 +01:00
sk
2a47d2fe77 update comment 2023-01-26 00:58:21 +01:00
sk
331d490f4f Merge remote-tracking branch 'upstream/master' 2023-01-26 00:56:48 +01:00
sk
8d722a2130 bump version, update changelog 2023-01-26 00:54:13 +01:00
sk
6863363452 change local-only string 2023-01-26 00:40:10 +01:00
sk
10e66a58eb fix visibility radio button 2023-01-26 00:39:02 +01:00
sk
3a5c27eadc change missing icons 2023-01-26 00:28:14 +01:00
sk
8c6bce4f73 enable boosting local posts 2023-01-26 00:07:50 +01:00
sk
17e1cd1fe9 replace visibility icons 2023-01-25 23:51:42 +01:00
sk
d7aceffc8f change list icon 2023-01-25 23:41:07 +01:00
Grishka
bcb3e217cd More onboarding updates 2023-01-26 01:38:29 +03:00
sk
229c19664c hopefully prevent some crashes 2023-01-25 23:23:43 +01:00
sk
8bdbb2adef dividers and alignments
nobody knows the trouble i've seen
2023-01-25 22:55:14 +01:00
HudobniVolk
907c5a2ca1 Translated using Weblate (Slovenian)
Currently translated at 30.7% (4 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/sl/
2023-01-25 17:32:56 +00:00
HudobniVolk
2a2bfebf48 Translated using Weblate (Slovenian)
Currently translated at 80.4% (189 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-01-25 17:32:56 +00:00
edxkl
eba59549ec Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.7% (225 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-25 17:32:56 +00:00
HudobniVolk
9478a71693 Translated using Weblate (Slovenian)
Currently translated at 15.3% (2 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/sl/
2023-01-25 17:32:56 +00:00
ghose
b01d7a417a Translated using Weblate (Galician)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-01-25 17:32:56 +00:00
ihor_ck
80c77292ed Translated using Weblate (Ukrainian)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-25 17:32:56 +00:00
HudobniVolk
488e6dda04 Translated using Weblate (Slovenian)
Currently translated at 79.5% (187 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-01-25 17:32:56 +00:00
edxkl
689f676668 Translated using Weblate (Portuguese (Brazil))
Currently translated at 86.3% (203 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-25 17:32:56 +00:00
gicorada
a06db9a3ab Translated using Weblate (Italian)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-01-25 17:32:56 +00:00
irure
a7283cbed8 Translated using Weblate (Basque)
Currently translated at 99.1% (233 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-01-25 17:32:56 +00:00
gallegonovato
bc70d5e212 Translated using Weblate (Spanish)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-25 17:32:56 +00:00
AiOO
441686740a Translated using Weblate (Korean)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-25 17:32:56 +00:00
LucasGGamerM
ac0df083f2 Added translation using Weblate (Portuguese) 2023-01-25 17:32:56 +00:00
Espasant3
e10762d5fa Translated using Weblate (Galician)
Currently translated at 92.3% (12 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-01-25 17:32:56 +00:00
McKris
0ca4663c29 Translated using Weblate (Polish)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2023-01-25 17:32:56 +00:00
edxkl
7efd9341b1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 81.7% (192 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-25 17:32:56 +00:00
McKris
3d8693b2bd Translated using Weblate (Polish)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-25 17:32:56 +00:00
Oliebol
a3b5f3c926 Translated using Weblate (Dutch)
Currently translated at 98.2% (231 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-01-25 17:32:56 +00:00
gicorada
f9f4a1d1ef Translated using Weblate (Italian)
Currently translated at 78.2% (184 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-01-25 17:32:56 +00:00
Linerly
dd536002d0 Translated using Weblate (Indonesian)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-25 17:32:56 +00:00
ghose
4f8e381c84 Translated using Weblate (Galician)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-25 17:32:56 +00:00
Choukajohn
3b6b212c9e Translated using Weblate (French)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-25 17:32:56 +00:00
gallegonovato
bf429ee263 Translated using Weblate (Spanish)
Currently translated at 98.2% (231 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-25 17:32:55 +00:00
Espasant3
e7b1301b71 Translated using Weblate (Spanish)
Currently translated at 98.2% (231 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-25 17:32:55 +00:00
ling0412
6726e9523c Translated using Weblate (Chinese (Simplified))
Currently translated at 99.1% (233 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-25 17:32:55 +00:00
sk22
3ffcc7cef2 Translated using Weblate (German)
Currently translated at 100.0% (235 of 235 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-25 17:32:55 +00:00
edxkl
e6232f6d3b Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2023-01-25 17:32:55 +00:00
ihor_ck
5efc431192 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-25 17:32:55 +00:00
HudobniVolk
c3b75782b1 Translated using Weblate (Slovenian)
Currently translated at 35.6% (81 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-01-25 17:32:55 +00:00
edxkl
ec6f3f0cc3 Translated using Weblate (Portuguese (Brazil))
Currently translated at 82.3% (187 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-25 17:32:55 +00:00
Linerly
136c3cfb4a Translated using Weblate (Indonesian)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-25 17:32:55 +00:00
Choukajohn
79d1dbd3b7 Translated using Weblate (French)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-25 17:32:55 +00:00
ling0412
f2e1663c41 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-25 17:32:55 +00:00
Oliebol
5c73f37599 Translated using Weblate (Dutch)
Currently translated at 15.3% (2 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/nl/
2023-01-25 17:32:55 +00:00
sheepnik
7f239abf2f Translated using Weblate (Welsh)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/cy/
2023-01-25 17:32:55 +00:00
sheepnik
a07f7c232a Translated using Weblate (Welsh)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cy/
2023-01-25 17:32:55 +00:00
McKris
4a60a5190f Translated using Weblate (Polish)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2023-01-25 17:32:55 +00:00
ling0412
69986fd869 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/zh_Hans/
2023-01-25 17:32:55 +00:00
ihor_ck
e2ca572d45 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-25 17:32:55 +00:00
HudobniVolk
746e41fdbc Translated using Weblate (Slovenian)
Currently translated at 23.7% (54 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-01-25 17:32:55 +00:00
McKris
091f1f1e8c Translated using Weblate (Polish)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-25 17:32:55 +00:00
Oliebol
844ec185a6 Translated using Weblate (Dutch)
Currently translated at 93.3% (212 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-01-25 17:32:55 +00:00
Linerly
5622eaed83 Translated using Weblate (Indonesian)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-25 17:32:55 +00:00
ghose
dbf25da1db Translated using Weblate (Galician)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-25 17:32:54 +00:00
Choukajohn
d35a416084 Translated using Weblate (French)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-25 17:32:54 +00:00
ling0412
098acb85e4 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-25 17:32:54 +00:00
AiOO
9d67337913 Translated using Weblate (Korean)
Currently translated at 66.9% (152 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-25 17:32:54 +00:00
sk22
914861775a Translated using Weblate (German)
Currently translated at 100.0% (227 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-25 17:32:54 +00:00
sk
c12a6eaee6 support admin notifications 2023-01-25 18:32:07 +01:00
sk
5de23581fe improve local visibility compatibility 2023-01-25 16:49:15 +01:00
sk
413141df1e fix null pointer exception 2023-01-25 16:24:54 +01:00
sk
5f48870a90 re-arrange settings 2023-01-25 15:52:41 +01:00
sk
86e781cdea tweak no alt indicator 2023-01-25 15:32:51 +01:00
sk
34ebd9219f fix alt indicator setting not saving 2023-01-25 15:19:30 +01:00
sk
41688c4670 update string 2023-01-25 12:54:50 +01:00
sk
0d30cd973e support akkoma local visibility 2023-01-25 12:54:35 +01:00
sk
5ed80ca40a Merge remote-tracking branch 'upstream/master' 2023-01-25 10:44:10 +01:00
sk
78958085c3 fix non-local-only posting (which i broke) 2023-01-25 10:33:04 +01:00
Grishka
a1798b6666 Update onboarding 2023-01-24 23:43:56 +03:00
sk
baa7dd6302 add missing import 2023-01-24 16:05:59 +01:00
sk
ba93e5bac3 bump version 2023-01-24 16:04:30 +01:00
sk
2358d3c602 implement local-only posting 2023-01-24 16:04:17 +01:00
sk
cf61626901 use notification icon 2023-01-24 12:41:23 +01:00
sk
349a1115a6 add indicator for direct and local-only posts 2023-01-24 12:40:23 +01:00
sk
8fa4980ba5 don't apply title for hashtags/lists
closes sk22#343
2023-01-24 11:20:14 +01:00
sk
099d0ccf94 no hashtag header in list timeline
closes sk22#366
2023-01-24 11:06:35 +01:00
sk
35a1de7888 add option to disable show new posts button 2023-01-24 10:53:11 +01:00
sk
6fc850b5ba tweak no alt indicator background 2023-01-24 10:08:03 +01:00
sk
96f13defd4 Revert "bigger hitbox for alt indicator"
This reverts commit 1b04440546.

this commit just wasn't working properly. animation would have a
frame of stuttering and i don't know where that came from or how i
could fix that. also, the code was a mess anyway
2023-01-24 09:46:22 +01:00
sk
36dd07aa38 fix loading default visibility 2023-01-24 09:31:49 +01:00
sk
6a831539ad bump version, again 2023-01-24 09:31:16 +01:00
sk
c679f5529e add null check 2023-01-24 02:17:15 +01:00
sk
9c8096274a bump version 2023-01-24 01:28:49 +01:00
sk
7291b2da5a implement pre-release toggle 2023-01-24 01:27:17 +01:00
sk
4ff98140cb fix navigation bumpiness
closes sk22#347
2023-01-24 01:09:41 +01:00
sk
c2a993c5c1 don't override visibility when replying to self
closes sk22#348
2023-01-23 22:00:23 +01:00
sk
1b04440546 bigger hitbox for alt indicator
closes sk22#353
2023-01-23 20:13:01 +01:00
sk
c0c276f03e add indicator for missing alt texts
closes sk22#355
2023-01-23 19:21:21 +01:00
sk
d30b1f7bbd hide scheduling options when editing
closes sk22#364
2023-01-23 17:11:10 +01:00
sk
c0ee16cf08 fix current language getting overwritten 2023-01-23 16:57:56 +01:00
sk
a37fb33a68 prompt when saving edited draft
closes sk22#319
2023-01-23 16:11:09 +01:00
sk
59095e4ffe Merge remote-tracking branch 'upstream/master' 2023-01-23 15:32:32 +01:00
sk
626614c03d Merge branch 'improve-compose-toolbar-hitbox' 2023-01-23 15:32:02 +01:00
Gregory K
58ab0c0fc1 Merge pull request #516 from sk22/improve-compose-toolbar-hitbox
Bigger hitbox for items in compose toolbar
2023-01-23 17:17:20 +03:00
sk
32a8d38edf bigger hitbox for items in compose toolbar 2023-01-23 14:54:39 +01:00
sk
82534f7c4a change add media icon
closes sk22#351
2023-01-23 14:42:05 +01:00
sk
c6d7242043 display header for followed hashtags
closes sk22#323
2023-01-23 14:31:09 +01:00
sk
c4e23b0fe6 update hashtags/lists in home
closes sk22#312
2023-01-23 13:57:17 +01:00
Gregory K
a5c753a9f8 Merge pull request #515 from sk22/allow-notifications-toolbar-tab
Enable scrolling to top by tapping Notifications toolbar
2023-01-23 15:38:07 +03:00
sk
e3520df57e Merge branch 'allow-notifications-toolbar-tab' 2023-01-23 12:50:05 +01:00
sk
66cede567e enable scrolling to top via toolbar 2023-01-23 12:49:55 +01:00
sk
6916f435b3 improve search empty text 2023-01-23 12:41:10 +01:00
sk
dab0c560e9 fix crash when recycler view is null 2023-01-23 12:23:15 +01:00
sk
1b23ef31d5 improve header icons
* align more button to action overflow button
* use different background to better reflect hitbox
2023-01-23 12:14:05 +01:00
sk
dd7af8b5d3 use fluent more icon, correct padding
closes sk22#350
2023-01-23 11:43:19 +01:00
sk
5914ef8fad fix akkoma crash on list edit
closes sk22#352
2023-01-23 10:51:24 +01:00
sk
a26ddfe70f move edit timelines option 2023-01-23 10:25:44 +01:00
sk
cb067ca4fa clean up code 2023-01-23 10:21:19 +01:00
sk
3df9a3eecc probably fix options menu issue
closes sk22#360
2023-01-23 10:20:06 +01:00
sk
987cbc86ec fix wrong status bar color
closes sk22#363
2023-01-23 10:13:23 +01:00
sk
66dcaa9169 Merge remote-tracking branch 'origin/main' 2023-01-23 10:07:55 +01:00
sk
7162feea31 fix double-click icon button 2023-01-23 10:07:43 +01:00
sk22
1a51744807 Update blocks.tsv 2023-01-22 17:36:04 +01:00
sk22
f83a28a1b3 Adding a 12 hour option for polls (#346)
Co-authored-by: Pleclown <pleclown+github@gmail.com>

closes #346
2023-01-22 13:38:29 +01:00
sk
f5d4e2a0b5 Merge remote-tracking branch 'upstream/master' 2023-01-22 03:44:30 +01:00
sk
4aaf0c4fa4 Merge remote-tracking branch 'weblate/main' 2023-01-22 03:27:55 +01:00
sk22
38e133bee4 Translated using Weblate (German)
Currently translated at 99.1% (225 of 227 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-22 02:26:28 +00:00
sk
87bc01d985 remove add media string 2023-01-22 03:26:18 +01:00
sk
d5561674cd add a few icons 2023-01-22 03:15:07 +01:00
ihor_ck
48ec9e9fc6 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (174 of 174 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-22 02:11:57 +00:00
Linerly
63775c6eb9 Translated using Weblate (Indonesian)
Currently translated at 100.0% (174 of 174 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-22 02:11:57 +00:00
Choukajohn
79a61f6865 Translated using Weblate (French)
Currently translated at 100.0% (174 of 174 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-22 02:11:57 +00:00
florian-obernberger
5f7e03a562 Translated using Weblate (German)
Currently translated at 91.9% (160 of 174 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-22 02:11:57 +00:00
sheepnik
c93c4efe1d Translated using Weblate (Welsh)
Currently translated at 15.3% (2 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/cy/
2023-01-22 02:11:57 +00:00
sheepnik
69771269fc Translated using Weblate (Welsh)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cy/
2023-01-22 02:11:57 +00:00
gicorada
e7a28696c6 Translated using Weblate (Italian)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-01-22 02:11:57 +00:00
sk
124ad1df06 add a few icons 2023-01-22 03:11:41 +01:00
sk
3a6ace53d5 add back file opener
closes sk22#328
2023-01-22 01:06:49 +01:00
sk
1e825c979c rearrange home menus 2023-01-22 00:43:17 +01:00
Grishka
c67b2b35f3 Fix #509 2023-01-22 02:08:55 +03:00
Grishka
8588ca8ae3 Fix #510 2023-01-22 02:05:36 +03:00
Grishka
7bb280e8b8 Fix #69 (nice) 2023-01-22 02:04:12 +03:00
sk
ad1e1b112b Merge remote-tracking branch 'upstream/master' 2023-01-21 23:14:35 +01:00
sk
29139a8f4d Revert "work around crash onHidden"
This reverts commit 763c5fe2a7.
2023-01-21 23:14:24 +01:00
Grishka
ddfeaabd44 Fix #512 2023-01-22 01:12:39 +03:00
Gregory K
51219bf98a Merge pull request #513 from sk22/fix-has-spoiler-restore
Fix wrong "hasSpoiler" value on restore
2023-01-22 01:11:42 +03:00
sk
335f734698 Merge branch 'fix-has-spoiler-restore' 2023-01-21 23:09:12 +01:00
sk
512cb70347 fix wrong "hasSpoiler" value on restore
closes sk22#324
2023-01-21 23:06:31 +01:00
sk
c7e0adfbd4 Merge remote-tracking branch 'weblate/main' 2023-01-21 22:50:26 +01:00
sk
ad7a9626a4 fix typo in string 2023-01-21 22:50:11 +01:00
sk
92f37fdf16 scroll image in alt text editor
closes sk22#315
2023-01-21 22:48:00 +01:00
sk
900e8fb2e9 notifications for edited posts
closes sk22#331
2023-01-21 22:06:00 +01:00
sk
be4b032527 fix redrafting empty posts
closes sk22#325
2023-01-21 21:48:33 +01:00
sk
95cb04530f add lists to status header 2023-01-21 21:39:11 +01:00
sk
4b6a0b71a0 restart app when pinned changes 2023-01-21 19:55:51 +01:00
sk
187190c07e update bug report template 2023-01-21 19:29:48 +01:00
sk
5142851f57 remove pivot for timeline title 2023-01-21 19:24:55 +01:00
sk
763c5fe2a7 work around crash onHidden
re: mastodon#512
2023-01-21 19:24:33 +01:00
sk
7f0265fe24 work around black screen opening notifs
closes sk22#342
2023-01-21 19:22:23 +01:00
sk
f87827700b different icon for post notifs 2023-01-21 16:17:53 +01:00
sk
fb2c0c0ec2 tweak alt button 2023-01-21 02:35:46 +01:00
sk
ec40488ed1 Merge remote-tracking branch 'upstream/master' 2023-01-21 02:25:44 +01:00
sk22
88851a085e Pinnable timelines (#338)
* implement draggable list

* implement pinning timelines

* fix TimelineDefinition equals not working

* implement removing timelines

* implement pinned lists/hashtags

* per-account pinned timelines

* implement pin button

* fix issues with pinning

* improve pin button

* improve pinning timelines

* implement custom icons

* fix home switcher menu

* make hashtags pinnable

* edit timelines in options menu
2023-01-21 02:17:47 +01:00
Espasant3
87c743886e Translated using Weblate (Galician)
Currently translated at 61.5% (8 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-01-19 12:53:13 +00:00
McKris
f3cde5441b Translated using Weblate (Polish)
Currently translated at 96.6% (144 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-19 12:53:13 +00:00
ghose
7a9534772d Translated using Weblate (Galician)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-19 12:53:13 +00:00
Jippang
42faa62a5f Translated using Weblate (Korean)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-19 12:53:13 +00:00
Grishka
6e718d6765 Save last seen home timeline post via markers API 2023-01-18 20:29:49 +03:00
Grishka
b26d491eda remove log 2023-01-18 20:10:03 +03:00
Grishka
abdbab9d7b Allow viewing alt text on images
closes #100
2023-01-18 20:09:27 +03:00
Grishka
af1c7194e6 Workaround to fix #497 2023-01-18 18:41:48 +03:00
sk
8e507e7970 move post notifications into home
closes sk22#314
2023-01-18 12:29:33 +01:00
sk
3b542730b1 fix update item margin
closes sk22#308
2023-01-18 12:10:35 +01:00
sk
b038f81718 add alt text reminder
closes sk22#103
2023-01-18 12:08:40 +01:00
sk
e1206703cf disable translating scheduled posts
closes sk22#318
2023-01-18 11:39:49 +01:00
Espasant3
924affee14 Translated using Weblate (Galician)
Currently translated at 61.5% (8 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-01-18 08:32:08 +00:00
sheepnik
0c5da34cd6 Translated using Weblate (Welsh)
Currently translated at 62.4% (93 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cy/
2023-01-18 08:32:08 +00:00
AiOO
b44e6b9f0a Translated using Weblate (Korean)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2023-01-18 08:32:08 +00:00
gallegonovato
9d3369f601 Translated using Weblate (Spanish)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-01-18 08:32:07 +00:00
edxkl
f607ed314d Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.9% (143 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-18 08:32:07 +00:00
McKris
2cdf642ca3 Translated using Weblate (Polish)
Currently translated at 95.9% (143 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-18 08:32:07 +00:00
Oliebol
5d278eb5aa Translated using Weblate (Dutch)
Currently translated at 97.9% (146 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-01-18 08:32:07 +00:00
Espasant3
860c2826e3 Translated using Weblate (Galician)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-18 08:32:07 +00:00
ghose
3060c36cca Translated using Weblate (Galician)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-18 08:32:07 +00:00
gallegonovato
a1b0632c75 Translated using Weblate (Spanish)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-18 08:32:07 +00:00
ling0412
14cbb1107f Translated using Weblate (Chinese (Simplified))
Currently translated at 99.3% (148 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-18 08:32:07 +00:00
AiOO
dd5f352f5e Translated using Weblate (Korean)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-18 08:32:07 +00:00
ihor_ck
d148883ab2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-01-17 11:26:44 +00:00
Linerly
cfa93424cc Translated using Weblate (Indonesian)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2023-01-17 11:26:43 +00:00
ihor_ck
ff575f75c7 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-17 11:26:43 +00:00
itslameni
6fec7a5205 Translated using Weblate (Russian)
Currently translated at 81.2% (121 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-01-17 11:26:43 +00:00
Oliebol
0693495e12 Translated using Weblate (Dutch)
Currently translated at 97.9% (146 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-01-17 11:26:43 +00:00
Linerly
04381d57f2 Translated using Weblate (Indonesian)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 11:26:43 +00:00
ghose
9f4adcab23 Translated using Weblate (Galician)
Currently translated at 46.9% (70 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-17 11:26:43 +00:00
Choukajohn
00dba5981c Translated using Weblate (French)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 11:26:43 +00:00
AiOO
ae838fe4d7 Translated using Weblate (Korean)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-17 11:26:43 +00:00
sk
2110861f1b bump version 2023-01-17 02:20:27 +01:00
sk
4f6476c807 fix "0" reply to ID 2023-01-17 02:17:40 +01:00
sk22
eccfa27128 Translated using Weblate (German)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2023-01-17 00:58:32 +00:00
sk22
460bce6174 Translated using Weblate (German)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2023-01-17 00:57:46 +00:00
ling0412
d40790a85a Translated using Weblate (Chinese (Simplified))
Currently translated at 97.9% (146 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-17 00:57:46 +00:00
sk22
75dc6fd019 Translated using Weblate (German)
Currently translated at 100.0% (149 of 149 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-17 00:57:46 +00:00
sk22
581e2056f7 Translated using Weblate (English)
Currently translated at 100.0% (13 of 13 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/en/
2023-01-17 00:57:46 +00:00
ihor_ck
70d5100419 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (144 of 144 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-17 00:57:46 +00:00
Linerly
0285d9620e Translated using Weblate (Indonesian)
Currently translated at 100.0% (144 of 144 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 00:57:46 +00:00
Choukajohn
f6411052dd Translated using Weblate (French)
Currently translated at 100.0% (144 of 144 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 00:57:46 +00:00
ling0412
ff21c0c103 Translated using Weblate (Chinese (Simplified))
Currently translated at 98.6% (142 of 144 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-17 00:57:46 +00:00
gicorada
443c18ce13 Translated using Weblate (Italian)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/it/
2023-01-17 00:57:46 +00:00
ihor_ck
7380da88f9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-17 00:57:46 +00:00
Oliebol
a7551ce9d9 Translated using Weblate (Dutch)
Currently translated at 93.7% (134 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-01-17 00:57:46 +00:00
gicorada
dbb2c62702 Translated using Weblate (Italian)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-01-17 00:57:46 +00:00
Choukajohn
eb2385afe4 Translated using Weblate (French)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 00:57:46 +00:00
Nicolas_Horvath
6c63e7b833 Translated using Weblate (Czech)
Currently translated at 13.9% (20 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cs/
2023-01-17 00:57:46 +00:00
ca
d8eb1f280b Translated using Weblate (Catalan)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2023-01-17 00:57:46 +00:00
ca
82a90d5486 Translated using Weblate (Catalan)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ca/
2023-01-17 00:57:46 +00:00
ca
78a3c43b06 Translated using Weblate (Catalan)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2023-01-17 00:57:46 +00:00
EifionLlwyd
54c23b2d05 Translated using Weblate (Welsh)
Currently translated at 48.2% (69 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cy/
2023-01-17 00:57:46 +00:00
McKris
3fb350abe4 Translated using Weblate (Polish)
Currently translated at 58.3% (7 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2023-01-17 00:57:46 +00:00
gallegonovato
2e4bb98bb0 Translated using Weblate (Spanish)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-01-17 00:57:46 +00:00
ihor_ck
0d2d4dd1b2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-17 00:57:46 +00:00
HudobniVolk
f8b1695c61 Translated using Weblate (Slovenian)
Currently translated at 15.3% (22 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-01-17 00:57:46 +00:00
edxkl
b456973c6a Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.1% (136 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-17 00:57:46 +00:00
McKris
7c4616568b Translated using Weblate (Polish)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-01-17 00:57:46 +00:00
Linerly
1e93360778 Translated using Weblate (Indonesian)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 00:57:46 +00:00
ghose
e7db1fcfc1 Translated using Weblate (Galician)
Currently translated at 25.1% (36 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-17 00:57:46 +00:00
Choukajohn
8be50e126b Translated using Weblate (French)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 00:57:46 +00:00
gallegonovato
a75611e707 Translated using Weblate (Spanish)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-17 00:57:45 +00:00
ling0412
1df643fc9a Translated using Weblate (Chinese (Simplified))
Currently translated at 98.6% (141 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-17 00:57:45 +00:00
AiOO
1e730df767 Translated using Weblate (Korean)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-17 00:57:45 +00:00
maxocito
f4c097704e Translated using Weblate (German)
Currently translated at 100.0% (143 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-17 00:57:45 +00:00
ca
a86035a4ed Translated using Weblate (Catalan)
Currently translated at 98.6% (141 of 143 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2023-01-17 00:57:45 +00:00
Anonymous
5b57b4ca79 Translated using Weblate (Burmese)
Currently translated at 71.4% (100 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/my/
2023-01-17 00:57:45 +00:00
Linerly
5e9dda72b5 Translated using Weblate (Indonesian)
Currently translated at 100.0% (140 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 00:57:45 +00:00
ghose
4121346794 Translated using Weblate (Galician)
Currently translated at 10.7% (15 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-01-17 00:57:45 +00:00
mondstern
3ce24f72d8 Translated using Weblate (Czech)
Currently translated at 13.5% (19 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cs/
2023-01-17 00:57:45 +00:00
NovaQ64
5ee81a6416 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.1% (136 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-17 00:57:45 +00:00
EifionLlwyd
0fb7402094 Translated using Weblate (Welsh)
Currently translated at 23.5% (33 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/cy/
2023-01-17 00:57:45 +00:00
ihor_ck
4de4617cf5 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-01-17 00:57:45 +00:00
ihor_ck
bc3ace42f4 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (140 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-17 00:57:45 +00:00
brenno
7c9437b5d2 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.4% (135 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-17 00:57:45 +00:00
Linerly
7d4b82f4ca Translated using Weblate (Indonesian)
Currently translated at 88.5% (124 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 00:57:45 +00:00
Choukajohn
f7ea6fb0dd Translated using Weblate (French)
Currently translated at 100.0% (140 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 00:57:45 +00:00
gallegonovato
afff61fe8c Translated using Weblate (Spanish)
Currently translated at 100.0% (140 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-17 00:57:45 +00:00
ling0412
d60c82b21c Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (140 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-17 00:57:45 +00:00
sk22
7c9107f229 Translated using Weblate (German)
Currently translated at 100.0% (140 of 140 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-17 00:57:45 +00:00
EifionLlwyd
40eb686418 Added translation using Weblate (Welsh) 2023-01-17 00:57:45 +00:00
irure
bf9f859827 Translated using Weblate (Basque)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-01-17 00:57:45 +00:00
Hiajen
cd51bca670 Translated using Weblate (German)
Currently translated at 97.6% (122 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-01-17 00:57:45 +00:00
AiOO
2048a49f9b Translated using Weblate (Korean)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-17 00:57:45 +00:00
irure
ea00117844 Translated using Weblate (Basque)
Currently translated at 93.6% (117 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-01-17 00:57:45 +00:00
mondstern
f8df86ae6b Translated using Weblate (Hungarian)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/hu/
2023-01-17 00:57:45 +00:00
edxkl
924f792f8b Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2023-01-17 00:57:45 +00:00
khant
02c9928a1f Translated using Weblate (Burmese)
Currently translated at 16.6% (2 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/my/
2023-01-17 00:57:45 +00:00
AiOO
0fec486ce0 Translated using Weblate (Korean)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2023-01-17 00:57:45 +00:00
gallegonovato
c6c90d61b5 Translated using Weblate (Spanish)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-01-17 00:57:45 +00:00
HitaloM
9147b3b495 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2023-01-17 00:57:45 +00:00
ling0412
a9cca7f8db Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/zh_Hans/
2023-01-17 00:57:45 +00:00
Choukajohn
e8e8eef42d Translated using Weblate (French)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2023-01-17 00:57:45 +00:00
khant
c1f31f3983 Translated using Weblate (Burmese)
Currently translated at 80.0% (100 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/my/
2023-01-17 00:57:45 +00:00
ihor_ck
3df7123599 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-01-17 00:57:45 +00:00
edxkl
6dd4b202d9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 84.0% (105 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-01-17 00:57:45 +00:00
Linerly
71432fb87d Translated using Weblate (Indonesian)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 00:57:44 +00:00
Choukajohn
1a0a09ddae Translated using Weblate (French)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 00:57:44 +00:00
gallegonovato
94b0c8be08 Translated using Weblate (Spanish)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-01-17 00:57:44 +00:00
ling0412
5cb5f426d8 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-01-17 00:57:44 +00:00
AiOO
2b0b612191 Translated using Weblate (Korean)
Currently translated at 100.0% (125 of 125 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-17 00:57:44 +00:00
AiOO
6c4424bca4 Translated using Weblate (Korean)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2023-01-17 00:57:44 +00:00
Linerly
b9e46339cd Translated using Weblate (Indonesian)
Currently translated at 100.0% (124 of 124 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-01-17 00:57:44 +00:00
Choukajohn
ded00f84f1 Translated using Weblate (French)
Currently translated at 100.0% (124 of 124 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-01-17 00:57:44 +00:00
AiOO
79b74a1960 Translated using Weblate (Korean)
Currently translated at 100.0% (124 of 124 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-01-17 00:57:44 +00:00
itslameni
25e8febc44 Translated using Weblate (Russian)
Currently translated at 91.6% (11 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2023-01-17 00:57:44 +00:00
sk
6cc2885050 update changelog 2023-01-17 01:57:11 +01:00
sk
a68053f3a5 update readme and changelog 2023-01-17 01:47:10 +01:00
sk
deca8df309 bump version 2023-01-17 01:43:50 +01:00
sk
60edcfee1f add changelog to updater
thanks, @LucasGGamerM!
2023-01-17 01:26:08 +01:00
sk
eb1ab99262 fix null-pointer when switching themes 2023-01-17 00:44:55 +01:00
sk
e75d350b7a implement soft-blocking
sk22#297
2023-01-16 23:56:32 +01:00
sk
e9cfe3dee0 change search placeholder string 2023-01-16 22:09:10 +01:00
sk
753914ca5a fix akkoma link previews not showing
closes sk22#183
2023-01-16 22:06:20 +01:00
sk
93e3097993 fix images not loading on akkoma
closes sk22#25
2023-01-16 21:38:47 +01:00
sk
0916eddbb7 hide recent searches header
closes sk22#188
2023-01-16 21:20:31 +01:00
sk
a4848f001b double-tab search to open keyboard
closes sk22#119
2023-01-16 21:09:32 +01:00
sk
8952cd6f97 make announcements selectable
closes sk22#275
2023-01-16 20:23:38 +01:00
sk
4a3e6888d6 display unread announcements first
closes sk22#274
2023-01-16 19:46:44 +01:00
sk
b9bcb62cda tweak timeline title animation 2023-01-16 19:38:00 +01:00
sk
d3491b5753 include list title in delete prompt
closes sk22#304
2023-01-16 19:12:37 +01:00
sk
9e9f9357fd display image cache size
closes sk22#301
2023-01-16 19:06:40 +01:00
sk
ec525bde6d fix clearing notifications
closes sk22#292
2023-01-16 18:32:42 +01:00
sk
ee19410cc6 add missing draft params
closes sk22#302
2023-01-16 18:12:21 +01:00
sk
0468ae246e only show new posts button at home 2023-01-16 18:02:35 +01:00
sk
9722cd9e12 set pivot of timeline title
closes sk22#296
2023-01-16 18:00:43 +01:00
sk
85799a7d93 fix cut off text
closes sk22#295
2023-01-16 17:55:44 +01:00
sk
e222559bde remove debug statements 2023-01-16 17:29:27 +01:00
sk
2f3c7dc8f1 improve multi-line style 2023-01-16 17:28:33 +01:00
sk
d86588bbe2 don't cut off multi-line strings 2023-01-16 16:51:38 +01:00
sk
2bf787c8f2 fix new posts centered layout 2023-01-16 16:46:09 +01:00
sk
82ab8bef56 fix centering button in rtl 2023-01-16 16:15:35 +01:00
sk
cf024dc85f fix rtl direction 2023-01-16 15:50:17 +01:00
sk
ddebe1b3c0 restore current tab 2023-01-16 14:46:12 +01:00
sk
070e5637cc don't use old fragments 2023-01-16 14:46:03 +01:00
sk
bdd3c849e7 simplify method 2023-01-16 10:08:06 +01:00
sk
21073b11d0 don't require unused fields 2023-01-16 09:48:29 +01:00
sk
b4fa74b78f Merge remote-tracking branch 'upstream/master' 2023-01-16 09:39:29 +01:00
Gregory K
ab3a98fd60 Merge pull request #439 from Poussinou/patch-1
Update README.md
2023-01-15 22:15:30 +03:00
Grishka
6e6fdbccd5 Fix #484 2023-01-15 11:40:06 +03:00
Grishka
1764e5f3d1 Paginate trending posts 2023-01-15 11:09:53 +03:00
sk
1cc6bf4971 change crash workaround 2023-01-13 18:24:23 +01:00
sk
54200991cb Revert "work around crash theme switch"
This reverts commit 58fd0c444f30aa5352486b97cab34b2aca6ce8ab.
2023-01-13 18:18:39 +01:00
sk
6bea10bdac add pager title transition 2023-01-13 05:46:43 +01:00
sk
6c615a4893 don't use person icon for unblock
close #245
2023-01-13 04:52:35 +01:00
sk
3dc338b3a5 fix multiple notifications
close sk22#219
2023-01-13 04:50:51 +01:00
sk22
37278ff52b New home layout with public timelines (#288)
* add dummy popup menu
* add pager to home fragment
* reduce pager sensitivity
* remove timelines from discover fragment
* add fabs to timelines
* change info banner color
* add back toolbar functionality
* update icons on navigate
* handle back press
* add lists and hashtags
* use tabs
* improve timeline title
* tweak switcher behavior
* fix show new posts button appearance
* hide show new posts button on reload
* tweak show new posts animations
* work around crash theme switch
* enable disabling federated timeline
2023-01-13 04:35:48 +01:00
sk
17262ebdac Merge remote-tracking branch 'upstream/master' 2023-01-11 22:49:50 +01:00
Grishka
836c493951 Fix #499 2023-01-12 00:40:50 +03:00
sk
eb45874546 tweak list decoration
closes sk22#273
2023-01-11 14:46:09 +01:00
sk
f75520a1d8 fix edit user lists always visible
closes sk22#272
2023-01-11 14:44:26 +01:00
sk
b5392f0c2b Merge remote-tracking branch 'upstream/master' 2023-01-11 14:37:58 +01:00
Grishka
d667b8fa98 Fix #498 2023-01-11 13:06:40 +03:00
Gregory K
6a1032cd61 Merge pull request #492 from tylersaunders/mastodon-photopicker
Update ComposeFragment to use the photopicker.
2023-01-11 12:49:19 +03:00
sk
d72f8d3f9c disable more button when read
closes #262
2023-01-10 16:09:55 +01:00
sk
cd95a75f8f fix editing sensitive option
closes sk22#260
2023-01-10 15:54:08 +01:00
sk
e7bb393cee add more domains 2023-01-10 15:41:52 +01:00
sk
9b74373c22 improve domain check logic 2023-01-10 15:41:46 +01:00
LucasGGamerM
de0afdfa16 improve fab background color
thanks, @LucasGGamerM!
2023-01-10 15:26:19 +01:00
sk
480b3f1902 add missing icons to popup 2023-01-10 15:25:06 +01:00
sk
be73ca188d add dividers to lists 2023-01-10 15:05:06 +01:00
sk
d0ad55611d move lists and change icons 2023-01-10 14:26:46 +01:00
sk
d47797bf7a implement editing lists
re: sk22#30
2023-01-10 13:56:37 +01:00
sk
54c29fd787 implement deleting lists
re: sk22#30
2023-01-10 13:27:28 +01:00
sk
294595513a implement creating lists
re: sk22#30
2023-01-10 11:33:04 +01:00
sk
b8f101ead7 change lists string 2023-01-10 09:39:25 +01:00
sk
2614118d7d don't overwrite notifications
re: sk22#219
2023-01-10 09:38:28 +01:00
sk
cbcbaaa9fa add missing margin 2023-01-10 09:13:15 +01:00
FineFindus
7c6f6816b3 feat(settings): add about instance link (#263) 2023-01-10 09:13:02 +01:00
sk
3e3ed050ba bump version 2023-01-09 17:18:43 +01:00
sk
84179bc207 implement announcements
closes #127
2023-01-09 17:16:55 +01:00
sk
9dc795ded7 don't connect to fascists 2023-01-09 12:25:48 +01:00
sk
9c733d65b2 tweak header text margin 2023-01-09 11:24:02 +01:00
sk
4d49890b1e hide keyboard when navigating
closes #227
2023-01-09 11:15:14 +01:00
sk
f78c6978cf scale text according to system
closes #244
2023-01-09 11:11:00 +01:00
sk
b58a3d89e8 fix wrong pin icon
closes #230
2023-01-09 10:47:12 +01:00
sk
cd0cfba7c0 click "replying to" to scroll up
closes #241
2023-01-09 10:44:51 +01:00
sk
713c95d597 tweak reply animation
closes #237
2023-01-09 10:38:30 +01:00
sk
15534ad42e don't add subject if blank
closes #240
2023-01-09 10:30:49 +01:00
Thiago 'Jedi' Abreu
32bb3fac69 Filter all status, even if filters are empty (#255) 2023-01-09 10:23:14 +01:00
sk
e604da4ff4 Merge remote-tracking branch 'upstream/master' 2023-01-09 10:22:25 +01:00
Tyler Saunders
557d535e5a Update ComposeFragment to use the photopicker.
The android platform has a great photopicker, and this change checks
for the current device's sdk version, and uses the photopicker if it's
available on the device.

For pre Android R sdkrev2 devices, the experience remains unchanged.
2023-01-03 17:21:22 +00:00
Gregory K
60517b00f3 Merge pull request #491 from mishnz/master
Second fix for MIME64 inconsistency in serverKey.
2023-01-02 14:23:23 +03:00
mishnz
faf5e8e82b Merge branch 'master' of https://github.com/mishnz/mastodon-android 2023-01-03 00:16:12 +13:00
mishnz
7264982761 serverKey assignment was missing, corrected. 2023-01-03 00:15:45 +13:00
mishnz
fedf74258f Merge branch 'mastodon:master' into master 2023-01-03 00:06:53 +13:00
mishnz
def4960be6 Second fix for MIME64 inconsistency in serverKey.
The previous fix https://github.com/mastodon/mastodon-android/pull/486 would break any connections to any instances using WEB_SAFE MIME64 encoding on the serverKey, which actually appears to be the usual case.
This update reverts to the previous logic, but also converts standard MIME64 characters ('/' and '+') to their WEB_SAFE equivalents.
This ensures the standard case of WEB_SAFE BASE64 serverKeys and the anomolous case of DEFAULT BASE64 keys both work.
2023-01-02 23:56:52 +13:00
Eugen Rochko
525cc69c70 Merge pull request #486 from mishnz/master
The Mastodon server does not currently use URL_SAFE encoding on its s…
2023-01-01 10:01:17 +01:00
mishnz
7ed1b164b5 The Mastodon server does not currently use URL_SAFE encoding on its serverKey. Using URL_SAFE in this client means the client will crash for any server that uses a key that generates a Mime64 string containing a "+" or "/". This change removes the URL_SAFE logic. See: https://github.com/mastodon/mastodon-android/issues/483 2023-01-01 18:50:09 +13:00
sk
0a9c31fb09 update changelog 2022-12-31 03:13:06 +01:00
sk
5ed6f97846 update changelog 2022-12-31 03:08:08 +01:00
sk
7dc195606c fix empty space when no text 2022-12-31 03:07:14 +01:00
sk
b2377a3353 tweak scroll height/timing 2022-12-31 02:54:33 +01:00
sk
0fdae0c775 Revert "match navigation bar color with toolbar"
This reverts commit 43d334259b.
2022-12-31 02:50:18 +01:00
sk
113bbd960f move settings items 2022-12-31 02:40:49 +01:00
sk
a48e09e77b bump version 2022-12-31 02:02:38 +01:00
sk
3c3f759d9a update readme 2022-12-31 02:02:00 +01:00
sk
5f0986d03b add option to reduce motion 2022-12-31 02:00:40 +01:00
sk
579794d7e0 peek original post before scrolling 2022-12-31 01:52:07 +01:00
sk
4956543eac update changelog 2022-12-31 01:37:39 +01:00
sk
87043f19bc Merge remote-tracking branch 'weblate/main' 2022-12-31 01:35:07 +01:00
sk
375f8ceb27 display original post when replying
closes sk22#193
2022-12-31 01:33:37 +01:00
sk
496ad6a442 change interact with strings 2022-12-30 23:08:04 +01:00
ihor_ck
83a09c4af2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2022-12-30 21:54:40 +00:00
gallegonovato
fac6985d01 Translated using Weblate (Spanish)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-30 21:54:40 +00:00
Linerly
43670ba62b Translated using Weblate (Indonesian)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-30 21:54:40 +00:00
Choukajohn
ef511349f8 Translated using Weblate (French)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-30 21:54:40 +00:00
ihor_ck
eea0199a21 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (121 of 121 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-30 21:54:40 +00:00
Linerly
7e0f02ecc7 Translated using Weblate (Indonesian)
Currently translated at 100.0% (121 of 121 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-30 21:54:40 +00:00
Choukajohn
7b26a65ea0 Translated using Weblate (French)
Currently translated at 100.0% (121 of 121 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-30 21:54:40 +00:00
gallegonovato
c5b92d7162 Translated using Weblate (Spanish)
Currently translated at 100.0% (121 of 121 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-30 21:54:40 +00:00
bubblineyuri
f8387f0a81 Translated using Weblate (German)
Currently translated at 100.0% (12 of 12 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2022-12-30 21:54:40 +00:00
bubblineyuri
8486326b00 Translated using Weblate (German)
Currently translated at 100.0% (121 of 121 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-30 21:54:40 +00:00
edxkl
8f64747e75 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-30 21:54:40 +00:00
ihor_ck
f75efdaa03 Translated using Weblate (Ukrainian)
Currently translated at 96.6% (115 of 119 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-30 21:54:40 +00:00
Linerly
ee8d9d0c07 Translated using Weblate (Indonesian)
Currently translated at 100.0% (119 of 119 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-30 21:54:40 +00:00
ling0412
6791adef46 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (119 of 119 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2022-12-30 21:54:40 +00:00
irure
80bcb84acf Translated using Weblate (Basque)
Currently translated at 18.1% (2 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/eu/
2022-12-30 21:54:40 +00:00
AiOO
7d6b0f9ca8 Translated using Weblate (Korean)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-30 21:54:39 +00:00
nkufideal
594f6d4fc5 Translated using Weblate (Russian)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2022-12-30 21:54:39 +00:00
nkufideal
e40acb9bf6 Translated using Weblate (Russian)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2022-12-30 21:54:39 +00:00
itslameni
e372871108 Translated using Weblate (Russian)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2022-12-30 21:54:39 +00:00
edxkl
1c01469a3e Translated using Weblate (Portuguese (Brazil))
Currently translated at 80.3% (82 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-30 21:54:39 +00:00
irure
90c2e45be2 Translated using Weblate (Basque)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2022-12-30 21:54:39 +00:00
AiOO
1a783d4faf Translated using Weblate (Korean)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-30 21:54:39 +00:00
edxkl
d2944983a4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-30 21:54:39 +00:00
ihor_ck
26459eecb0 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-30 21:54:39 +00:00
Linerly
90dea16222 Translated using Weblate (Indonesian)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-30 21:54:39 +00:00
Choukajohn
8897a326b3 Translated using Weblate (French)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-30 21:54:39 +00:00
gallegonovato
f3e69ddef1 Translated using Weblate (Spanish)
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-30 21:54:39 +00:00
ling0412
8ecaa2c4d1 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (102 of 102 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2022-12-30 21:54:39 +00:00
sk
3a607a81f6 add compose fab to drafts list 2022-12-30 22:54:07 +01:00
sk
4b113e4a82 handle recursive compose/drafts list 2022-12-30 22:34:41 +01:00
sk
3e0e0c1484 move and refine scheduling and drafting 2022-12-30 21:48:59 +01:00
sk
676e166459 move compose action to layout file 2022-12-30 19:24:30 +01:00
sk
f0a704b93b schedule/draft in overflow menu 2022-12-29 20:24:37 +01:00
sk
cfc528df9a Merge remote-tracking branch 'origin/main' 2022-12-29 20:12:31 +01:00
sk
9231ea1446 offer to save when scheduledAt changed
closes sk22#218
2022-12-29 20:12:08 +01:00
sk22
f2f9138435 Update README.md 2022-12-29 18:39:32 +01:00
sk
624700497b update changelog 2022-12-29 18:28:24 +01:00
sk
5794a64da6 use rules fragment in settings 2022-12-29 18:27:37 +01:00
sk
7e6e9d3dcd move translation availability
closes sk22#213
2022-12-29 18:14:26 +01:00
sk
07634edfa3 don't finish compose fragment 2022-12-29 18:14:00 +01:00
sk
4a03fbfbf0 update changelog, bump version 2022-12-29 18:01:50 +01:00
sk
000cdb08ec change fab styles
closes sk22#211
2022-12-29 18:01:22 +01:00
sk
e0521b3c95 add mention with quasi-quoting 2022-12-29 17:14:38 +01:00
sk22
9547be89e1 Drafts and scheduled posts (#217)
closes #100
closes #59 

* enable saving as draft (scheduled)
* add scheduled posts list
* fix NoSuchMethodError
* editable drafts/scheduled posts
* ui for drafts
* use instants between 9999-01-01 and 9999-12-31
* use save and draft strings
* map scheduled status params to status
* implement scheduling posts
* improve save/discard draft dialog
* persist scheduled date in state
* add unsent posts button to toolbar
* clean up imports
2022-12-29 16:53:18 +01:00
sk
40d44269fc Merge branch 'main' of github.com:sk22/megalodon 2022-12-29 16:46:14 +01:00
sk
3bf0903453 fix toolbar inset not applying in true black 2022-12-29 16:46:10 +01:00
Thiago 'Jedi' Abreu
c3abf8c05c Better handling of filter expiration date (#212)
* Better handling of filter expiration date
* Simplify Thread and Home Timeline filtering
2022-12-29 13:32:22 +01:00
Thiago 'Jedi' Abreu
6220ce6780 Implement 4.0 filters with hide action (#202)
* adding new "filtered" field for status
* respect "hide" filter action on status
* handling expire date for filter

closes #161
2022-12-28 14:49:45 +01:00
sk
6107698a76 optionally forward report
closes #205
2022-12-28 14:45:20 +01:00
sk
a3c3fec9b4 add icon indicating the existence of replies
closes #207
2022-12-28 14:13:49 +01:00
sk
f3a9b19104 replace mute icon 2022-12-28 01:58:44 +01:00
sk
d9ed6f600b change animation duration 2022-12-28 01:39:06 +01:00
sk
8a6d86727c remove unused menu item 2022-12-28 01:35:53 +01:00
sk
d9abf82918 fix null pointer on loading profile 2022-12-28 01:35:04 +01:00
sk
3cd9020ee0 use short usernames in popup menus
improves upon mastodon#148
2022-12-28 00:58:57 +01:00
sk
6d22a4d014 icons. icons everywhere 2022-12-28 00:53:06 +01:00
sk
ccad5d40ec fix akkoma crash on edit 2022-12-27 22:00:19 +01:00
ihor_ck
5b7b022d9f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2022-12-27 20:46:35 +00:00
Andrewblasco
387139b5d3 Translated using Weblate (Spanish)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-27 20:46:35 +00:00
edxkl
0ae10d5fbe Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-27 20:46:35 +00:00
ihor_ck
d53397d8f8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-27 20:46:35 +00:00
sk
b1006d2a14 rename string 2022-12-27 21:46:21 +01:00
sk
c5cf318cdd Merge remote-tracking branch 'weblate/main' 2022-12-27 21:45:01 +01:00
sk
671338c16a different icon for delete notifs setting 2022-12-27 21:41:08 +01:00
sk
bbaa70e396 add option to use uniform notif icon 2022-12-27 21:39:41 +01:00
sk
536d6cf63e revert broken color attribute for notif icon
closes #190
2022-12-27 21:30:35 +01:00
sk
b564a297ab fix #200 2022-12-27 21:20:20 +01:00
sk
6d34ae1a50 long-click to compose from other account 2022-12-27 21:02:05 +01:00
sk
0d2457f39e restore accidentally deleted functionality 2022-12-27 20:43:29 +01:00
sk
420505328c fix default visibility crashing akkoma session
closes #196
2022-12-27 20:36:06 +01:00
sk
0e60d71006 refine long-clicks
and disable long-click for multiple accounts when logged in to single account
2022-12-27 20:30:58 +01:00
sk
0f1456819b interact as other accounts
closes #199
2022-12-27 19:53:01 +01:00
sk
3af89a6175 update readme 2022-12-27 13:32:23 +01:00
gallegonovato
2fac871493 Translated using Weblate (Spanish)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-26 09:34:47 +00:00
Pointifurry
0166133b61 Translated using Weblate (Spanish)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-26 09:34:46 +00:00
Linerly
a9e0911796 Translated using Weblate (Indonesian)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-26 09:34:46 +00:00
ling0412
213f341257 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/zh_Hans/
2022-12-26 09:34:46 +00:00
Choukajohn
01cc2a2c67 Translated using Weblate (French)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-26 09:34:46 +00:00
nitrogenez
6c7a040c02 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-26 09:34:46 +00:00
itslameni
4e40944b26 Translated using Weblate (Russian)
Currently translated at 96.7% (88 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2022-12-26 09:34:46 +00:00
goliv
af859438b4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 74.7% (68 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-26 09:34:46 +00:00
Linerly
7ef80e87b8 Translated using Weblate (Indonesian)
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-26 09:34:45 +00:00
Choukajohn
f8e873cd78 Translated using Weblate (French)
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-26 09:34:45 +00:00
Pointifurry
5cc97f7cf1 Translated using Weblate (Spanish)
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-26 09:34:45 +00:00
ling0412
44c56331fd Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2022-12-26 09:34:45 +00:00
sk22
1272c3962e Translated using Weblate (German)
Currently translated at 100.0% (91 of 91 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-26 09:34:45 +00:00
sk
e2799fcdff fix metadata markdown 2022-12-23 23:58:59 +01:00
sk
8e4f402e21 update changelogs 2022-12-23 23:48:21 +01:00
sk
10d2949647 remove unused method 2022-12-23 23:43:19 +01:00
sk
30ef23308b bump version 2022-12-23 23:41:46 +01:00
sk
564132ee82 update changelog 2022-12-23 23:40:50 +01:00
sk
1e527e87df fix default reblog visibility 2022-12-23 23:39:51 +01:00
sk
9692a04275 Merge remote-tracking branch 'weblate/main' 2022-12-23 23:36:48 +01:00
Linerly
6ece8eb0c1 Translated using Weblate (Indonesian)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-23 22:18:14 +00:00
Choukajohn
1f33237e8a Translated using Weblate (French)
Currently translated at 100.0% (11 of 11 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-23 22:18:14 +00:00
Linerly
9209508aac Translated using Weblate (Indonesian)
Currently translated at 100.0% (89 of 89 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-23 22:18:14 +00:00
Choukajohn
f750e6ff7e Translated using Weblate (French)
Currently translated at 100.0% (89 of 89 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-23 22:18:14 +00:00
sk
f2eecf774b disable block domain from post 2022-12-23 22:59:06 +01:00
sk
98de4e75e0 implement open with other account as submenu 2022-12-23 22:56:18 +01:00
sk
459e32caf8 fix instance info v2 never getting saved 2022-12-23 21:49:21 +01:00
sk
c4ad325e5c improve settings items 2022-12-23 21:35:16 +01:00
sk
f55bd6d6cd truncate publish button 2022-12-23 21:16:36 +01:00
sk
f1ce700c93 add option to open post with other account
closes #182
2022-12-23 21:11:22 +01:00
nitrogenez
c18e1e8456 Translated using Weblate (Ukrainian)
Currently translated at 90.0% (9 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2022-12-23 19:22:28 +00:00
ling0412
1fcd1924c3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/zh_Hans/
2022-12-23 19:22:28 +00:00
Choukajohn
a1767f0425 Translated using Weblate (French)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-23 19:22:28 +00:00
nitrogenez
44d95ca25f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (86 of 86 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-23 19:22:28 +00:00
Linerly
7432540c29 Translated using Weblate (Indonesian)
Currently translated at 100.0% (86 of 86 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-23 19:22:28 +00:00
Choukajohn
c289f58351 Translated using Weblate (French)
Currently translated at 100.0% (86 of 86 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-23 19:22:28 +00:00
gallegonovato
711e041ff5 Translated using Weblate (Spanish)
Currently translated at 100.0% (86 of 86 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-23 19:22:28 +00:00
ling0412
0ac3534585 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (86 of 86 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2022-12-23 19:22:27 +00:00
benjaminwolkchen
57821e0860 Translated using Weblate (German)
Currently translated at 98.8% (85 of 86 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-23 19:22:27 +00:00
sk
0dae798c9a add option to open post with other account
closes #182
2022-12-23 20:17:54 +01:00
sk
732e780fd9 Merge remote-tracking branch 'weblate/main' 2022-12-23 18:54:20 +01:00
sk
5577124b7a use popup background color for dialogs 2022-12-23 18:38:16 +01:00
sk
81b82c75a2 add copy link item and change copyText
use haptic feedback instead of vibrator
2022-12-23 18:10:08 +01:00
sk
b32e322749 implement long-click to copy links
closes sk22#84
2022-12-23 17:51:06 +01:00
sk
3031cc4561 remove selectable background for username
closes sk22#187
2022-12-23 17:22:17 +01:00
sk
d60abc648c only show boost visibility for own posts 2022-12-23 17:11:29 +01:00
sk
a9a0233bb3 Merge branch 'clickable-boost-reply-line' 2022-12-23 16:52:04 +01:00
sk
f6fa9e5122 remove selectable background 2022-12-23 16:51:13 +01:00
sk
29b4f7c91a update changelog 2022-12-22 16:51:50 +01:00
sk
0a9ee57233 implement followed hashtags list
closes sk22/megalodon#162
2022-12-22 16:51:43 +01:00
AiOO
94b69a9c1c Translated using Weblate (Korean)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-22 14:59:36 +00:00
gallegonovato
f0209dd1cc Translated using Weblate (Spanish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-22 14:59:36 +00:00
Linerly
366e432c18 Translated using Weblate (Indonesian)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-22 14:59:36 +00:00
Christian Elbrianno
0075c0e779 Translated using Weblate (Indonesian)
Currently translated at 100.0% (83 of 83 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-22 14:59:36 +00:00
Linerly
d99dfd4185 Translated using Weblate (Indonesian)
Currently translated at 100.0% (83 of 83 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-22 14:59:36 +00:00
Choukajohn
0309b3ad25 Translated using Weblate (French)
Currently translated at 100.0% (83 of 83 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-22 14:59:36 +00:00
gallegonovato
7a85532b73 Translated using Weblate (Spanish)
Currently translated at 100.0% (83 of 83 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-22 14:59:36 +00:00
AiOO
7299d947f7 Translated using Weblate (Korean)
Currently translated at 100.0% (83 of 83 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-22 14:59:35 +00:00
braydofficial
adec7b28f1 Translated using Weblate (German)
Currently translated at 100.0% (83 of 83 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-22 14:59:35 +00:00
sk
c2563da056 Merge branch 'feature/open-urls-in-app' 2022-12-22 15:35:53 +01:00
sk
64b9e53916 add missing fedi url format 2022-12-22 15:35:26 +01:00
sk
86ab6f7b3d implement setting boost visibility 2022-12-22 15:03:42 +01:00
sk
ed02733524 disable boost button if disabled
closes #180
2022-12-22 11:27:24 +01:00
sk
a99af63f34 Merge branch 'feature/open-urls-in-app' 2022-12-22 11:14:03 +01:00
sk
1d900a66fe try to open link previews in app 2022-12-22 11:13:50 +01:00
sk
f29acc217d update changelog 2022-12-22 01:37:52 +01:00
sk
f60164f5c5 bump version 2022-12-22 01:30:41 +01:00
sk
578cf1f00d update readme 2022-12-22 01:29:28 +01:00
sk
bca3bc6b4a Merge branch 'feature/more-html-tags' 2022-12-22 01:28:21 +01:00
sk
352c813544 smaller space between paragraphs 2022-12-22 01:27:55 +01:00
sk
7d876bddc7 preserve whitespaces in html 2022-12-22 01:25:43 +01:00
sk
43d334259b match navigation bar color with toolbar 2022-12-22 01:09:46 +01:00
sk
750579b1c2 use color attributes instead of fixed colors 2022-12-22 00:57:12 +01:00
sk
d69221d85b fix media upload colors 2022-12-22 00:50:23 +01:00
sk
a1c80e92cd reset state on boost long click 2022-12-22 00:47:44 +01:00
sk
ce1a0d66f1 update changelog 2022-12-22 00:14:59 +01:00
sk
f28057d620 update changelog 2022-12-22 00:08:37 +01:00
sk
8f6dc7e6d2 update changelog 2022-12-22 00:05:19 +01:00
sk
b25a237c20 add long-click to "quote" 2022-12-22 00:01:51 +01:00
sk
ccb0b59e17 Merge branch 'feature/open-urls-in-app' 2022-12-21 23:50:14 +01:00
sk
14658a2d70 only perform fedi lookup if looks like fedi url 2022-12-21 23:45:27 +01:00
sk
5f26878c06 resolve fediverse links in app
closes sk22#177
closes sk22#96
2022-12-21 23:29:16 +01:00
sk
df78ae59fe Merge remote-tracking branch 'weblate/main' 2022-12-21 22:39:19 +01:00
Choukajohn
47924dfb61 Translated using Weblate (French)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-21 21:37:59 +00:00
Choukajohn
3eb442e0f6 Translated using Weblate (French)
Currently translated at 100.0% (82 of 82 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-21 21:37:59 +00:00
sk
b309fc09f6 tweak item header and notification deletion 2022-12-21 22:37:30 +01:00
gallegonovato
a00fe0485b Translated using Weblate (Spanish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-21 19:21:44 +00:00
sk22
a60f65857b Translated using Weblate (Spanish)
Currently translated at 98.7% (81 of 82 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-21 19:21:44 +00:00
gallegonovato
fe584b58b0 Translated using Weblate (Spanish)
Currently translated at 98.7% (81 of 82 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-21 19:21:44 +00:00
sk22
91ad2bf66b Translated using Weblate (German)
Currently translated at 100.0% (82 of 82 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-21 19:21:44 +00:00
sk22
01988a9435 Translated using Weblate (English)
Currently translated at 100.0% (82 of 82 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2022-12-21 19:21:44 +00:00
sk
51bc8e1b2c use instance domain if title blank 2022-12-21 19:57:31 +01:00
sk
b28c684bd3 fix missing text in notification 2022-12-21 19:54:15 +01:00
sk
42b2cde1e2 use UiUtils.getThemeColor 2022-12-21 19:48:44 +01:00
sk
199a7b816c Merge remote-tracking branch 'weblate/main' 2022-12-21 18:20:08 +01:00
sk22
2b8fc6764e Translated using Weblate (German)
Currently translated at 100.0% (80 of 80 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-21 17:18:57 +00:00
sk22
37f93cda4d Translated using Weblate (English)
Currently translated at 100.0% (80 of 80 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2022-12-21 17:18:57 +00:00
sk
4114f5b3c2 update changelog 2022-12-21 18:18:03 +01:00
Florian Obernberger
14d45eb759 Custom icons for different types of notifications (#178)
* Add filled variant of the person_add icon
* Add mention icon
* Add custom icons for different notification types

Co-authored-by: sk22 <sk22@mailbox.org>
2022-12-21 18:13:08 +01:00
sk
0dfa9d2c2c Merge branch 'use-fluent-mention-icon' 2022-12-21 18:09:41 +01:00
sk
6fce18ffe8 replace custom symbol with fluent mention symbol 2022-12-21 17:59:38 +01:00
sk
956c56c494 add translation availability info text 2022-12-21 17:54:28 +01:00
gallegonovato
75e7c6a9eb Translated using Weblate (Spanish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-21 16:18:19 +00:00
Choukajohn
a7fb66d269 Translated using Weblate (French)
Currently translated at 100.0% (10 of 10 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-21 16:18:19 +00:00
Choukajohn
5f48802357 Translated using Weblate (French)
Currently translated at 100.0% (70 of 70 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-21 16:18:19 +00:00
gallegonovato
a27488c8da Translated using Weblate (Spanish)
Currently translated at 100.0% (70 of 70 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-21 16:18:19 +00:00
sk
b6dbd7512c no ellipsis for settings items 2022-12-21 16:37:40 +01:00
sk
e41386082c add toggle for hiding translate button 2022-12-21 16:35:47 +01:00
sk
ae385c139b animate translate button opacity 2022-12-21 16:23:09 +01:00
LucasGGamerM
dd2f213a4f lower opacity of button while translating 2022-12-21 16:18:28 +01:00
sk
35f92a6e91 fix icons not showing in RTL layout 2022-12-21 16:12:03 +01:00
sk
ab5648a5d6 make toot button customizable 2022-12-21 16:07:47 +01:00
sk
8a9b59c66a generalize color picker settings item 2022-12-21 14:49:38 +01:00
sk
a6e0c877b5 use heart for donation link 2022-12-21 14:36:23 +01:00
sk
de5a623a00 update changelog 2022-12-21 14:34:27 +01:00
sk
b0f9ce081f implement deleting notifications 2022-12-21 14:25:19 +01:00
sk
e17b6e83a4 new light grays 2022-12-21 11:40:07 +01:00
sk
96f4322f74 reuse old brownish gray and move colors 2022-12-21 10:45:40 +01:00
sk
780f59d666 new grays 2022-12-21 10:19:59 +01:00
sk
8c5db2eef5 Merge remote-tracking branch 'upstream/master' 2022-12-21 09:41:29 +01:00
sk
5ab004b87e fix wrong default visibility in popup
closes sk22#174
2022-12-21 09:41:03 +01:00
sk
1b001bdd4f Merge branch 'fix-wrong-visibility-on-edit' 2022-12-21 09:29:57 +01:00
Gregory K
a5fa44213d Merge pull request #474 from sk22/fix-wrong-visibility-on-edit
Only load default status visibility if not editing
2022-12-21 11:25:14 +03:00
sk
68e9d9d91c only load default visibility if not editing
fix mastodon#306
2022-12-21 09:24:09 +01:00
sk
a14783a275 fix action bar buttons color
closes sk22#175
2022-12-21 09:14:36 +01:00
sk
3ce58d2edf move button text/background to styles 2022-12-20 16:06:28 +01:00
sk
523efac4fb make separator color brighter
closes #159
2022-12-20 15:51:00 +01:00
sk
d352aca9cc add toolbar background color 2022-12-20 15:44:37 +01:00
sk
ae6afab01b Merge branch 'feature/animate-buttons' 2022-12-20 15:19:02 +01:00
sk
efea405b83 fire counter updated event for content status
see mastodon#467
closes sk22#173
2022-12-20 15:17:43 +01:00
sk
ad9262cf0f fix counter updates for preloaded data
re: mastodon#467
see fb5289372d
2022-12-20 14:58:27 +01:00
sk
636c268e46 add drag to open to visibility button 2022-12-20 12:58:18 +01:00
sk
06a61f0374 update fastlane descriptions 2022-12-20 12:50:47 +01:00
sk
4ba7763de5 fix fastlane configs 2022-12-20 12:49:01 +01:00
sk
b486542e7b update strings 2022-12-20 12:43:56 +01:00
sk22
f53ce6cbf0 Translated using Weblate (German)
Currently translated at 100.0% (70 of 70 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-20 11:34:43 +00:00
AiOO
b10ff655f1 Translated using Weblate (Korean)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-20 11:34:43 +00:00
jonta
bbc27dbeea Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-20 11:34:43 +00:00
jonta
dadb929afd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (62 of 62 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-20 11:34:43 +00:00
gallegonovato
c0f397cdd5 Translated using Weblate (Spanish)
Currently translated at 100.0% (62 of 62 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-20 11:34:43 +00:00
itslameni
b597cf6e18 Translated using Weblate (Russian)
Currently translated at 37.5% (3 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2022-12-20 11:34:43 +00:00
Linerly
e3bbeb2022 Translated using Weblate (Indonesian)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-20 11:34:43 +00:00
Radiquum
cad9fc8977 Translated using Weblate (Russian)
Currently translated at 100.0% (62 of 62 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2022-12-20 11:34:43 +00:00
Linerly
2f191c1f71 Translated using Weblate (Indonesian)
Currently translated at 100.0% (62 of 62 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-20 11:34:43 +00:00
Choukajohn
dc0debce1a Translated using Weblate (French)
Currently translated at 100.0% (62 of 62 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-20 11:34:43 +00:00
AiOO
d96b6f0100 Translated using Weblate (Korean)
Currently translated at 100.0% (62 of 62 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-20 11:34:42 +00:00
sk
16f1901976 update strings 2022-12-20 12:34:32 +01:00
sk
61d9e4d531 update german 2022-12-20 12:25:59 +01:00
sk
aec4479e19 rename color theme to color palette 2022-12-20 12:23:59 +01:00
sk
ec7235c03a add settings links
closes #163
2022-12-20 12:12:45 +01:00
sk
f3db153ea9 check if server supports translation earlier
closes #172
2022-12-20 11:19:50 +01:00
sk
e1c258478f fix italian 2022-12-20 10:38:54 +01:00
sk
1f2e691eb1 Merge remote-tracking branch 'upstream/master' 2022-12-20 10:27:54 +01:00
sk
be9a3a9975 fix error in readme 2022-12-20 10:27:11 +01:00
sk
8d17ac6f28 simplify themes 2022-12-20 10:26:03 +01:00
Grishka
d9df150cf8 Fix #472 2022-12-20 12:14:56 +03:00
sk
667a4aab1a Merge branch 'main' of github.com:sk22/megalodon 2022-12-19 19:06:04 +01:00
sk
862ffd8172 Merge remote-tracking branch 'upstream/master' 2022-12-19 19:05:36 +01:00
sk
eb1dd954ee merge miui fix for copying text 2022-12-19 19:03:11 +01:00
Grishka
6f2e5a63d7 This is officially the first Xiaomi workaround in this app 🎉
#469
2022-12-19 20:27:56 +03:00
sk
5bf78c5cd2 use primary color for update notification
closes #169
2022-12-19 18:27:03 +01:00
LucasGGamerM
277361a562 merge moshidon's red theme
closes sk22#160
2022-12-19 17:58:16 +01:00
sk
6697d3d0d5 update changelog 2022-12-19 16:38:00 +01:00
sk
7202aae712 Merge branch 'feature/animate-buttons' 2022-12-19 16:34:25 +01:00
sk
6d2c6748f7 set pivot point once 2022-12-19 16:34:16 +01:00
sk
6c98c9ccf2 fix broken long click 2022-12-19 16:33:30 +01:00
sk
afc25ec8b3 Merge branch 'feature/animate-buttons' 2022-12-19 16:06:24 +01:00
sk
6c9553ba65 tweak animations 2022-12-19 16:05:30 +01:00
sk
0fd5ea4689 fix counter updates for preloaded data
re: mastodon#467
see fb5289372d
2022-12-19 16:00:46 +01:00
sk
8441208058 fix bug in bookmark button
closes #167
2022-12-19 15:59:15 +01:00
sk
aa34298771 Merge branch 'feature/animate-buttons' 2022-12-19 15:43:18 +01:00
sk
ccacd88f80 tweak animations 2022-12-19 15:42:32 +01:00
sk
1f20b21fc8 add option to disable swiping
closes sk22#165
2022-12-19 15:31:38 +01:00
sk
ae7152aca7 Merge branch 'feature/long-press-copy-url' 2022-12-19 15:15:03 +01:00
sk
ba36347f03 copy post URL on long click 2022-12-19 15:14:54 +01:00
sk
c0c5e83f31 move copy text to UiUtils 2022-12-19 15:12:37 +01:00
sk
9c05ff2f7c restore toast message for android 13+ 2022-12-19 15:08:13 +01:00
sk
0ada05bf3a add vibration when copying username 2022-12-19 15:06:17 +01:00
sk
c77b5dfac2 bump version 2022-12-17 23:28:56 +01:00
sk
673ea40238 hide material you theme for older versions 2022-12-17 23:22:51 +01:00
sk
f7ced7f253 Merge branch 'feature/animate-buttons' 2022-12-17 23:19:42 +01:00
sk
6152ec9d0d tweak scaling while animating buttons 2022-12-17 23:19:36 +01:00
sk
7ed8bb259d Merge branch 'feature/animate-buttons' 2022-12-17 23:12:16 +01:00
sk
06882d5bea change button animations 2022-12-17 23:07:36 +01:00
sk
f460456502 add missing night variant for red 2022-12-17 22:30:15 +01:00
sk
6ef9f2ff15 update changelog 2022-12-17 22:08:39 +01:00
sk
062af9937f update changelog 2022-12-17 21:59:22 +01:00
sk
452ee8e1a5 update readme, bump version 2022-12-17 21:49:23 +01:00
sk
88c62427aa Merge remote-tracking branch 'weblate/main' 2022-12-17 21:46:52 +01:00
gallegonovato
09458c5ecb Translated using Weblate (Spanish)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-17 20:46:15 +00:00
Choukajohn
4171a5d210 Translated using Weblate (French)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-17 20:46:15 +00:00
tippete
1362a03877 Translated using Weblate (Italian)
Currently translated at 100.0% (60 of 60 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2022-12-17 20:46:15 +00:00
Choukajohn
34ae099b89 Translated using Weblate (French)
Currently translated at 100.0% (60 of 60 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-17 20:46:14 +00:00
gallegonovato
679bd4588f Translated using Weblate (Spanish)
Currently translated at 100.0% (60 of 60 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-17 20:46:14 +00:00
sk
7d4c69bc82 tweak gray colors 2022-12-17 21:36:19 +01:00
sk
1749fcacb1 fix text view cutting off text
closes #157
2022-12-17 21:16:35 +01:00
sk
683f87cc19 Merge branch 'feature/lists' 2022-12-17 21:13:23 +01:00
sk
2ef19be3c7 add missing lists with handling
fix #158
2022-12-17 21:11:48 +01:00
sk
fb5289372d fix updating wrong status when interacting with reblog
see mastodon#467
2022-12-17 21:01:10 +01:00
sk
f8d9d00dac Merge branch 'feature/animate-buttons' 2022-12-17 19:56:24 +01:00
sk
a7c707f62e animate footer icons
closes sk22#154
2022-12-17 19:48:20 +01:00
sk
336ebb71cf Merge branch 'feature/follow-requests' 2022-12-17 16:35:53 +01:00
sk
a5f98f5c50 fix follow request list issues
closes #153
2022-12-17 16:35:41 +01:00
sk
9d5d4b7957 make red theme less orange 2022-12-17 15:47:04 +01:00
LucasGGamerM
3626da7362 custom, darker grays for everyone 2022-12-17 15:41:42 +01:00
sk
400e340859 Merge branch 'fix-toolbar-styles-api-24' 2022-12-17 14:58:09 +01:00
sk
31cad1efbe move api 24 styles into extra styles.xml 2022-12-17 14:56:26 +01:00
sk
e5da24a44d add red theme 2022-12-16 14:41:53 +01:00
sk
d63e5af8d0 use custom instead of app name 2022-12-16 14:21:54 +01:00
sk
abdce64b99 for pink shall remain the default
also, save color name as a string
2022-12-16 14:00:43 +01:00
kaea
d5696684fa Translated using Weblate (Polish)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-16 12:39:36 +00:00
itslameni
d168794d4e Translated using Weblate (Russian)
Currently translated at 37.5% (3 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2022-12-16 12:39:36 +00:00
itslameni
52c5057e85 Translated using Weblate (Russian)
Currently translated at 89.8% (53 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2022-12-16 12:39:36 +00:00
tippete
21167f64c9 Translated using Weblate (Italian)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2022-12-16 12:39:36 +00:00
AiOO
26343ce10b Translated using Weblate (Korean)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-16 12:39:36 +00:00
nitrogenez
238d930c48 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-16 12:39:36 +00:00
jonta
87ade4a020 Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.2% (55 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-16 12:39:36 +00:00
kaea
db9bb58b3c Translated using Weblate (Polish)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-16 12:39:36 +00:00
Choukajohn
99cbc8f071 Translated using Weblate (French)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-16 12:39:36 +00:00
AiOO
d2a4ae8f59 Translated using Weblate (Korean)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-16 12:39:36 +00:00
sk
9a47530ab8 Merge remote-tracking branch 'upstream/master' 2022-12-16 02:52:55 +01:00
sk
ed1d9165e1 use default posting language from server 2022-12-16 02:14:06 +01:00
sk
ef421dd5dd set material3 theme as default 2022-12-16 02:02:48 +01:00
sk
acbf27f025 add button styles for each theme 2022-12-16 01:33:28 +01:00
sk
f54e2375be material you and true black improvements 2022-12-16 01:20:39 +01:00
sk
1a66db065f fix wrong button colors 2022-12-16 01:16:45 +01:00
sk
c51b2bb2e7 add m3 colors to colors.xml for compatibility 2022-12-16 00:24:04 +01:00
sk
4de3da09b3 introduce dedicated button colors 2022-12-16 00:13:01 +01:00
Grishka
e0febda372 Minor fixes 2022-12-15 20:16:32 +03:00
sk
516f97e679 improve material you colors 2022-12-15 18:03:06 +01:00
Grishka
069d141451 Fix crash in ComposeFragment::onSaveInstanceState in release builds
fixes #452, fixes #453, fixes #457
2022-12-15 20:02:26 +03:00
Grishka
166401ea18 Signup flow redesign 2022-12-15 19:41:38 +03:00
sk
55e5c03b5f add missing string 2022-12-15 17:03:24 +01:00
sk
c950b6e6c1 simplify code 2022-12-15 17:03:17 +01:00
LucasGGamerM
2dc884b1bb Making material you setting work fine. Its ready for release 2022-12-15 16:44:16 +01:00
LucasGGamerM
c49660950d Adding the color things 2022-12-15 16:37:31 +01:00
sk
9162908173 Merge branch 'more-distinct-filled-boost-icon' 2022-12-15 16:18:42 +01:00
sk
2789169dd7 slightly more padding for fill 2022-12-15 16:18:21 +01:00
sk
0728b00381 Merge branch 'more-distinct-filled-boost-icon' 2022-12-13 15:45:30 +01:00
sk
34b82337b1 add distinct filled boost icon 2022-12-13 15:45:19 +01:00
sk
f25d4e4d44 update screenshots 2022-12-13 12:04:34 +01:00
sk
ac3176c0d8 Merge branch 'external-share-include-subject' 2022-12-13 09:18:42 +01:00
sk
021fc9e5a0 add empty line after subject
closes #149
2022-12-13 09:18:18 +01:00
sk
a48c11332c Merge branch 'feature/translate-button' 2022-12-13 09:15:34 +01:00
sk
93bccc02bf add missing language null check
fix #143
2022-12-13 09:15:15 +01:00
sk
7a594be3f2 update metadata 2022-12-13 00:03:37 +01:00
sk
c9f4df3d4e bump version, update changelog 2022-12-12 23:35:54 +01:00
sk22
9078667d51 Translated using Weblate (German)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-12 22:29:04 +00:00
sk
7569e1aef6 add strings back 2022-12-12 23:26:52 +01:00
nitrogenez
723983dadf Translated using Weblate (Ukrainian)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2022-12-12 22:25:44 +00:00
lunarna
f87e020abd Translated using Weblate (Polish)
Currently translated at 25.0% (2 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2022-12-12 22:25:44 +00:00
AiOO
fb5729d5cc Translated using Weblate (Korean)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-12 22:25:44 +00:00
Adolfo Jayme Barrientos
2ff6c53d6d Translated using Weblate (Spanish)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-12 22:25:44 +00:00
edxkl
cfc6895711 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-12 22:25:44 +00:00
Choukajohn
1c27fc68ee Translated using Weblate (French)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-12 22:25:44 +00:00
nitrogenez
df0d578573 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-12 22:25:44 +00:00
edxkl
2fa3c69af1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.4% (54 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-12 22:25:44 +00:00
lunarna
095bf92fed Translated using Weblate (Polish)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-12 22:25:44 +00:00
Choukajohn
debe017f12 Translated using Weblate (French)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-12 22:25:44 +00:00
Adolfo Jayme Barrientos
f956e12167 Translated using Weblate (Spanish)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:44 +00:00
AiOO
2c50c38d82 Translated using Weblate (Korean)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-12 22:25:44 +00:00
sk22
b4980101ad Translated using Weblate (German)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-12 22:25:44 +00:00
sk22
8395fca60f Translated using Weblate (English)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2022-12-12 22:25:44 +00:00
AiOO
b22e7d277f Translated using Weblate (Korean)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-12 22:25:44 +00:00
edxkl
c0e67593ee Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-12 22:25:44 +00:00
edxkl
5dc4235724 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.8% (46 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-12 22:25:43 +00:00
kaea
f77caeefae Translated using Weblate (Polish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-12 22:25:43 +00:00
Adolfo Jayme Barrientos
c1ef23bbe8 Translated using Weblate (Spanish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:43 +00:00
plutonemhikari
e7e80bcf7d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2022-12-12 22:25:43 +00:00
AiOO
c27f5aaf30 Translated using Weblate (Korean)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-12 22:25:43 +00:00
gallegonovato
d52728f22e Translated using Weblate (Spanish)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-12 22:25:43 +00:00
Christian Elbrianno
3c7c962320 Translated using Weblate (Indonesian)
Currently translated at 71.4% (5 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-12 22:25:43 +00:00
Choukajohn
abf570d177 Translated using Weblate (French)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-12 22:25:43 +00:00
edxkl
46422cd62d Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.6% (44 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-12 22:25:43 +00:00
tippete
f1ffa2629e Translated using Weblate (Italian)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2022-12-12 22:25:43 +00:00
Christian Elbrianno
2074f3c33b Translated using Weblate (Indonesian)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-12 22:25:43 +00:00
Choukajohn
7c51803674 Translated using Weblate (French)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-12 22:25:43 +00:00
Adolfo Jayme Barrientos
6d80c62f30 Translated using Weblate (Spanish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:43 +00:00
gallegonovato
64907a7e1c Translated using Weblate (Spanish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:43 +00:00
ca
17922ca1d5 Translated using Weblate (Catalan)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2022-12-12 22:25:43 +00:00
sk
01ac219854 remove strings 2022-12-12 23:25:31 +01:00
sk
9bbf8c4618 add custom login fragment 2022-12-12 23:18:01 +01:00
sk
978beaec77 use system default language for translation
fix #144
2022-12-12 09:09:45 +01:00
sk
0950e2eb7f Merge branch 'better-poll-voting' 2022-12-10 22:40:46 +01:00
sk
116328adb9 hide icons in own polls
closes #137
2022-12-10 22:40:35 +01:00
sk
32a2c66c34 Merge branch 'feature/language-selector' 2022-12-10 22:30:25 +01:00
sk
661f545e35 Merge branch 'feature/language-selector' 2022-12-10 22:24:05 +01:00
sk
d1e0cd3c20 Merge branch 'feature/display-reply-visibility' 2022-12-10 17:55:41 +01:00
sk
db16dde073 fix wrong visibility in reply
fix #140
2022-12-10 17:55:29 +01:00
sk
b3fe44bc08 update push settings on app start
fix #138, hopefully
2022-12-10 17:37:09 +01:00
sk
e5fab4a555 update changelog, bump version 2022-12-09 21:25:24 +01:00
sk
abe28179ec use saved default status visibility 2022-12-09 21:23:20 +01:00
sk
60d4e4d396 use default posting language 2022-12-09 21:15:11 +01:00
sk
435e73d718 Merge branch 'feature/language-selector' 2022-12-09 20:56:09 +01:00
sk
8714b24388 bump version 2022-12-09 03:15:01 +01:00
sk
495db142d7 update readme 2022-12-09 03:14:11 +01:00
sk
ac5d11159f Merge branch 'feature/translate-button' 2022-12-09 03:05:59 +01:00
sk
d1479f142b add progress spinner 2022-12-09 03:05:17 +01:00
sk
ee6ec631e8 Merge branch 'feature/translate-button' 2022-12-09 02:46:55 +01:00
sk
dee21222a7 implement translate feature 2022-12-09 02:37:38 +01:00
sk
cd8123ca34 Merge remote-tracking branch 'upstream/master' 2022-12-08 21:41:38 +01:00
sk
ceb08ea78d fix get started button color 2022-12-08 21:36:50 +01:00
sk
cac5b554e2 Merge remote-tracking branch 'upstream/master' 2022-12-08 21:02:45 +01:00
sk
c4adbc8e45 update changelog/readme 2022-12-08 21:02:06 +01:00
sk
bb01077c3b Merge branch 'feature/mark-media-as-sensitive' 2022-12-08 21:00:43 +01:00
sk
b370fcda6d add bottom margin to sensitive toggle 2022-12-08 21:00:30 +01:00
sk
d364ebbb2f Merge branch 'better-poll-voting' 2022-12-08 20:56:19 +01:00
sk
5b28468efd add option to allow multiple poll choices 2022-12-08 20:53:34 +01:00
sk
6fd58c9682 improve semantics for poll options 2022-12-08 19:56:04 +01:00
sk
b580743619 fix poll option displaying wrong own vote
fixes #132
2022-12-08 16:03:46 +01:00
sk
4a9cb9f2dc fix poll option displaying wrong own vote
fixes #132
2022-12-08 15:53:35 +01:00
Poussinou
0dcdda75be fix typo in README 2022-12-08 12:45:28 +09:30
sk22
145f55817f Translated using Weblate (German)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2022-12-07 18:20:46 +00:00
sk
79025c2f36 update description 2022-12-07 19:19:05 +01:00
sk
2515a8d381 add missing item to changelog 2022-12-07 19:16:14 +01:00
sk22
ede7ece25a Translated using Weblate (German)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2022-12-07 18:11:14 +00:00
sk22
2db39f8c66 Translated using Weblate (German)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-07 18:11:13 +00:00
sk
5f0382456f remove upstream fastlane changes 2022-12-07 19:09:13 +01:00
sk
63b1b58c4e use dashes instead of asterisks 2022-12-07 19:05:38 +01:00
Poussinou
e9fe4a82df Update README.md 2022-12-04 05:26:19 +09:30
601 changed files with 4973 additions and 3614 deletions

3
.github/FUNDING.yml vendored
View File

@@ -1,8 +1,9 @@
# These are supported funding model platforms
github: LucasGGamerM
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # mastodon
open_collective: # Replace with a single Open Collective username e.g., user1
ko_fi: xsk22
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username e.g., user1

View File

@@ -8,25 +8,35 @@ assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
**To reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Does this happen in the official app?**
Does this issue also occur with the respective upstream release?
(Please test using the respective `upstream-xxxxxx.apk` provided in [Releases](https://github.com/sk22/megalodon/releases) or at least using the current Mastodon version from the Play Store)
> No / Yes
> In case it does, please consider filing an [upstream bug report](https://github.com/mastodon/mastodon-android/issues) instead.
> If this bug is seriously impacting your usage or you think I might want to try to fix it for Megalodon, feel free to still create this issue!
**Screenshots and screen recordings**
If applicable, add screenshots (and screen recordings, if possible) to help explain your problem.
**Version**
Megalodon version: [e.g. v1.1.4+fork.#]
**Additional context**
- Does this issue also occur with the respective upstream release? (Please test using the respective `upstream-xxxxxx.apk` provided in [Releases](https://github.com/sk22/megalodon/releases)) No / Yes (`mastodon#…`)
> In this case, please consider filing an [upstream bug report](https://github.com/mastodon/mastodon-android/issues) instead. If this bug is seriously impacting your usage or you think I might want to try to fix it for Megalodon, feel free to still create this issue!
**Crash log**
If you know your way around Android development tools, please consider attaching a crash log, if possible.

149
README.md
View File

@@ -1,28 +1,25 @@
![MoshidonLogo](mastodon/src/main/res/mipmap-xhdpi/ic_launcher_round.png)
![Pink logo with pink shark](mastodon/src/main/res/mipmap-xhdpi/ic_launcher_round.png)
# Moshidon, the material you mastodon client!
# Megalodon
> A fork of [megalodon](https://github.com/sk22/megalodon) which is a fork of [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly wont ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
[![Translation status](https://translate.codeberg.org/widgets/megalodon/-/svg-badge.svg)](https://translate.codeberg.org/engage/megalodon/)
&nbsp;
[![Download latest release](https://img.shields.io/badge/dynamic/json?color=d92aad&label=Download%20APK&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2Fsk22%2Fmegalodon%2Freleases%2Flatest&style=flat)](https://github.com/sk22/megalodon/releases/latest/download/megalodon.apk)
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
&nbsp;
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
[![Download latest release](https://img.shields.io/badge/dynamic/json?color=282C37&label=download%20apk&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FLucasGGamerM%2Fmoshidon%2Freleases%2Flatest&style=for-the-badge)](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
---
> A fork of the [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly wont ever be implemented, such as the federated timeline, unlisted posting and an image description viewer.
## Key features
### **Material you theme support on Android 12+ devices!**
### **Color themes**
**Allows you to change theme within the app. Supports Purple, pink, green, blue, orange and yellow!**
### **Unlisted posting**
**Allows you to post publicly without having your post show up in trends, hashtags or public timelines (i.e., in the tabs “Local”, “Community” and “Posts”).**
**Allows you to post publicly without having your post show up in trends, hashtags or public timelines (i.e., in the tabs “Community”, “Federated” and “Posts”).**
When posting with Unlisted visibility, your posts will still be publicly accessible in your profile. They will also be shown in peoples Home timelines, but only if they follow you or someone they follow reposted/replied to your post.
When posting with Unlisted visibility, your posts will still be publicly accessible in your profile. They will also be shown in peoples Home timelines, but only if they follow you or someone they follow reblogged/replied to your post.
The Mastodon documentation has some more information about [Unlisted posting](https://docs.joinmastodon.org/user/posting/#unlisted) and [Public timelines](https://docs.joinmastodon.org/user/network/#timelines).
@@ -34,6 +31,12 @@ Despite being one of the main features of federated social media, the Federated
Thats one of the reasons why choosing a small, **well-moderated instance is important**. Instance admins and moderators should always make sure to ban abusive users and stop federating with instances who platform them. On well-moderated instances, the Federated timeline can be a welcoming place to meet new people!
### **Draft and schedule posts**
**Allows for preparing a post and scheduling it to send it automatically at a specific time.**
You can create drafts, edit them, send them manually later or set a scheduled date. Drafts are technically saved as scheduled posts, so you can view and edit them from other apps that support scheduled posts. Scheduled posts are handled by your home instance, so they'll work even if you uninstall Megalodon.
### **Image description viewer**
**Allows you to quickly check whether an image or video has an alternative text attached to it.**
@@ -46,29 +49,71 @@ This is important to **ensure the content youre sharing is as accessible as p
On the Fediverse, its quite common for people to pin posts they want others to read before following them. You can pin/unpin posts yourself by clicking the `⋯` button in the top right corner of your posts.
### **Bookmarks**
**They allow for quickly saving posts and viewing them through the Bookmarks button on the top right of your profile.**
To bookmark a post, press the button between the Favorite and Share buttons on the bottom of the post. Bookmarks are saved privately, so the post authors wont know you saved their post the list of bookmarked posts is only visible to you.
## Installation
**Press the download button above to download the APK. Open the downloaded file on your Android device to install it. Moshidon will automatically notify you about new updates inside the app.**
### IzzyOnDroid
To install this app on your Android device, download the [latest release from GitHub](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk) and open it. You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
[apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk)
Moshidon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)s automatic update checker. Megalodon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
Note that you'll need to add Izzy's F-Droid repository to your F-Droid app first:
[`https://apt.izzysoft.de/fdroid/repo`](https://apt.izzysoft.de/fdroid/repo)
### Google Play Store
[play.google.com/store/apps/details?id=org.joinmastodon.android.sk](https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk)
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
### F-Droid
**[F-Droid.org?](https://f-droid.org)** Not yet, sorry!
If you want, you can help me figure out if something's missing in the [Issue #47: F-Droid.org](https://github.com/sk22/megalodon/issues/47)
### Direct
Press the download button to download the APK. Open the downloaded file on your Android device to install it. Megalodon will automatically notify you about new updates inside the app.
[![Download latest release](https://img.shields.io/badge/dynamic/json?color=d92aad&label=Download%20APK&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2Fsk22%2Fmegalodon%2Freleases%2Flatest&style=flat)](https://github.com/sk22/megalodon/releases/latest/download/megalodon.apk)
You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/sk22/megalodon/releases) page.
Megalodon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)s automatic update checker. Megalodon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
---
## Release variants
All downloads can be found on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
All downloads can be found on the [Releases](https://github.com/sk22/megalodon/releases) page.
**`moshidon.apk`**
**`megalodon.apk`**
Variant with an integrated updater. If you download Megalodon from here (and not from an app store), just download the regular `megalodon.apk`.
**`upstream-1234abc.apk`**
This is an **unmodified version** of the official [Mastodon for Android](https://github.com/mastodon/mastodon-android) app the respective Megalodon release is based on. Should you find any bugs in Megalodon (which you will), try to see if it occurs with this variant, too. The last 7 digits of the file name are important to know which version of the official app you're using.
<!-- **`megalodon-fdroid.apk`**
Variant without the integrated updater. This is the variant to be published to F-Droid.org where an integrated updater is not necessary. -->
---
## Contribution
### Translation
As with the source code, the translation is sourced from the official project, which you can contribute to on the official “**Mastodon for Android**” Crowdin project: https://crowdin.com/project/mastodon-for-android
There's also a handful of custom strings exclusive to this projects that would need to be translated. You can help translate **Megalodon** on Weblate: https://translate.codeberg.org/projects/megalodon/
[![Translation status](https://translate.codeberg.org/widgets/megalodon/-/horizontal-auto.svg)](https://translate.codeberg.org/engage/megalodon/)
Variant with an integrated updater. If you download Moshidon from here (and not from an app store), just download the regular `moshidon.apk`.
---
@@ -79,19 +124,14 @@ Variant with an integrated updater. If you download Moshidon from here (and not
* [Add “Unlisted” as a post visibility option](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/enable-unlisted)
([Pull request](https://github.com/mastodon/mastodon-android/pull/103))
* Adding a useful private profile note box!*
* Auto hiding the compose button on scroll!*
* Adding the hability to remind yourself to add alt text to images!*
* Adding the ability to have drafts!*
* Also adding the ability to view announcements from your instance!*
* Adding the ability to post for local timeline only (Only on instances that support it!)*
* [Add “Federation” tab and change Discover tab order](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/add-federated-timeline) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/8))
* [Add image description button and viewer](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
* [Implement pinning posts and displaying pinned posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/pin-posts) ([Pull request](https://github.com/mastodon/mastodon-android/pull/140))
* [Implement deleting and re-drafting](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/delete-redraft) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/21))
* [Implement a bookmark button and list](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/bookmarks) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/22))
* [Add “Check for update” button in addition to integrated update checker](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/check-for-update-button)
* [Add “Mark media as sensitive” option](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/mark-media-as-sensitive)
* [Add settings to hide replies and reposts from the timeline](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/filter-home-timeline) ([Pull request](https://github.com/mastodon/mastodon-android/pull/317))
* [Add settings to hide replies and reblogs from the timeline](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/filter-home-timeline) ([Pull request](https://github.com/mastodon/mastodon-android/pull/317))
* [Follow and unfollow hashtags](https://github.com/sk22/megalodon/commit/7d38f031f197aa6cefaf53e39d929538689c1e4e) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/233))
* [Notification bell for posts](https://github.com/sk22/megalodon/commit/b166ca705eb9169025ef32bbe6315b42491b57ea) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/81))
* [Viewing lists and adding/removing users from lists](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:list-timeline-views) based on [@obstsalatschuessel](https://github.com/obstsalatschuessel)'s [Pull request](https://github.com/mastodon/mastodon-android/pull/286)
@@ -101,12 +141,23 @@ Variant with an integrated updater. If you download Moshidon from here (and not
* [Add notifications tab for posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/posts-notifications-tab)
* [Show visibility of original post when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-reply-visibility)
* [Clickable reply/boost line above posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:clickable-boost-reply-line)
* [Clickable reply line while replying to open original post](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/clickable-reply-line-compose)
* [Add push notification setting for post notifications](https://github.com/sk22/megalodon/commit/b190480d7739be47f23543d9e7644660f9b4b4ee)
* [Add option to allow voting for multiple options on polls](https://github.com/sk22/megalodon/commit/5b28468efd49387b4f8b83f142f3adf3104ca60c)
* [Add translate function](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/translate-button)
* [Add language selector](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/language-selector)
* [Implement deleting notifications](https://github.com/sk22/megalodon/commit/b0f9ce081f69f29ad59658fc00ca41372cd2677d) (disabled by default)
* [Long-click boost button to "quote" a post](https://github.com/sk22/megalodon/commit/b25a237c20c6a924ed4d9b357999867c3a32b32b)
* [Draft and schedule posts](https://github.com/sk22/megalodon/pull/217)
* [Display original post when replying](https://github.com/sk22/megalodon/commit/375f8ceb2747705fedf43686681cc0e0b812f899)
* [Display server announcements](https://github.com/sk22/megalodon/commit/84179bc207d6b69cc2a770a3c28fa0a39b0b54e8)
* [Create](https://github.com/sk22/megalodon/commit/294595513a45037359b31377aafc25ae5b58d8e7), [edit](https://github.com/sk22/megalodon/commit/d47797bf7ac8cff3f9ba1cfee219a1bb2af21da6) and [delete](https://github.com/sk22/megalodon/commit/54c29fd787fc2cd0dfd2787ad796b8190f795973) lists
* [Soft-blocking (by blocking and immediately unblocking)](https://github.com/sk22/megalodon/commit/e75d350b7a2709259e9fc5138e0e1f361bdb0972)
* [Pinnable custom timelines](https://github.com/sk22/megalodon/pull/338/commits)
* Support for local-only posts
### Behavior
* Adding a bottom option for the publish button, allowing for easier user on larger screens!
* [Make back button return to the home tab before exiting the app](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/back-returns-home) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/118))
* [Always preserve content warnings when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/always-preserve-cw) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/113))
* [Display full image when adding image description](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/compose-image-description-full-image) ([Pull request](https://github.com/mastodon/mastodon-android/pull/182))
@@ -114,6 +165,20 @@ Variant with an integrated updater. If you download Moshidon from here (and not
* [Option to hide interaction numbers](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:settings/hide-interaction-numbers)
* [Option to always reveal content warnings](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/cw-above-text)
* [Option to disable scrolling title bars](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:settings/disable-marquee)
* [No ellipsis for long poll answers](https://github.com/mastodon/mastodon-android/commit/c9aae828e2518adccdc092e41f8d1f0489636271)
* [Show poll vote button for multiple and single answer polls](https://github.com/mastodon/mastodon-android/commit/e14dfda2fdf32f0fa3043504ac5831683a87559a)
* [Show own vote after voting](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28) ([Closes issue](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28))
* [Make inline emoji search case-insensitive and don't only search from start of emoji names](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:better-inline-emoji-search) ([Pull request](https://github.com/mastodon/mastodon-android/pull/445))
* [Include subject line when sharing e.g. a website to Megalodon](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:external-share-include-subject)
* [Improve semantics for voting on polls (radio buttons and checkboxes)](https://github.com/sk22/megalodon/commit/6fd58c96827cb1d2da329cebdc170a1425dd18d7)
* [Copy post URL when long-pressing share button](https://github.com/sk22/megalodon/commit/ba36347f03278763ecec617b1ce57ba89db7be72)
* [Add option to disable swiping between tabs](https://github.com/sk22/megalodon/commit/1f20b21fc84bf006c1ec14bd2229cbfad5215ec8)
* [Resolve Fediverse links in the app](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/open-urls-in-app)
* [Preserve whitespaces in HTML](https://github.com/sk22/megalodon/commit/7d876bddc7a07d98f0fecbf62b13bdb9fcce3412)
* [Long-click to copy links](https://github.com/sk22/megalodon/commit/b32e32274923a94742a9926ef38785f746d41405)
* Improved filtering using Mastodon 4.0 API: [#202](https://github.com/sk22/megalodon/pull/202), [#212](https://github.com/sk22/megalodon/pull/212), [#255](https://github.com/sk22/megalodon/pull/255) by [@thiagojedi](https://github.com/thiagojedi)
* [Support admin notifications](https://github.com/sk22/megalodon/commit/c12a6eaee6b609bc53eb0a45d9199f37d5241801) and [notifications for edited reblogged posts](https://github.com/sk22/megalodon/commit/900e8fb2e9353002c16d15e06b78d2731e121601)
* [Android file opener added back in addition to image picker](https://github.com/sk22/megalodon/commit/3a6ace53d5ab01e28077c9c930cb6ed487b78031)
### Visual
@@ -121,6 +186,16 @@ Variant with an integrated updater. If you download Moshidon from here (and not
* [Custom extended footer redesign](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:compact-extended-footer)
* [Improvements to the true black mode](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:true-black-improvements)
* [Profile header tweaks](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:ui/profile-header-tweaks)
* [Custom color themes](https://github.com/sk22/megalodon/pull/124) by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Custom "megalodon" text logo](https://github.com/sk22/megalodon/commit/563afd487ca5c608cfbb00fa3909d3c27384acc0) by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Custom login screen](https://github.com/sk22/megalodon/commit/9bbf8c4618dbe13accaeb3b5482bf3fe88cac4c0)
* [More distinct filled boost icon](https://github.com/sk22/megalodon/commits/more-distinct-filled-boost-icon)
* Material You color theme by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Animations for interaction buttons](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/animate-buttons)
* [Dedicated icons for different notification types](https://github.com/sk22/megalodon/pull/178) by [@florian-obernberger](https://github.com/florian-obernberger)
* Scale text according to system settings
* Header in timeline for followed hashtags
* [Indicator for missing alt texts](https://github.com/sk22/megalodon/commit/c0c276f03e793b78c478c17dfdef24a66ef7cedb)
## Building
@@ -137,6 +212,4 @@ This project is released under the [GPL-3 License](./LICENSE).
## Links
[Official matrix chatroom:](https://matrix.to/#/#moshidon:matrix.org) https://matrix.to/#/#moshidon:matrix.org
<a rel="me" href="https://floss.social/@moshidon">@moshidon<wbr>@floss.social</a>
<a rel="me" href="https://floss.social/@megalodon">@megalodon<wbr>@floss.social</a>

View File

@@ -1,2 +1,2 @@
title: Moshidon
title: Megalodon
layout: default

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moshidon</title>
<title>Megalodon</title>
<link rel="icon" href="mastodon/src/main/res/mipmap-mdpi/ic_launcher_round.png">
<link rel="me" href="https://floss.social/@mastodon">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
@@ -14,4 +14,4 @@
{{ content }}
</div>
</body>
</html>
</html>

3
fix-metadata-markdown-lists.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
find metadata -name '*.txt' -exec sed -Ei 's/^[–—─•·*]\s+/- /' {} \;

View File

@@ -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

BIN
img/izzy-badge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -5,12 +5,12 @@ plugins {
android {
compileSdk 33
defaultConfig {
archivesBaseName = "moshidon"
applicationId "org.joinmastodon.android.moshinda"
archivesBaseName = "megalodon"
applicationId "org.joinmastodon.android.sk"
minSdk 23
targetSdk 33
versionCode 91
versionName "1.1.4+fork.91.moshinda"
versionCode 74
versionName "1.1.5+fork.74"
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'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -115,7 +115,7 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
private void actuallyCheckForUpdates(){
Request req=new Request.Builder()
.url("https://api.github.com/repos/LucasGGamerM/moshidon/releases")
.url("https://api.github.com/repos/sk22/megalodon/releases")
.build();
Call call=MastodonAPIController.getHttpClient().newCall(req);
try(Response resp=call.execute()){
@@ -153,7 +153,7 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
Log.d(TAG, "actuallyCheckForUpdates: new version: "+version);
for(JsonElement el:obj.getAsJsonArray("assets")){
JsonObject asset=el.getAsJsonObject();
if("moshidon.apk".equals(asset.get("name").getAsString()) && "application/vnd.android.package-archive".equals(asset.get("content_type").getAsString()) && "uploaded".equals(asset.get("state").getAsString())){
if("megalodon.apk".equals(asset.get("name").getAsString()) && "application/vnd.android.package-archive".equals(asset.get("content_type").getAsString()) && "uploaded".equals(asset.get("state").getAsString())){
long size=asset.get("size").getAsLong();
String url=asset.get("browser_download_url").getAsString();

View File

@@ -1,3 +0,0 @@
<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="M3.897 4.054L3.97 3.97c0.266-0.267 0.683-0.29 0.976-0.073L5.03 3.97 10 8.939l4.97-4.97c0.266-0.266 0.683-0.29 0.976-0.072L16.03 3.97c0.267 0.266 0.29 0.683 0.073 0.976L16.03 5.03 11.061 10l4.97 4.97c0.266 0.266 0.29 0.683 0.072 0.976L16.03 16.03c-0.266 0.267-0.683 0.29-0.976 0.073L14.97 16.03 10 11.061l-4.97 4.97c-0.266 0.266-0.683 0.29-0.976 0.072L3.97 16.03c-0.267-0.266-0.29-0.683-0.073-0.976L3.97 14.97 8.939 10l-4.97-4.97C3.704 4.764 3.68 4.347 3.898 4.054L3.97 3.97 3.897 4.054z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -1,3 +0,0 @@
<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="M22 6.5c0 3.038-2.462 5.5-5.5 5.5S11 9.538 11 6.5 13.462 1 16.5 1 22 3.462 22 6.5zm-7.146-2.354c-0.196-0.195-0.512-0.195-0.708 0-0.195 0.196-0.195 0.512 0 0.708L15.793 6.5l-1.647 1.646c-0.195 0.196-0.195 0.512 0 0.707 0.196 0.196 0.512 0.196 0.708 0L16.5 7.208l1.646 1.647c0.196 0.195 0.512 0.195 0.708 0 0.195-0.196 0.195-0.512 0-0.707L17.207 6.5l1.647-1.646c0.195-0.196 0.195-0.512 0-0.708-0.196-0.195-0.512-0.195-0.708 0L16.5 5.793l-1.646-1.647zM19.5 14v-1.732c0.551-0.287 1.056-0.651 1.5-1.078v7.56c0 1.733-1.357 3.15-3.066 3.245L17.75 22H6.25c-1.733 0-3.15-1.357-3.245-3.066L3 18.75V7.25C3 5.517 4.356 4.1 6.066 4.005L6.25 4h4.248c-0.198 0.474-0.34 0.977-0.422 1.5H6.25c-0.918 0-1.671 0.707-1.744 1.606L4.5 7.25V14H9c0.38 0 0.694 0.282 0.743 0.648L9.75 14.75C9.75 15.993 10.757 17 12 17c1.19 0 2.166-0.925 2.245-2.096l0.005-0.154c0-0.38 0.282-0.694 0.648-0.743L15 14h4.5zm-15 1.5v3.25c0 0.918 0.707 1.671 1.606 1.744L6.25 20.5h11.5c0.918 0 1.671-0.707 1.744-1.607L19.5 18.75V15.5h-3.825c-0.335 1.648-1.75 2.904-3.475 2.995L12 18.5c-1.747 0-3.215-1.195-3.632-2.812L8.325 15.5H4.5z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -1,3 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" android:viewportWidth="28" android:viewportHeight="28">
<path android:pathData="M26 7.5c0 3.59-2.91 6.5-6.5 6.5S13 11.09 13 7.5 15.91 1 19.5 1 26 3.91 26 7.5zm-9.146-3.354c-0.196-0.195-0.512-0.195-0.708 0-0.195 0.196-0.195 0.512 0 0.708L18.793 7.5l-2.647 2.646c-0.195 0.196-0.195 0.512 0 0.708 0.196 0.195 0.512 0.195 0.708 0L19.5 8.207l2.646 2.647c0.196 0.195 0.512 0.195 0.708 0 0.195-0.196 0.195-0.512 0-0.708L20.207 7.5l2.647-2.646c0.195-0.196 0.195-0.512 0-0.708-0.196-0.195-0.512-0.195-0.708 0L19.5 6.793l-2.646-2.647zM25 22.75V12.6c-0.443 0.476-0.947 0.896-1.5 1.245V16h-6l-0.102 0.007c-0.366 0.05-0.648 0.363-0.648 0.743 0 1.519-1.231 2.75-2.75 2.75s-2.75-1.231-2.75-2.75l-0.007-0.102C11.193 16.282 10.88 16 10.5 16h-6V7.25c0-0.966 0.784-1.75 1.75-1.75h6.02c0.145-0.525 0.345-1.028 0.595-1.5H6.25C4.455 4 3 5.455 3 7.25v15.5C3 24.545 4.455 26 6.25 26h15.5c1.795 0 3.25-1.455 3.25-3.25zm-20.5 0V17.5h5.316l0.041 0.204C10.291 19.592 11.982 21 14 21l0.215-0.005c1.994-0.1 3.627-1.574 3.969-3.495H23.5v5.25c0 0.966-0.784 1.75-1.75 1.75H6.25c-0.966 0-1.75-0.784-1.75-1.75z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -22,7 +22,7 @@
<application
android:name=".MastodonApp"
android:allowBackup="true"
android:label="@string/mo_app_name"
android:label="@string/sk_app_name"
android:supportsRtl="true"
android:localeConfig="@xml/locales_config"
android:icon="@mipmap/ic_launcher"
@@ -41,7 +41,7 @@
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="moshidon-android-auth" android:host="callback"/>
<data android:scheme="megalodon-android-auth" android:host="callback"/>
</intent-filter>
</activity>
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 358 KiB

View File

@@ -12,7 +12,6 @@ import android.widget.Toast;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.ArrayList;
@@ -36,13 +35,10 @@ public class ExternalShareActivity extends FragmentStackActivity{
openComposeFragment(sessions.get(0).getID());
}else{
getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
new M3AlertDialogBuilder(this)
.setItems(sessions.stream().map(as->"@"+as.self.username+"@"+as.domain).toArray(String[]::new), (dialog, which)->{
openComposeFragment(sessions.get(which).getID());
})
.setTitle(R.string.choose_account)
.setOnCancelListener(dialog -> finish())
.show();
UiUtils.pickAccount(this, null, R.string.choose_account, 0,
session -> openComposeFragment(session.getID()),
b -> b.setOnCancelListener(d -> finish())
);
}
}
}

View File

@@ -4,7 +4,6 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
@@ -30,17 +29,20 @@ public class GlobalUserPreferences{
public static boolean alwaysExpandContentWarnings;
public static boolean disableMarquee;
public static boolean disableSwipe;
public static boolean disableDividers;
public static boolean voteButtonForSingleChoice;
public static boolean uniformNotificationIcon;
public static boolean enableDeleteNotifications;
public static boolean relocatePublishButton;
public static boolean translateButtonOpenedOnly;
public static boolean uniformNotificationIcon;
public static boolean reduceMotion;
public static boolean keepOnlyLatestNotification;
public static boolean enableFabAutoHide;
public static boolean disableAltTextReminder;
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;
@@ -52,11 +54,7 @@ public class GlobalUserPreferences{
public static Set<String> accountsWithLocalOnlySupport;
public static Set<String> accountsInGlitchMode;
private final static Type recentEmojisType = new TypeToken<Map<String, Integer>>() {}.getType();
public static Map<String, Integer> recentEmojis;
public static boolean enablePreReleases;
private static SharedPreferences getPrefs(){
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
}
@@ -75,40 +73,36 @@ public class GlobalUserPreferences{
showBoosts=prefs.getBoolean("showBoosts", true);
loadNewPosts=prefs.getBoolean("loadNewPosts", true);
showNewPostsButton=prefs.getBoolean("showNewPostsButton", true);
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", true);
showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
disableMarquee=prefs.getBoolean("disableMarquee", false);
disableSwipe=prefs.getBoolean("disableSwipe", false);
disableDividers=prefs.getBoolean("disableDividers", true);
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", true);
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", false);
translateButtonOpenedOnly=prefs.getBoolean("translateButtonOpenedOnly", false);
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
reduceMotion=prefs.getBoolean("reduceMotion", false);
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
enableFabAutoHide=prefs.getBoolean("enableFabAutoHide", true);
disableAltTextReminder=prefs.getBoolean("disableAltTextReminder", false);
showAltIndicator =prefs.getBoolean("showAltIndicator", true);
showNoAltIndicator =prefs.getBoolean("showNoAltIndicator", true);
enablePreReleases =prefs.getBoolean("enablePreReleases", false);
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", "{}"), recentLanguagesType, new HashMap<>());
recentEmojis=fromJson(prefs.getString("recentEmojis", "{}"), recentEmojisType, new HashMap<>());
publishButtonText=prefs.getString("publishButtonText", "");
recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new HashMap<>());
pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
try {
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.MATERIAL3.name()));
}else{
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PURPLE.name()));
}
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PINK.name()));
} catch (IllegalArgumentException|ClassCastException ignored) {
// invalid color name or color was previously saved as integer
color=ColorPreference.PURPLE;
color=ColorPreference.PINK;
}
}
@@ -125,23 +119,24 @@ public class GlobalUserPreferences{
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
.putBoolean("disableMarquee", disableMarquee)
.putBoolean("disableSwipe", disableSwipe)
.putBoolean("disableDividers", disableDividers)
.putBoolean("relocatePublishButton", relocatePublishButton)
.putBoolean("uniformNotificationIcon", uniformNotificationIcon)
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
.putBoolean("translateButtonOpenedOnly", translateButtonOpenedOnly)
.putBoolean("uniformNotificationIcon", uniformNotificationIcon)
.putBoolean("reduceMotion", reduceMotion)
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
.putBoolean("enableFabAutoHide", enableFabAutoHide)
.putBoolean("disableAltTextReminder", disableAltTextReminder)
.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))
.putString("pinnedTimelines", gson.toJson(pinnedTimelines))
.putString("recentEmojis", gson.toJson(recentEmojis))
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
.apply();
@@ -155,8 +150,7 @@ public class GlobalUserPreferences{
BLUE,
BROWN,
RED,
YELLOW,
NORD
YELLOW
}
public enum ThemePreference{

View File

@@ -17,7 +17,6 @@ import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
@@ -155,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();

View File

@@ -37,7 +37,6 @@ public class PushNotificationReceiver extends BroadcastReceiver{
private static final String TAG="PushNotificationReceive";
public static final int NOTIFICATION_ID=178;
private static final int SUMMARY_ID = 791;
private static int notificationId = 0;
@Override
@@ -99,7 +98,6 @@ public class PushNotificationReceiver extends BroadcastReceiver{
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
String accountName="@"+self.username+"@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
Notification.Builder builder;
Notification.Builder summaryNotification;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
boolean hasGroup=false;
List<NotificationChannelGroup> channelGroups=nm.getNotificationChannelGroups();
@@ -122,28 +120,21 @@ public class PushNotificationReceiver extends BroadcastReceiver{
nm.createNotificationChannels(channels);
}
builder=new Notification.Builder(context, accountID+"_"+pn.notificationType);
// summaryNotification=new Notification.Builder(context, accountID);
}else{
builder=new Notification.Builder(context)
.setPriority(Notification.PRIORITY_DEFAULT)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
summaryNotification=new Notification.Builder(context)
.setPriority(Notification.PRIORITY_DEFAULT)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
}
Drawable avatar=ImageCache.getInstance(context).get(new UrlImageLoaderRequest(pn.icon, V.dp(50), V.dp(50)));
Intent contentIntent=new Intent(context, MainActivity.class);
contentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
contentIntent.putExtra("fromNotification", true);
contentIntent.putExtra("accountID", accountID);
contentIntent.putExtra("notificationID", notificationId);
if(notification!=null){
contentIntent.putExtra("notification", Parcels.wrap(notification));
}
builder.setContentTitle(pn.title)
.setContentText(pn.body)
.setContentTitle(pn.title)
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
.setSmallIcon(R.drawable.ic_ntf_logo)
.setContentIntent(PendingIntent.getActivity(context, notificationId, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT))
@@ -151,8 +142,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setShowWhen(true)
.setCategory(Notification.CATEGORY_SOCIAL)
.setAutoCancel(true)
.setColor(context.getColor(R.color.shortcut_icon_background))
.setGroup(accountID);
.setColor(context.getColor(R.color.primary_700));
if (!GlobalUserPreferences.uniformNotificationIcon) {
builder.setSmallIcon(switch (pn.notificationType) {
@@ -174,9 +164,6 @@ public class PushNotificationReceiver extends BroadcastReceiver{
if(AccountSessionManager.getInstance().getLoggedInAccounts().size()>1){
builder.setSubText(accountName);
}
notificationId++;
nm.notify(accountID, GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId, builder.build());
nm.notify(accountID, GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId++, builder.build());
}
}

View File

@@ -372,7 +372,7 @@ public class PushSubscriptionManager{
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
if(session.pushSubscription==null || forceReRegister)
session.getPushSubscriptionManager().registerAccountForPush(session.pushSubscription);
else if(session.needUpdatePushSettings)
else
session.getPushSubscriptionManager().updatePushSettings(session.pushSubscription);
}
}

View File

@@ -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)

View File

@@ -1,19 +0,0 @@
package org.joinmastodon.android.api.requests.accounts;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Relationship;
public class SetPrivateNote extends MastodonAPIRequest<Relationship>{
public SetPrivateNote(String id, String comment){
super(MastodonAPIRequest.HttpMethod.POST, "/accounts/"+id+"/note", Relationship.class);
Request req = new Request(comment);
setRequestBody(req);
}
private static class Request{
public String comment;
public Request(String comment){
this.comment=comment;
}
}
}

View File

@@ -1,17 +0,0 @@
package org.joinmastodon.android.api.requests.lists;
import org.joinmastodon.android.api.MastodonAPIRequest;
import java.util.List;
public class AddList extends MastodonAPIRequest<Object> {
public AddList(String listName){
super(HttpMethod.POST, "/lists", Object.class);
Request req = new Request();
req.title = listName;
setRequestBody(req);
}
public static class Request{
public String title;
}
}

View File

@@ -1,17 +0,0 @@
package org.joinmastodon.android.api.requests.lists;
import org.joinmastodon.android.api.MastodonAPIRequest;
import java.util.List;
public class EditListName extends MastodonAPIRequest<Object> {
public EditListName(String newListName, String listId){
super(HttpMethod.PUT, "/lists/"+listId, Object.class);
Request req = new Request();
req.title = newListName;
setRequestBody(req);
}
public static class Request{
public String title;
}
}

View File

@@ -1,10 +0,0 @@
package org.joinmastodon.android.api.requests.lists;
import org.joinmastodon.android.api.MastodonAPIRequest;
import java.util.List;
public class RemoveList extends MastodonAPIRequest<Object> {
public RemoveList(String listId){
super(HttpMethod.DELETE, "/lists/"+listId, Object.class);
}
}

View File

@@ -10,8 +10,8 @@ import java.util.EnumSet;
import java.util.List;
public class DismissNotification extends MastodonAPIRequest<Object>{
public DismissNotification(String id){
super(HttpMethod.POST, "/notifications/" + (id != null ? id + "/dismiss" : "clear"), Object.class);
setRequestBody(new Object());
}
public DismissNotification(String id){
super(HttpMethod.POST, "/notifications/" + (id != null ? id + "/dismiss" : "clear"), Object.class);
setRequestBody(new Object());
}
}

View File

@@ -11,9 +11,9 @@ public class CreateOAuthApp extends MastodonAPIRequest<Application>{
}
private static class Request{
public String clientName="Moshidon";
public String clientName="Megalodon";
public String redirectUris=AccountSessionManager.REDIRECT_URI;
public String scopes=AccountSessionManager.SCOPE;
public String website="https://github.com/LucasGGamerM/moshidon";
public String website="https://sk22.github.io/megalodon";
}
}

View File

@@ -61,7 +61,7 @@ import me.grishka.appkit.api.ErrorResponse;
public class AccountSessionManager{
private static final String TAG="AccountSessionManager";
public static final String SCOPE="read write follow push";
public static final String REDIRECT_URI="moshidon-android-auth://callback";
public static final String REDIRECT_URI="megalodon-android-auth://callback";
private static final AccountSessionManager instance=new AccountSessionManager();
@@ -211,7 +211,7 @@ public class AccountSessionManager{
.path("/oauth/authorize")
.appendQueryParameter("response_type", "code")
.appendQueryParameter("client_id", result.clientId)
.appendQueryParameter("redirect_uri", "moshidon-android-auth://callback")
.appendQueryParameter("redirect_uri", "megalodon-android-auth://callback")
.appendQueryParameter("scope", SCOPE)
.build();

View File

@@ -3,10 +3,6 @@ package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.TranslateAnimation;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
@@ -15,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;
@@ -61,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());
}
})
@@ -70,7 +70,6 @@ public class AccountTimelineFragment extends StatusListFragment{
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
fab = ((ProfileFragment) getParentFragment()).getFab();
}
@Override

View File

@@ -16,7 +16,6 @@ import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.Toolbar;
@@ -59,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,14 +75,18 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
protected DisplayItemsAdapter adapter;
protected String accountID;
protected PhotoViewer currentPhotoViewer;
protected ImageButton fab;
protected int scrollDiff = 0;
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
@@ -95,6 +100,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
setRetainInstance(true);
}
@Override
protected RecyclerView.Adapter getAdapter(){
return adapter=new DisplayItemsAdapter();
@@ -278,46 +285,11 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
fab=view.findViewById(R.id.fab);
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
if(currentPhotoViewer!=null)
currentPhotoViewer.offsetView(-dx, -dy);
if (fab!=null && GlobalUserPreferences.enableFabAutoHide) {
if(dy > 0){
scrollDiff = 0;
}
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
fab.setVisibility(View.INVISIBLE);
scrollDiff = 0;
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
if (scrollDiff > 800) {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
scrollDiff = 0;
} else {
scrollDiff += Math.abs(dy);
}
}
}
}
});
list.addItemDecoration(new StatusListItemDecoration());
@@ -353,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
@@ -518,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());
}
@@ -527,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)){
@@ -544,14 +540,13 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
public void onGapClick(GapStatusDisplayItem.Holder item){}
public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warningItem){
int i = warningItem.getAbsoluteAdapterPosition();
for(StatusDisplayItem item:warningItem.filteredItems){
i++;
displayItems.add(i, item);
}
displayItems.remove(warningItem.getAbsoluteAdapterPosition());
adapter.notifyItemChanged(warningItem.getAbsoluteAdapterPosition());
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(){
@@ -669,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(){
@@ -725,7 +730,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
private int currentMediaHiddenLayoutsWidth=0;
{
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), GlobalUserPreferences.disableDividers ? R.attr.colorWindowBackground : R.attr.colorPollVoted));
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), R.attr.colorPollVoted));
dividerPaint.setStyle(Paint.Style.STROKE);
dividerPaint.setStrokeWidth(V.dp(1));
}

View File

@@ -1,10 +1,9 @@
package org.joinmastodon.android.fragments;
import static android.os.ext.SdkExtensions.getExtensionVersion;
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;
@@ -43,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;
@@ -67,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;
@@ -116,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;
@@ -156,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();
@@ -230,17 +232,13 @@ 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;
private int navigationBarColorBefore;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(true);
navigationBarColorBefore = getActivity().getWindow().getNavigationBarColor();
getActivity().getWindow().setNavigationBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLightest));
accountID=getArguments().getString("account");
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
@@ -285,7 +283,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
UiUtils.removeCallbacks(updateUploadEtaRunnable);
updateUploadEtaRunnable=null;
}
getActivity().getWindow().setNavigationBarColor(navigationBarColorBefore);
}
@Override
@@ -303,25 +300,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
emojiKeyboard.setListener(this::onCustomEmojiClick);
View view=inflater.inflate(R.layout.fragment_compose, container, false);
if(GlobalUserPreferences.relocatePublishButton){
publishButton=view.findViewById(R.id.publish);
// publishButton.setText(editingStatus==null || redraftStatus ? R.string.publish : R.string.save);
publishButton.setEllipsize(TextUtils.TruncateAt.END);
publishButton.setOnClickListener(this::onPublishClick);
publishButton.setSingleLine(true);
publishButton.setVisibility(View.VISIBLE);
draftsBtn=view.findViewById(R.id.drafts_btn);
draftsBtn.setVisibility(View.VISIBLE);
} else {
charCounter=view.findViewById(R.id.char_counter);
charCounter.setVisibility(View.VISIBLE);
charCounter.setText(String.valueOf(charLimit));
}
mainEditText=view.findViewById(R.id.toot_text);
mainEditTextWrap=view.findViewById(R.id.toot_text_wrap);
charCounter=view.findViewById(R.id.char_counter);
charCounter.setText(String.valueOf(charLimit));
scrollView=view.findViewById(R.id.scroll_view);
selfName=view.findViewById(R.id.self_name);
@@ -710,10 +692,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
replyText.setOnClickListener(v->{
scrollView.smoothScrollTo(0, 0);
});
replyText.setOnClickListener(v->{
scrollView.smoothScrollTo(0, 0);
});
ArrayList<String> mentions=new ArrayList<>();
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
@@ -735,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);
@@ -805,20 +787,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
item.setActionView(wrap);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
if(!GlobalUserPreferences.relocatePublishButton){
publishButton = wrap.findViewById(R.id.publish_btn);
publishButton.setOnClickListener(this::onPublishClick);
publishButton.setVisibility(View.VISIBLE);
draftsBtn = wrap.findViewById(R.id.drafts_btn);
draftsBtn.setVisibility(View.VISIBLE);
}else{
charCounter = wrap.findViewById(R.id.char_counter);
charCounter.setVisibility(View.VISIBLE);
charCounter.setText(String.valueOf(charLimit));
}
// draftsBtn = wrap.findViewById(R.id.drafts_btn);
draftsBtn = wrap.findViewById(R.id.drafts_btn);
draftOptionsPopup = new PopupMenu(getContext(), draftsBtn);
draftOptionsPopup.inflate(R.menu.compose_more);
draftMenuItem = draftOptionsPopup.getMenu().findItem(R.id.draft);
@@ -835,11 +804,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
});
UiUtils.enablePopupMenuIcons(getContext(), draftOptionsPopup);
publishButton = wrap.findViewById(R.id.publish_btn);
languageButton = wrap.findViewById(R.id.language_btn);
sendProgress = wrap.findViewById(R.id.send_progress);
sendError = wrap.findViewById(R.id.send_error);
publishButton.setOnClickListener(this::onPublishClick);
draftsBtn.setOnClickListener(v-> draftOptionsPopup.show());
draftsBtn.setOnTouchListener(draftOptionsPopup.getDragToOpenListener());
updateScheduledAt(scheduledAt != null ? scheduledAt : scheduledStatus != null ? scheduledStatus.scheduledAt : null);
@@ -872,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")
@@ -891,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);
@@ -901,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;
@@ -947,9 +945,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private void resetPublishButtonText() {
int publishText = editingStatus==null || redraftStatus ? R.string.publish : R.string.save;
if(GlobalUserPreferences.relocatePublishButton){
return;
}
if (publishText == R.string.publish && !GlobalUserPreferences.publishButtonText.isEmpty()) {
publishButton.setText(GlobalUserPreferences.publishButtonText);
} else {
@@ -972,7 +967,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
nonDoneAttachmentCount++;
}
publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && nonDoneAttachmentCount==0 && (pollOptions.isEmpty() || nonEmptyPollOptionsCount>1));
// sendError.setVisibility(View.GONE);
sendError.setVisibility(View.GONE);
}
private void onCustomEmojiClick(Emoji emoji){
@@ -988,18 +983,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
private void onPublishClick(View v){
if (!attachments.isEmpty()
&& statusVisibility != StatusPrivacy.DIRECT
&& !attachments.stream().allMatch(attachment -> attachment.description != null && !attachment.description.isBlank())) {
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.mo_no_image_desc_title)
.setMessage(R.string.mo_no_image_desc)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.publish, (dialog, i)-> publish())
.show();
} else {
publish();
}
publish();
}
private void publishErrorCallback(ErrorResponse error) {
@@ -1046,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()) {
@@ -1146,7 +1134,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
};
if(editingStatus!=null && !redraftStatus){
new EditStatus(req, editingStatus.id)
.setCallback(resCallback)
@@ -1188,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();
}
@@ -1253,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);
@@ -1263,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.
@@ -1286,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/*"});
}
@@ -1450,7 +1440,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private void uploadMediaAttachment(DraftMediaAttachment attachment){
if(areThereAnyUploadingAttachments()){
throw new IllegalStateException("there is already an attachment being uploaded");
throw new IllegalStateException("there is already an attachment being uploaded");
}
attachment.state=AttachmentUploadState.UPLOADING;
attachment.progressBar.setVisibility(View.VISIBLE);
@@ -1648,6 +1638,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
if(att.serverAttachment==null)
return;
editMediaDescription(att);
}
private void editMediaDescription(DraftMediaAttachment att) {
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("attachment", att.serverAttachment.id);
@@ -1805,15 +1799,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
scheduleDraftText.setText(R.string.sk_compose_draft);
scheduleDraftText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_drafts_20_regular, 0, 0, 0);
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_draft));
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_drafts_24_regular : R.drawable.ic_fluent_drafts_20_filled, 0, 0, 0);
if(GlobalUserPreferences.relocatePublishButton){
publishButton.setCompoundDrawablesWithIntrinsicBounds(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.drawable.ic_fluent_save_24_selector : R.drawable.ic_fluent_drafts_24_selector, 0, 0, 0);
}else{
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.string.save : R.string.sk_draft);
}
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_drafts_20_filled, 0, 0, 0);
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.string.save : R.string.sk_draft);
} else {
scheduleMenuItem.setVisible(false);
unscheduleMenuItem.setVisible(true);
@@ -1823,21 +1811,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
scheduleDraftText.setText(R.string.sk_compose_scheduled);
scheduleDraftText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_schedule));
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_filled : R.drawable.ic_fluent_clock_20_filled, 0, 0, 0);
if(GlobalUserPreferences.relocatePublishButton)
{
publishButton.setCompoundDrawablesWithIntrinsicBounds(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.drawable.ic_fluent_save_24_selector : R.drawable.ic_fluent_clock_24_selector, 0, 0, 0);
}else{
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.equals(scheduledAt)
? R.string.save : R.string.sk_schedule);
}
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_clock_20_filled, 0, 0, 0);
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.equals(scheduledAt)
? R.string.save : R.string.sk_schedule);
}
} else {
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_regular : R.drawable.ic_fluent_clock_20_regular, 0, 0, 0);
if(GlobalUserPreferences.relocatePublishButton){
publishButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_send_24_selector, 0, 0, 0);
}
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_clock_20_regular, 0, 0, 0);
resetPublishButtonText();
}
}
@@ -2057,14 +2036,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
});
}
private void editMediaDescription(DraftMediaAttachment att) {
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("attachment", att.serverAttachment.id);
args.putParcelable("uri", att.uri);
args.putString("existingDescription", att.description);
Nav.goForResult(getActivity(), ComposeImageDescriptionFragment.class, args, IMAGE_DESCRIPTION_RESULT, this);
}
@Override
public CharSequence getTitle(){

View File

@@ -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);
}
}

View File

@@ -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+' ');

View File

@@ -41,11 +41,7 @@ import me.grishka.appkit.views.FragmentRootLinearLayout;
public class HomeFragment extends AppKitFragment implements OnBackPressedListener{
private FragmentRootLinearLayout content;
private HomeTabFragment homeTabFragment;
// private HomeTimelineFragment homeTimelineFragment;
private NotificationsFragment notificationsFragment;
private DiscoverFragment searchFragment;
private ProfileFragment profileFragment;
@@ -61,7 +57,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
setTitle(R.string.mo_app_name);
setTitle(R.string.sk_app_name);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
setRetainInstance(true);
@@ -69,13 +65,8 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
if(savedInstanceState==null){
Bundle args=new Bundle();
args.putString("account", accountID);
homeTabFragment=new HomeTabFragment();
homeTabFragment.setArguments(args);
// homeTimelineFragment=new HomeTimelineFragment();
// homeTimelineFragment.setArguments(args);
args=new Bundle(args);
args.putBoolean("noAutoLoad", true);
searchFragment=new DiscoverFragment();
@@ -125,13 +116,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
.add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
.commit();
// getChildFragmentManager().beginTransaction()
// .add(R.id.fragment_wrap, homeTimelineFragment)
// .add(R.id.fragment_wrap, searchFragment).hide(searchFragment)
// .add(R.id.fragment_wrap, notificationsFragment).hide(notificationsFragment)
// .add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
// .commit();
String defaultTab=getArguments().getString("tab");
if("notifications".equals(defaultTab)){
tabBar.selectTab(R.id.tab_notifications);
@@ -152,21 +136,13 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
@Override
public void onViewStateRestored(Bundle savedInstanceState){
super.onViewStateRestored(savedInstanceState);
if(savedInstanceState==null) return;
// if(savedInstanceState==null || homeTimelineFragment!=null)
// return;
homeTabFragment=(HomeTabFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTabFragment");
// homeTimelineFragment=(HomeTimelineFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTimelineFragment");
searchFragment=(DiscoverFragment) getChildFragmentManager().getFragment(savedInstanceState, "searchFragment");
notificationsFragment=(NotificationsFragment) getChildFragmentManager().getFragment(savedInstanceState, "notificationsFragment");
profileFragment=(ProfileFragment) getChildFragmentManager().getFragment(savedInstanceState, "profileFragment");
currentTab=savedInstanceState.getInt("selectedTab");
Fragment current=fragmentForTab(currentTab);
getChildFragmentManager().beginTransaction()
.hide(homeTabFragment)
.hide(searchFragment)
@@ -174,14 +150,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
.hide(profileFragment)
.show(current)
.commit();
// getChildFragmentManager().beginTransaction()
// .hide(homeTimelineFragment)
// .hide(searchFragment)
// .hide(notificationsFragment)
// .hide(profileFragment)
// .show(current)
// .commit();
maybeTriggerLoading(current);
}
@@ -211,11 +179,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
}
WindowInsets topOnlyInsets=insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
homeTabFragment.onApplyWindowInsets(topOnlyInsets);
// homeTimelineFragment.onApplyWindowInsets(topOnlyInsets);
searchFragment.onApplyWindowInsets(topOnlyInsets);
notificationsFragment.onApplyWindowInsets(topOnlyInsets);
profileFragment.onApplyWindowInsets(topOnlyInsets);
@@ -224,9 +188,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private Fragment fragmentForTab(@IdRes int tab){
if(tab==R.id.tab_home){
return homeTabFragment;
// if(tab==R.id.tab_home){
// return homeTimelineFragment;
}else if(tab==R.id.tab_search){
return searchFragment;
}else if(tab==R.id.tab_notifications){
@@ -240,18 +201,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private void onTabSelected(@IdRes int tab){
Fragment newFragment=fragmentForTab(tab);
if(tab==currentTab){
if(tab == R.id.tab_search){
if(newFragment instanceof ScrollableToTop scrollable)
scrollable.scrollToTop();
searchFragment.selectSearch();
return;
}
if(newFragment instanceof ScrollableToTop scrollable)
scrollable.scrollToTop();
return;
}
if(tab==currentTab && tab == R.id.tab_search){
if(newFragment instanceof ScrollableToTop scrollable)
if (tab == R.id.tab_search)
searchFragment.onSelect();
else if(newFragment instanceof ScrollableToTop scrollable)
scrollable.scrollToTop();
return;
}
@@ -288,12 +240,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
new AccountSwitcherSheet(getActivity()).show();
return true;
}
if(tab==R.id.tab_search){
onTabSelected(R.id.tab_search);
tabBar.selectTab(R.id.tab_search);
searchFragment.selectSearch();
return true;
}
return false;
}
@@ -316,15 +262,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putInt("selectedTab", currentTab);
if (homeTabFragment.isAdded()) getChildFragmentManager().putFragment(outState, "homeTabFragment", homeTabFragment);
if (searchFragment.isAdded()) getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
if (notificationsFragment.isAdded()) getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
if (profileFragment.isAdded()) getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
// getChildFragmentManager().putFragment(outState, "homeTimelineFragment", homeTimelineFragment);
// getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
// getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
// getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
}
}

View File

@@ -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);
}

View File

@@ -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);
@@ -45,7 +50,6 @@ public class HomeTimelineFragment extends FabStatusListFragment {
}
private List<Status> filterPosts(List<Status> items) {
// This is the function I must use to solve the filters thing for real
return items.stream().filter(i ->
(GlobalUserPreferences.showReplies || i.inReplyToId == null) &&
(GlobalUserPreferences.showBoosts || i.reblog == null)
@@ -98,24 +102,24 @@ public class HomeTimelineFragment extends FabStatusListFragment {
@Override
protected void onHidden(){
super.onHidden();
// if(!data.isEmpty()){
// String topPostID=displayItems.get(list.getChildAdapterPosition(list.getChildAt(0))-getMainAdapterOffset()).parentID;
// if(!topPostID.equals(lastSavedMarkerID)){
// lastSavedMarkerID=topPostID;
// new SaveMarkers(topPostID, null)
// .setCallback(new Callback<>(){
// @Override
// public void onSuccess(SaveMarkers.Response result){
// }
//
// @Override
// public void onError(ErrorResponse error){
// lastSavedMarkerID=null;
// }
// })
// .exec(accountID);
// }
// }
if(!data.isEmpty()){
String topPostID=displayItems.get(Math.max(0, list.getChildAdapterPosition(list.getChildAt(0))-getMainAdapterOffset())).parentID;
if(!topPostID.equals(lastSavedMarkerID)){
lastSavedMarkerID=topPostID;
new SaveMarkers(topPostID, null)
.setCallback(new Callback<>(){
@Override
public void onSuccess(SaveMarkers.Response result){
}
@Override
public void onError(ErrorResponse error){
lastSavedMarkerID=null;
}
})
.exec(accountID);
}
}
}
public void onStatusCreated(StatusCreatedEvent ev){

View File

@@ -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);

View File

@@ -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));

View File

@@ -44,7 +44,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
private FrameLayout[] tabViews;
private TabLayoutMediator tabLayoutMediator;
private NotificationsListFragment allNotificationsFragment, mentionsFragment, postsFragment;
private NotificationsListFragment allNotificationsFragment, mentionsFragment;
private String accountID;
@@ -104,13 +104,12 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
pager=view.findViewById(R.id.pager);
UiUtils.reduceSwipeSensitivity(pager);
tabViews=new FrameLayout[3];
tabViews=new FrameLayout[2];
for(int i=0;i<tabViews.length;i++){
FrameLayout tabView=new FrameLayout(getActivity());
tabView.setId(switch(i){
case 0 -> R.id.notifications_all;
case 1 -> R.id.notifications_mentions;
case 2 -> R.id.notifications_posts;
default -> throw new IllegalStateException("Unexpected value: "+i);
});
tabView.setVisibility(View.GONE);
@@ -162,15 +161,9 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
mentionsFragment=new NotificationsListFragment();
mentionsFragment.setArguments(args);
args=new Bundle(args);
args.putBoolean("onlyPosts", true);
postsFragment=new NotificationsListFragment();
postsFragment.setArguments(args);
getChildFragmentManager().beginTransaction()
.add(R.id.notifications_all, allNotificationsFragment)
.add(R.id.notifications_mentions, mentionsFragment)
.add(R.id.notifications_posts, postsFragment)
.commit();
}
@@ -180,7 +173,6 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
tab.setText(switch(position){
case 0 -> R.string.all_notifications;
case 1 -> R.string.mentions;
case 2 -> R.string.posts;
default -> throw new IllegalStateException("Unexpected value: "+position);
});
tab.view.textView.setAllCaps(true);
@@ -231,7 +223,6 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
return switch(page){
case 0 -> allNotificationsFragment;
case 1 -> mentionsFragment;
case 2 -> postsFragment;
default -> throw new IllegalStateException("Unexpected value: "+page);
};
}
@@ -252,7 +243,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
@Override
public int getItemCount(){
return 3;
return 2;
}
@Override

View File

@@ -48,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);
@@ -92,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, Filter.FilterContext.NOTIFICATIONS);
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS);
if(titleItem!=null){
for(StatusDisplayItem item:items){
if(item instanceof ImageStatusDisplayItem imgItem){
@@ -193,6 +198,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);
}
@@ -250,4 +256,4 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
displayItems.subList(index, lastIndex).clear();
adapter.notifyItemRangeRemoved(index, lastIndex-index);
}
}
}

View File

@@ -15,7 +15,6 @@ import java.util.ArrayList;
import java.util.List;
public abstract class PinnableStatusListFragment extends StatusListFragment {
protected boolean pinnedUpdated;
protected List<TimelineDefinition> pinnedTimelines;
@Override
@@ -54,7 +53,7 @@ public abstract class PinnableStatusListFragment extends StatusListFragment {
}
protected void togglePin(MenuItem pin) {
pinnedUpdated = true;
onPinnedUpdated(true);
getToolbar().performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
TimelineDefinition def = makeTimelineDefinition();
boolean pinned = isPinned();
@@ -66,17 +65,5 @@ public abstract class PinnableStatusListFragment extends StatusListFragment {
updatePinButton(pin);
}
protected Bundle getResultArgs() {
return new Bundle();
}
@Override
public void onDestroy() {
super.onDestroy();
Bundle resultArgs = getResultArgs();
if (pinnedUpdated) {
resultArgs.putBoolean("pinnedUpdated", true);
setResult(true, resultArgs);
}
}
public void onPinnedUpdated(boolean pinned) {}
}

View File

@@ -1,6 +1,5 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.app.Fragment;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -13,23 +12,11 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.SetPrivateNote;
import org.joinmastodon.android.model.AccountField;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
@@ -39,8 +26,11 @@ import org.joinmastodon.android.ui.views.LinkedTextView;
import java.util.Collections;
import java.util.List;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.fragments.WindowInsetsAwareFragment;
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
@@ -56,11 +46,6 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
private static final int MAX_FIELDS=4;
public UsableRecyclerView list;
public FrameLayout noteWrap;
public EditText noteEdit;
private String accountID;
private String profileAccountID;
private String note;
private List<AccountField> fields=Collections.emptyList();
private AboutAdapter adapter;
private Paint dividerPaint=new Paint();
@@ -79,49 +64,11 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
adapter.notifyDataSetChanged();
}
public void setNote(String note, String accountID, String profileAccountID){
this.note=note;
this.accountID=accountID;
this.profileAccountID=profileAccountID;
// noteWrap.setVisibility(View.VISIBLE);
// noteEdit.setVisibility(View.VISIBLE);
// noteEdit.setText(note);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_profile_about, null);
noteEdit = view.findViewById(R.id.note_edit);
noteWrap = view.findViewById(R.id.note_edit_wrap);
ImageButton noteEditConfirm = view.findViewById(R.id.note_edit_confirm);
noteEdit.setOnFocusChangeListener((v, hasFocus) -> {
if (hasFocus) {
noteEditConfirm.setVisibility(View.VISIBLE);
noteEditConfirm.animate()
.alpha(1.0f)
.setDuration(700);
} else {
noteEditConfirm.animate()
.alpha(0.0f)
.setDuration(700);
noteEditConfirm.setVisibility(View.INVISIBLE);
}
});
noteEditConfirm.setOnClickListener((v -> {
if (!noteEdit.getText().toString().trim().equals(note)) {
savePrivateNote();
}
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getView().getRootView().getWindowToken(), 0);
noteEdit.clearFocus();
}));
list = view.findViewById(R.id.list);
list=new UsableRecyclerView(getActivity());
list.setId(R.id.list);
list.setItemAnimator(new BetterItemAnimator());
list.setDrawSelectorOnTop(true);
list.setLayoutManager(new LinearLayoutManager(getActivity()));
@@ -148,20 +95,8 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
}
}
});
return view;
return list;
}
private void savePrivateNote(){
new SetPrivateNote(profileAccountID, noteEdit.getText().toString()).setCallback(new Callback<>() {
@Override
public void onSuccess(Relationship result) {}
@Override
public void onError(ErrorResponse result) {
Toast.makeText(getActivity(), getString(R.string.mo_personal_note_update_failed), Toast.LENGTH_LONG).show();
}
}).exec(accountID);
}
public void enterEditMode(List<AccountField> editableFields){
isInEditMode=true;

View File

@@ -8,9 +8,11 @@ import android.app.Activity;
import android.app.Fragment;
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;
@@ -28,23 +30,15 @@ import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager2.widget.ViewPager2;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
@@ -52,7 +46,6 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.api.requests.accounts.SetPrivateNote;
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
@@ -62,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;
@@ -70,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 +80,13 @@ import java.util.ArrayList;
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;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -91,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;
@@ -102,27 +112,25 @@ 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;
public FrameLayout noteWrap;
public EditText noteEdit;
private String note;
private Account account;
private String accountID;
private Relationship relationship;
@@ -134,11 +142,20 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private Uri editNewAvatar, editNewCover;
private String profileAccountID;
private boolean refreshing;
private ImageButton fab;
private View fab;
private WindowInsets childInsets;
private PhotoViewer currentPhotoViewer;
private boolean editModeLoading;
private boolean isScrollingUp = false;
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);
@@ -184,15 +201,16 @@ 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);
followingCount=content.findViewById(R.id.following_count);
followingLabel=content.findViewById(R.id.following_label);
followingBtn=content.findViewById(R.id.following_btn);
postsCount=content.findViewById(R.id.posts_count);
postsLabel=content.findViewById(R.id.posts_label);
postsBtn=content.findViewById(R.id.posts_btn);
@@ -208,10 +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);
noteEdit = content.findViewById(R.id.note_edit);
noteWrap = content.findViewById(R.id.note_edit_wrap);
Button noteEditConfirm = content.findViewById(R.id.note_edit_confirm);
list=content.findViewById(R.id.metadata);
rolesView=content.findViewById(R.id.roles);
avatar.setOutlineProvider(new ViewOutlineProvider(){
@Override
@@ -221,49 +237,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
});
avatar.setClipToOutline(true);
noteEdit.setOnFocusChangeListener((v, hasFocus) -> {
if (hasFocus) {
fab.setVisibility(View.INVISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
noteEditConfirm.setVisibility(View.VISIBLE);
noteEditConfirm.animate()
.alpha(1.0f)
.setDuration(700);
} else {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
animate.setFillAfter(true);
fab.startAnimation(animate);
noteEditConfirm.animate()
.alpha(0.0f)
.setDuration(700);
noteEditConfirm.setVisibility(View.INVISIBLE);
}
});
noteEditConfirm.setOnClickListener((v -> {
if (!noteEdit.getText().toString().trim().equals(note)) {
savePrivateNote();
}
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getView().getRootView().getWindowToken(), 0);
noteEdit.clearFocus();
}));
FrameLayout sizeWrapper=new FrameLayout(getActivity()){
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
@@ -274,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){
@@ -291,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;
@@ -352,28 +325,17 @@ 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;
}
public void setNote(String note){
this.note=note;
noteWrap.setVisibility(View.VISIBLE);
noteEdit.setVisibility(View.VISIBLE);
noteEdit.setText(note);
}
private void savePrivateNote(){
new SetPrivateNote(profileAccountID, noteEdit.getText().toString()).setCallback(new Callback<>() {
@Override
public void onSuccess(Relationship result) {}
@Override
public void onError(ErrorResponse result) {
Toast.makeText(getActivity(), getString(R.string.mo_personal_note_update_failed), Toast.LENGTH_LONG).show();
}
}).exec(accountID);
}
@Override
protected void doLoadData(){
currentRequest=new GetAccountByID(profileAccountID)
@@ -426,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();
@@ -520,8 +482,20 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
name.setText(ssb);
setTitle(ssb);
boolean isSelf=AccountSessionManager.getInstance().isSelf(accountID, account);
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){
ssb=new SpannableStringBuilder("@");
@@ -536,19 +510,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
lock.setTint(username.getCurrentTextColor());
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(lock, ImageSpan.ALIGN_BASELINE), 0);
username.setText(ssb);
}else if(account.bot){
ssb=new SpannableStringBuilder("@");
ssb.append(account.acct);
if(isSelf){
ssb.append('@');
ssb.append(AccountSessionManager.getInstance().getAccount(accountID).domain);
}
ssb.append(" ");
Drawable botIcon=username.getResources().getDrawable(R.drawable.ic_bot, getActivity().getTheme()).mutate();
botIcon.setBounds(0, 0, botIcon.getIntrinsicWidth(), botIcon.getIntrinsicHeight());
botIcon.setTint(username.getCurrentTextColor());
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(botIcon, ImageSpan.ALIGN_BASELINE), 0);
username.setText(ssb);
}else{
// noinspection SetTextI18n
username.setText('@'+account.acct+(isSelf ? ('@'+AccountSessionManager.getInstance().getAccount(accountID).domain) : ""));
@@ -560,8 +521,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
bio.setVisibility(View.VISIBLE);
bio.setText(parsedBio);
}
followersCount.setText(UiUtils.abbreviateNumber(account.followersCount));
followingCount.setText(UiUtils.abbreviateNumber(account.followingCount));
postsCount.setText(UiUtils.abbreviateNumber(account.statusesCount));
@@ -603,9 +562,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
fields.add(field);
}
if(aboutFragment!=null){
aboutFragment.setFields(fields);
}
setFields(fields);
}
private void updateToolbar(){
@@ -641,11 +598,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
if(relationship==null && !isOwnProfile)
return;
inflater.inflate(isOwnProfile ? R.menu.profile_own : R.menu.profile, menu);
if(isOwnProfile){
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.scheduled, R.id.bookmarks, R.id.favorites);
}else{
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags, R.id.favorites, R.id.scheduled);
}
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags);
menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getShortUsername()));
if(isOwnProfile)
return;
@@ -778,17 +731,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
notifyProgress.setIndeterminateTintList(notifyButton.getTextColors());
followsYouView.setVisibility(relationship.followedBy ? View.VISIBLE : View.GONE);
notifyButton.setSelected(relationship.notifying);
if (!isOwnProfile) {
setNote(relationship.note);
aboutFragment.setNote(relationship.note, accountID, profileAccountID);
}
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
}
public ImageButton getFab() {
return fab;
}
private void onScrollChanged(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY){
int topBarsH=getToolbar().getHeight()+statusBarHeight;
if(scrollY>avatarBorder.getTop()-topBarsH){
@@ -809,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);
@@ -827,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();
};
}
@@ -892,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();
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();
@@ -913,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);
@@ -924,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(){
@@ -935,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);
@@ -953,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();
}
@@ -974,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){
@@ -1013,9 +957,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@Override
public boolean onBackPressed(){
if(noteEdit.hasFocus()) {
savePrivateNote();
}
if(isInEditMode){
exitEditMode();
return true;
@@ -1148,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;
}
}
}

View File

@@ -13,7 +13,6 @@ import org.joinmastodon.android.api.requests.statuses.CreateStatus;
import org.joinmastodon.android.api.requests.statuses.GetScheduledStatuses;
import org.joinmastodon.android.events.ScheduledStatusCreatedEvent;
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.ScheduledStatus;
import org.joinmastodon.android.model.Status;
@@ -29,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
@@ -57,20 +56,30 @@ 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);
}
@Override
protected List<StatusDisplayItem> buildDisplayItems(ScheduledStatus s) {
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null, true, Filter.FilterContext.HOME);
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null, true);
}
@Override

View File

@@ -21,8 +21,6 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -45,16 +43,19 @@ 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;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.TextInputFrameLayout;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import org.parceler.Parcels;
@@ -66,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;
@@ -113,21 +113,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
items.add(new HeaderItem(R.string.settings_theme));
items.add(themeItem=new ThemeItem());
items.add(new SwitchItem(R.string.theme_true_black, R.drawable.ic_fluent_dark_theme_24_regular, GlobalUserPreferences.trueBlackTheme, this::onTrueBlackThemeChanged));
items.add(new SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i->{
GlobalUserPreferences.disableMarquee=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i->{
GlobalUserPreferences.uniformNotificationIcon=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i->{
GlobalUserPreferences.reduceMotion=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new ButtonItem(R.string.sk_settings_color_palette, R.drawable.ic_fluent_color_24_regular, b->{
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.color_palettes);
@@ -144,41 +129,43 @@ public class SettingsFragment extends MastodonToolbarFragment{
case BROWN -> R.string.sk_color_palette_brown;
case RED -> R.string.sk_color_palette_red;
case YELLOW -> R.string.sk_color_palette_yellow;
case NORD -> R.string.mo_color_palette_nord;
});
}));
items.add(new ButtonItem(R.string.sk_settings_publish_button_text, R.drawable.ic_fluent_send_24_regular, b-> {
items.add(new ButtonItem(R.string.sk_settings_publish_button_text, R.drawable.ic_fluent_send_24_regular, b->{
updatePublishText(b);
if (GlobalUserPreferences.relocatePublishButton) {
b.setOnClickListener(l -> {
Toast.makeText(getActivity(), R.string.mo_disable_relocate_publish_button_to_enable_customization,
Toast.LENGTH_LONG).show();
});
} else {
b.setOnClickListener(l -> {
FrameLayout inputWrap = new FrameLayout(getContext());
EditText input = new EditText(getContext());
input.setHint(R.string.publish);
input.setText(GlobalUserPreferences.publishButtonText.trim());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(V.dp(16), V.dp(4), V.dp(16), V.dp(16));
input.setLayoutParams(params);
inputWrap.addView(input);
new M3AlertDialogBuilder(getContext()).setTitle(R.string.sk_settings_publish_button_text_title).setView(inputWrap)
.setPositiveButton(R.string.save, (d, which) -> {
GlobalUserPreferences.publishButtonText = input.getText().toString().trim();
GlobalUserPreferences.save();
updatePublishText(b);
})
.setNeutralButton(R.string.clear, (d, which) -> {
GlobalUserPreferences.publishButtonText = "";
GlobalUserPreferences.save();
updatePublishText(b);
})
.setNegativeButton(R.string.cancel, (d, which) -> {
})
.show();
});}
b.setOnClickListener(l->{
TextInputFrameLayout input = new TextInputFrameLayout(
getContext(),
getString(R.string.publish),
GlobalUserPreferences.publishButtonText.trim()
);
new M3AlertDialogBuilder(getContext()).setTitle(R.string.sk_settings_publish_button_text_title).setView(input)
.setPositiveButton(R.string.save, (d, which) -> {
GlobalUserPreferences.publishButtonText = input.getEditText().getText().toString().trim();
GlobalUserPreferences.save();
updatePublishText(b);
})
.setNeutralButton(R.string.clear, (d, which) -> {
GlobalUserPreferences.publishButtonText = "";
GlobalUserPreferences.save();
updatePublishText(b);
})
.setNegativeButton(R.string.cancel, (d, which) -> {})
.show();
});
}));
items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i->{
GlobalUserPreferences.uniformNotificationIcon=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i->{
GlobalUserPreferences.disableMarquee=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i->{
GlobalUserPreferences.reduceMotion=i.checked;
GlobalUserPreferences.save();
}));
items.add(new HeaderItem(R.string.settings_behavior));
@@ -203,34 +190,23 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.save();
needAppRestart=true;
}));
// items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged));
items.add(new SwitchItem(R.string.mo_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{
GlobalUserPreferences.disableDividers=i.checked;
items.add(new SwitchItem(R.string.sk_enable_delete_notifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, GlobalUserPreferences.enableDeleteNotifications, i->{
GlobalUserPreferences.enableDeleteNotifications=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.mo_hide_compose_button_while_scrolling_setting, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.enableFabAutoHide, i->{
GlobalUserPreferences.enableFabAutoHide =i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.mo_relocate_publish_button, R.drawable.ic_fluent_arrow_autofit_down_24_regular, GlobalUserPreferences.relocatePublishButton, i->{
GlobalUserPreferences.relocatePublishButton=i.checked;
items.add(new SwitchItem(R.string.sk_settings_disable_alt_text_reminder, R.drawable.ic_fluent_image_alt_text_24_regular, GlobalUserPreferences.disableAltTextReminder, i->{
GlobalUserPreferences.disableAltTextReminder=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
GlobalUserPreferences.keepOnlyLatestNotification=i.checked;
GlobalUserPreferences.save();
}));
// items.add(new SwitchItem(R.string.sk_settings_translate_only_opened, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
// GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
// GlobalUserPreferences.save();
// }));
// items.add(new SwitchItem(R.string.sk_settings_hide_translate_in_timeline, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
// GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
// GlobalUserPreferences.save();
// needAppRestart=true;
// }));
items.add(new SwitchItem(R.string.sk_settings_prefix_reply_cw_with_re, R.drawable.ic_fluent_arrow_reply_24_regular, GlobalUserPreferences.prefixRepliesWithRe, i->{
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->{
@@ -251,22 +227,36 @@ public class SettingsFragment extends MastodonToolbarFragment{
if (list.findViewHolderForAdapterPosition(items.indexOf(showNewPostsButtonItem)) instanceof SwitchViewHolder svh) svh.rebind();
GlobalUserPreferences.save();
}));
items.add(showNewPostsButtonItem = new SwitchItem(R.string.sk_settings_show_new_posts_button, R.drawable.ic_fluent_arrow_up_24_regular, GlobalUserPreferences.showNewPostsButton, i->{
items.add(showNewPostsButtonItem = new SwitchItem(R.string.sk_settings_see_new_posts_button, R.drawable.ic_fluent_arrow_up_24_regular, GlobalUserPreferences.showNewPostsButton, i->{
GlobalUserPreferences.showNewPostsButton=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_show_alt_indicator, R.drawable.ic_fluent_scan_text_24_regular, GlobalUserPreferences.showAltIndicator, i->{
GlobalUserPreferences.showAltIndicator=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_settings_show_no_alt_indicator, R.drawable.ic_fluent_important_24_regular, GlobalUserPreferences.showNoAltIndicator, i->{
GlobalUserPreferences.showNoAltIndicator=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_collapse_long_posts, R.drawable.ic_fluent_chevron_down_24_filled, GlobalUserPreferences.collapseLongPosts, i->{
GlobalUserPreferences.collapseLongPosts=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_spectator_mode, 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();
needAppRestart=true;
}));
boolean translationAvailable = instance.v2 != null && instance.v2.configuration.translation != null && instance.v2.configuration.translation.enabled;
items.add(new SmallTextItem(getString(translationAvailable ?
R.string.sk_settings_translation_availability_note_available :
R.string.sk_settings_translation_availability_note_unavailable, instanceName)));
items.add(new HeaderItem(R.string.settings_notifications));
items.add(notificationPolicyItem=new NotificationPolicyItem());
@@ -325,27 +315,9 @@ public class SettingsFragment extends MastodonToolbarFragment{
glitchModeItem.enabled = GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID);
items.add(new SmallTextItem(getString(R.string.sk_settings_glitch_mode_explanation)));
boolean translationAvailable = instance.v2 != null && instance.v2.configuration.translation != null && instance.v2.configuration.translation.enabled;
items.add(new SmallTextItem(getString(translationAvailable ?
R.string.sk_settings_translation_availability_note_available :
R.string.sk_settings_translation_availability_note_unavailable, instance.title)));
items.add(new HeaderItem(R.string.sk_settings_about));
if (GithubSelfUpdater.needSelfUpdating()) {
checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
items.add(checkForUpdateItem);
items.add(new SwitchItem(R.string.sk_updater_enable_pre_releases, 0, GlobalUserPreferences.enablePreReleases, i->{
GlobalUserPreferences.enablePreReleases=i.checked;
GlobalUserPreferences.save();
}));
}
items.add(new TextItem(R.string.mo_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon"), R.drawable.ic_fluent_open_24_regular));
items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sponsors/LucasGGamerM"), R.drawable.ic_fluent_heart_24_regular));
items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon"), R.drawable.ic_fluent_open_24_regular));
items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://ko-fi.com/xsk22"), R.drawable.ic_fluent_heart_24_regular));
LruCache<?, ?> cache = imageCache == null ? null : imageCache.getLruCache();
clearImageCacheItem = new TextItem(R.string.settings_clear_cache, UiUtils.formatFileSize(getContext(), cache != null ? cache.size() : 0, true), this::clearImageCache, 0);
items.add(clearImageCacheItem);
@@ -353,14 +325,29 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.recentLanguages.remove(accountID);
GlobalUserPreferences.save();
})));
if (GithubSelfUpdater.needSelfUpdating()) {
items.add(new SwitchItem(R.string.sk_updater_enable_pre_releases, 0, GlobalUserPreferences.enablePreReleases, i->{
GlobalUserPreferences.enablePreReleases=i.checked;
GlobalUserPreferences.save();
}));
checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
items.add(checkForUpdateItem);
}
items.add(new TextItem(R.string.mo_clear_recent_emoji, ()-> {
GlobalUserPreferences.recentEmojis.clear();
GlobalUserPreferences.save();
}));
// items.add(new TextItem(R.string.log_out, this::confirmLogOut));
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.mo_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
}
private void updatePublishText(Button btn) {
@@ -448,7 +435,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
else if (id == R.id.brown_color) pref = ColorPreference.BROWN;
else if (id == R.id.red_color) pref = ColorPreference.RED;
else if (id == R.id.yellow_color) pref = ColorPreference.YELLOW;
else if (id == R.id.nord_color) pref = ColorPreference.NORD;
if (pref == null) return false;
@@ -458,7 +444,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
return true;
}
private void onTrueBlackThemeChanged(SwitchItem item){
GlobalUserPreferences.trueBlackTheme=item.checked;
GlobalUserPreferences.save();
@@ -525,12 +510,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
needUpdateNotificationSettings=true;
}
private void onNotificationStyleChanged(SwitchItem item){
GlobalUserPreferences.uniformNotificationIcon=item.checked;
GlobalUserPreferences.save();
}
private void onNotificationsPolicyChanged(PushSubscription.Policy policy){
PushSubscription subscription=getPushSubscription();
PushSubscription.Policy prevPolicy=subscription.policy;
@@ -645,7 +624,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
this.text=getString(text);
}
public HeaderItem(String text) {
public HeaderItem(String text){
this.text=text;
}
@@ -700,13 +679,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
}
public class ColorPicker extends Item{
@Override
public int getViewType(){
return 8;
}
}
private static class ThemeItem extends Item{
@Override
@@ -763,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;
@@ -775,6 +752,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
super(text);
}
public RedHeaderItem(String text){
super(text);
}
@Override
public int getViewType(){
return 5;
@@ -951,7 +932,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
}
}
private class ButtonViewHolder extends BindableViewHolder<ButtonItem>{
private final Button button;
private final ImageView icon;
@@ -1115,10 +1095,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
if (state == GithubSelfUpdater.UpdateState.CHECKING) return;
GithubSelfUpdater.UpdateInfo info=updater.getUpdateInfo();
if(state!=GithubSelfUpdater.UpdateState.DOWNLOADED){
text.setText(getString(R.string.mo_update_available, info.version));
text.setText(getString(R.string.sk_update_available, info.version));
button.setText(getString(R.string.download_update, UiUtils.formatFileSize(getActivity(), info.size, false)));
}else{
text.setText(getString(R.string.mo_update_ready, info.version));
text.setText(getString(R.string.sk_update_ready, info.version));
button.setText(R.string.install_update);
}
if(state==GithubSelfUpdater.UpdateState.DOWNLOADING){
@@ -1135,7 +1115,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
progress.removeCallbacks(progressUpdater);
}
changelog.setText(info.changelog);
// changelog.setText(getString(R.string.sk_changelog, info.changelog));
}
private void updateProgress(){

View File

@@ -6,7 +6,6 @@ import android.view.View;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetStatusEditHistory;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
@@ -56,7 +55,7 @@ public class StatusEditHistoryFragment extends StatusListFragment{
@Override
protected List<StatusDisplayItem> buildDisplayItems(Status s){
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null, Filter.FilterContext.HOME);
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null);
int idx=data.indexOf(s);
if(idx>=0){
String date=UiUtils.DATE_TIME_FORMATTER.format(s.createdAt.atZone(ZoneId.systemDefault()));

View File

@@ -6,6 +6,7 @@ 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;
@@ -31,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, Filter.FilterContext.HOME);
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

View File

@@ -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){

View File

@@ -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();
}

View File

@@ -15,6 +15,7 @@ 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.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.model.Account;
@@ -48,7 +49,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop{
public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop {
private String accountID;
private Map<String, Relationship> relationships=Collections.emptyMap();
private GetAccountRelationships relationshipsRequest;
@@ -139,6 +140,11 @@ public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccou
smoothScrollRecyclerViewToTop(list);
}
@Override
public boolean isOnTop() {
return isRecyclerViewOnTop(list);
}
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
public AccountsAdapter(){

View File

@@ -1,7 +1,6 @@
package org.joinmastodon.android.fragments.discover;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
@@ -18,11 +17,10 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.fragments.ListTimelinesFragment;
import org.joinmastodon.android.ui.SimpleViewHolder;
import org.joinmastodon.android.ui.tabs.TabLayout;
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
@@ -38,7 +36,7 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
import me.grishka.appkit.fragments.OnBackPressedListener;
import me.grishka.appkit.utils.V;
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener{
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener, IsOnTop {
private TabLayout tabLayout;
private ViewPager2 pager;
@@ -55,15 +53,10 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
private DiscoverNewsFragment newsFragment;
private DiscoverAccountsFragment accountsFragment;
private SearchFragment searchFragment;
private LocalTimelineFragment localTimelineFragment;
private FederatedTimelineFragment federatedTimelineFragment;
private ListTimelinesFragment listTimelinesFragment;
private String accountID;
private Runnable searchDebouncer=this::onSearchChangedDebounced;
// private final boolean noFederated = !GlobalUserPreferences.showFederatedTimeline;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -81,22 +74,9 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
tabLayout=view.findViewById(R.id.tabbar);
pager=view.findViewById(R.id.pager);
// tabViews=new FrameLayout[noFederated ? 5 : 6];
tabViews=new FrameLayout[4];
for(int i=0;i<tabViews.length;i++){
FrameLayout tabView=new FrameLayout(getActivity());
/// int switchIndex = noFederated && i > 0 ? i + 1 : i;
// tabView.setId(switch(switchIndex){
// case 0 -> R.id.discover_local_timeline;
// case 1 -> R.id.discover_federated_timeline;
// case 2 -> R.id.discover_hashtags;
// case 3 -> R.id.discover_posts;
// case 4 -> R.id.discover_news;
// case 5 -> R.id.discover_users;
// default -> throw new IllegalStateException("Unexpected value: "+switchIndex);
// });
tabView.setId(switch(i){
case 0 -> R.id.discover_hashtags;
case 1 -> R.id.discover_posts;
@@ -104,7 +84,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
case 3 -> R.id.discover_users;
default -> throw new IllegalStateException("Unexpected value: "+i);
});
tabView.setVisibility(View.GONE);
view.addView(tabView); // needed so the fragment manager will have somewhere to restore the tab fragment
tabViews[i]=tabView;
@@ -130,7 +109,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
}
});
if(localTimelineFragment==null || hashtagsFragment==null){
if(hashtagsFragment==null){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putBoolean("__is_tab", true);
@@ -147,27 +126,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
accountsFragment=new DiscoverAccountsFragment();
accountsFragment.setArguments(args);
localTimelineFragment=new LocalTimelineFragment();
localTimelineFragment.setArguments(args);
// listTimelinesFragment=new ListTimelinesFragment();
// listTimelinesFragment.setArguments(args);
//
// FragmentTransaction transaction = getChildFragmentManager().beginTransaction()
// .add(R.id.discover_posts, postsFragment)
// .add(R.id.discover_local_timeline, localTimelineFragment)
// .add(R.id.discover_hashtags, hashtagsFragment)
// .add(R.id.discover_news, newsFragment)
// .add(R.id.discover_users, accountsFragment)
// .add(R.id.discover_lists, listTimelinesFragment);
//
// if (!noFederated) {
// federatedTimelineFragment=new FederatedTimelineFragment();
// federatedTimelineFragment.setArguments(args);
// transaction.add(R.id.discover_federated_timeline, federatedTimelineFragment);
// }
//
// transaction.commit();
getChildFragmentManager().beginTransaction()
.add(R.id.discover_posts, postsFragment)
@@ -180,21 +138,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
tabLayoutMediator=new TabLayoutMediator(tabLayout, pager, new TabLayoutMediator.TabConfigurationStrategy(){
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position){
// if (noFederated && position > 0) position++;
// tab.setText(switch(position){
// case 0 -> R.string.local_timeline;
// case 1 -> R.string.sk_federated_timeline;
// case 2 -> R.string.sk_list_timelines;
// case 3 -> R.string.hashtags;
// case 4 -> R.string.posts;
// case 5 -> R.string.news;
// case 6 -> R.string.for_you;
//
// default -> throw new IllegalStateException("Unexpected value: "+position);
// });
tab.setText(switch(position){
case 0 -> R.string.hashtags;
case 1 -> R.string.posts;
@@ -284,12 +227,26 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
}
}
@Override
public boolean isOnTop() {
return searchActive ? searchFragment.isOnTop()
: ((IsOnTop)getFragmentForPage(pager.getCurrentItem())).isOnTop();
}
public void onSelect() {
if (isOnTop()) selectSearch();
else scrollToTop();
}
private void selectSearch() {
searchEdit.requestFocus();
onSearchEditFocusChanged(searchEdit, true);
getActivity().getSystemService(InputMethodManager.class).showSoftInput(searchEdit, 0);
}
public void loadData(){
if(hashtagsFragment!=null && !hashtagsFragment.loaded && !hashtagsFragment.dataLoading)
hashtagsFragment.loadData();
// if(localTimelineFragment!=null && !localTimelineFragment.loaded && !localTimelineFragment.dataLoading)
// localTimelineFragment.loadData();
}
private void onSearchEditFocusChanged(View v, boolean hasFocus){
@@ -324,19 +281,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
}
private Fragment getFragmentForPage(int page){
// if (noFederated && page > 0) page++;
// return switch(page){
// case 0 -> localTimelineFragment;
// case 1 -> federatedTimelineFragment;
// case 2 -> hashtagsFragment;
// case 3 -> postsFragment;
// case 4 -> newsFragment;
// case 5 -> accountsFragment;
// case 6 -> listTimelinesFragment;
// default -> throw new IllegalStateException("Unexpected value: "+page);
// };
return switch(page){
case 0 -> hashtagsFragment;
case 1 -> postsFragment;
@@ -398,10 +342,4 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
return position;
}
}
public void selectSearch(){
searchEdit.requestFocus();
onSearchEditFocusChanged(searchEdit, true);
getActivity().getSystemService(InputMethodManager.class).showSoftInput(searchEdit, 0);
}
}

View File

@@ -10,6 +10,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.trends.GetTrendingLinks;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.ui.DividerItemDecoration;
@@ -34,7 +35,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements ScrollableToTop{
public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements ScrollableToTop, IsOnTop {
private String accountID;
private List<ImageLoaderRequest> imageRequests=Collections.emptyList();
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS);
@@ -82,6 +83,11 @@ public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements
smoothScrollRecyclerViewToTop(list);
}
@Override
public boolean isOnTop() {
return isRecyclerViewOnTop(list);
}
private class LinksAdapter extends UsableRecyclerView.Adapter<LinkViewHolder> implements ImageLoaderRecyclerAdapter{
public LinksAdapter(){
super(imgLoader);

View File

@@ -4,15 +4,19 @@ import android.os.Bundle;
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;
public class DiscoverPostsFragment extends StatusListFragment{
public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop {
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_POSTS);
@Override
@@ -22,6 +26,7 @@ public class DiscoverPostsFragment extends StatusListFragment{
@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);
@@ -32,4 +37,9 @@ public class DiscoverPostsFragment extends StatusListFragment{
super.onViewCreated(view, savedInstanceState);
bannerHelper.maybeAddBanner(contentWrap);
}
@Override
public boolean isOnTop() {
return isRecyclerViewOnTop(list);
}
}

View File

@@ -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);
@@ -39,6 +45,6 @@ public class FederatedTimelineFragment extends FabStatusListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
// bannerHelper.maybeAddBanner(contentWrap);
bannerHelper.maybeAddBanner(contentWrap);
}
}

View File

@@ -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 {
// private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.LOCAL_TIMELINE);
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);
@@ -39,6 +44,6 @@ public class LocalTimelineFragment extends FabStatusListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
// bannerHelper.maybeAddBanner(contentWrap);
bannerHelper.maybeAddBanner(contentWrap);
}
}

View File

@@ -11,10 +11,10 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.SearchResults;
@@ -38,11 +38,10 @@ 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.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.V;
public class SearchFragment extends BaseStatusListFragment<SearchResult>{
public class SearchFragment extends BaseStatusListFragment<SearchResult> implements IsOnTop {
private String currentQuery;
private List<StatusDisplayItem> prevDisplayItems;
private EnumSet<SearchResult.Type> currentFilter=EnumSet.allOf(SearchResult.Type.class);
@@ -81,7 +80,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
return switch(s.type){
case ACCOUNT -> Collections.singletonList(new AccountStatusDisplayItem(s.id, this, s.account));
case HASHTAG -> Collections.singletonList(new HashtagStatusDisplayItem(s.id, this, s.hashtag));
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, false, true, null, Filter.FilterContext.PUBLIC);
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, false, true, null);
};
}
@@ -185,7 +184,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
return;
}
UiUtils.updateList(prevDisplayItems, displayItems, list, adapter, (i1, i2)->i1.parentID.equals(i2.parentID) && i1.index==i2.index && i1.getType()==i2.getType());
boolean recent=isInRecentMode();
boolean recent=isInRecentMode() && !displayItems.isEmpty();
if(recent!=headerAdapter.isVisible())
headerAdapter.setVisible(recent);
imgLoader.forceUpdateImages();
@@ -311,6 +310,11 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
}
}
@Override
public boolean isOnTop() {
return isRecyclerViewOnTop(list);
}
@FunctionalInterface
public interface ProgressVisibilityListener{
void onProgressVisibilityChanged(boolean visible);

View File

@@ -7,6 +7,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.trends.GetTrendingHashtags;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.ui.DividerItemDecoration;
@@ -23,7 +24,7 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.views.UsableRecyclerView;
public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop{
public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop {
private String accountID;
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_HASHTAGS);
@@ -67,6 +68,11 @@ public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> impl
smoothScrollRecyclerViewToTop(list);
}
@Override
public boolean isOnTop() {
return isRecyclerViewOnTop(list);
}
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
@NonNull
@Override

View File

@@ -96,9 +96,9 @@ public class AccountActivationFragment extends ToolbarFragment{
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
}
// @Override
@Override
protected void onUpdateToolbar(){
// super.onUpdateToolbar();
super.onUpdateToolbar();
getToolbar().setBackground(null);
getToolbar().setElevation(0);
}
@@ -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(), OnboardingProfileSetupFragment.class, args);
}
}

View File

@@ -140,8 +140,8 @@ public class CustomWelcomeFragment extends InstanceCatalogFragment {
headerView.findViewById(R.id.separator).setVisibility(View.GONE);
headerView.findViewById(R.id.timestamp).setVisibility(View.GONE);
headerView.findViewById(R.id.unread_indicator).setVisibility(View.GONE);
((TextView) headerView.findViewById(R.id.username)).setText(R.string.mo_app_username);
((TextView) headerView.findViewById(R.id.name)).setText(R.string.mo_app_name);
((TextView) headerView.findViewById(R.id.username)).setText(R.string.sk_app_username);
((TextView) headerView.findViewById(R.id.name)).setText(R.string.sk_app_name);
((ImageView) headerView.findViewById(R.id.avatar)).setImageDrawable(getActivity().getDrawable(R.mipmap.ic_launcher));
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(this);

View File

@@ -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

View File

@@ -92,7 +92,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,7 +106,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
}
protected void onSearchChangedDebounced(){
currentSearchQuery=searchEdit.getText().toString().toLowerCase();
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
updateFilteredList();
loadInstanceInfo(currentSearchQuery, false);
}

View File

@@ -527,6 +527,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);

View File

@@ -106,13 +106,13 @@ public class InstanceChooserLoginFragment extends InstanceCatalogFragment{
.execNoAuth("");
}
// @Override
// protected void onUpdateToolbar(){
// super.onUpdateToolbar();
// Toolbar toolbar=getToolbar();
// toolbar.setElevation(0);
// toolbar.setBackground(null);
// }
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
Toolbar toolbar=getToolbar();
toolbar.setElevation(0);
toolbar.setBackground(null);
}
@Override
protected RecyclerView.Adapter getAdapter(){

View File

@@ -70,7 +70,7 @@ public class InstanceRulesFragment extends ToolbarFragment{
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
adapter.addAdapter(new ItemsAdapter());
list.setAdapter(adapter);
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorM3SurfaceVariant, 1, 56, 0, DividerItemDecoration.NOT_FIRST));
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 56, 0, DividerItemDecoration.NOT_FIRST));
btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(v->onButtonClick());
@@ -84,8 +84,8 @@ public class InstanceRulesFragment extends ToolbarFragment{
@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));
// 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 File

@@ -0,0 +1,350 @@
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){
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(), HomeFragment.class, args);
getActivity().getWindow().getDecorView().postDelayed(()->Nav.finish(this), 500);
}
@Override
protected boolean canGoBack(){
return true;
}
@Override
public void onToolbarNavigationClick(){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
}
private class SuggestionsAdapter extends UsableRecyclerView.Adapter<SuggestionViewHolder> implements ImageLoaderRecyclerAdapter{
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);
}
}
}

View File

@@ -0,0 +1,237 @@
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.go(getActivity(), OnboardingFollowSuggestionsFragment.class, args);
getActivity().getWindow().getDecorView().postDelayed(()->Nav.finish(OnboardingProfileSetupFragment.this), 500);
}
@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;
});
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));
}
@Override
protected boolean canGoBack(){
return true;
}
@Override
public void onToolbarNavigationClick(){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
}
}

View File

@@ -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
@Override
protected void onUpdateToolbar(){
// super.onUpdateToolbar();
getToolbar().setBackground(null);
super.onUpdateToolbar();
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;

View File

@@ -21,7 +21,6 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.PhotoLayoutHelper;
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
@@ -239,7 +238,7 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
@Override
protected List<StatusDisplayItem> buildDisplayItems(Status s){
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null, Filter.FilterContext.HOME);
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null);
for(StatusDisplayItem item:items){
if(item instanceof ImageStatusDisplayItem isdi){
isdi.horizontalInset=V.dp(40+32);

View File

@@ -9,6 +9,7 @@ import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
@@ -28,15 +29,17 @@ 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.utils.V;
public class ReportCommentFragment extends MastodonToolbarFragment{
private String accountID;
private Account reportAccount;
private Button btn;
private View buttonBar;
private View buttonBar, forwardReportItem;
private TextView forwardReportText;
private Switch forwardReportSwitch;
private EditText commentEdit;
private boolean forwardReport;
@Override
public void onCreate(Bundle savedInstanceState){
@@ -77,7 +80,17 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
view.findViewById(R.id.btn_back).setOnClickListener(this::onButtonClick);
buttonBar=view.findViewById(R.id.button_bar);
commentEdit=view.findViewById(R.id.text);
forwardReportSwitch = view.findViewById(R.id.forward_report_switch);
forwardReportItem = view.findViewById(R.id.forward_report);
forwardReportText = view.findViewById(R.id.forward_report_text);
String domain = reportAccount.getDomain();
if (domain == null) {
forwardReportItem.setVisibility(View.GONE);
} else {
forwardReportItem.setOnClickListener(this::onForwardReportClick);
forwardReportText.setText(getActivity().getString(R.string.sk_forward_report_to, domain));
forwardReportSwitch.setChecked(forwardReport = true);
}
return view;
}
@@ -102,7 +115,7 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
ReportReason reason=ReportReason.valueOf(getArguments().getString("reason"));
ArrayList<String> statusIDs=getArguments().getStringArrayList("statusIDs");
ArrayList<String> ruleIDs=getArguments().getStringArrayList("ruleIDs");
new SendReport(reportAccount.id, reason, statusIDs, ruleIDs, v.getId()==R.id.btn_back ? null : commentEdit.getText().toString(), true)
new SendReport(reportAccount.id, reason, statusIDs, ruleIDs, v.getId()==R.id.btn_back ? null : commentEdit.getText().toString(), forwardReport)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Object result){
@@ -123,6 +136,11 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
.exec(accountID);
}
private void onForwardReportClick(View v) {
forwardReport = !forwardReport;
forwardReportSwitch.setChecked(forwardReport);
}
@Subscribe
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
if(ev.reportAccountID.equals(reportAccount.id))

View File

@@ -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{

View File

@@ -18,9 +18,8 @@ public class Filter extends BaseModel{
@RequiredField
public String id;
@RequiredField
public String title;
@RequiredField
public String phrase;
public String title;
public transient EnumSet<FilterContext> context=EnumSet.noneOf(FilterContext.class);
public Instant expiresAt;
public boolean irreversible;
@@ -52,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();
}
@@ -80,7 +80,9 @@ public class Filter extends BaseModel{
@SerializedName("public")
PUBLIC,
@SerializedName("thread")
THREAD
THREAD,
@SerializedName("account")
ACCOUNT
}
public enum FilterAction{

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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{"+

View File

@@ -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;
}

View File

@@ -20,7 +20,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
public Instant createdAt;
@RequiredField
public Account account;
// @RequiredField
// @RequiredField
public String content;
@RequiredField
public StatusPrivacy visibility;
@@ -58,9 +58,9 @@ public class Status extends BaseModel implements DisplayItemsParent{
public boolean bookmarked;
public boolean pinned;
public boolean filterRevealed;
public transient boolean filterRevealed;
public transient boolean spoilerRevealed;
public transient boolean textExpanded, textExpandable;
public transient boolean hasGapAfter;
private transient String strippedText;
@@ -160,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;
}
}

View File

@@ -1,7 +1,7 @@
package org.joinmastodon.android.model;
public class TranslatedStatus extends BaseModel {
public String content;
public String detectedSourceLanguage;
public String provider;
public String content;
public String detectedSourceLanguage;
public String provider;
}

View File

@@ -24,7 +24,6 @@ import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.List;

View File

@@ -1,9 +1,8 @@
package org.joinmastodon.android.ui;
import static org.joinmastodon.android.GlobalUserPreferences.recentEmojis;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
@@ -13,13 +12,8 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.otto.Subscribe;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiUpdatedEvent;
@@ -27,13 +21,13 @@ import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
@@ -46,9 +40,6 @@ import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class CustomEmojiPopupKeyboard extends PopupKeyboard{
//determines how many emoji need to be clicked, before it disappears from the recent emojis
private static final int NEW_RECENT_VALUE=15;
private List<EmojiCategory> emojis;
private UsableRecyclerView list;
private ListImageLoaderWrapper imgLoader;
@@ -91,17 +82,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
list.setLayoutManager(lm);
imgLoader=new ListImageLoaderWrapper(activity, list, new RecyclerViewDelegate(list), null);
// inject category with last used emojis
if (!recentEmojis.isEmpty()) {
List<Emoji> allAvailableEmojis = emojis.stream().flatMap(category -> category.emojis.stream()).collect(Collectors.toList());
List<Emoji> recentEmojiList = new ArrayList<>();
for (String emojiCode : recentEmojis.keySet().stream().sorted(Comparator.comparingInt(GlobalUserPreferences.recentEmojis::get).reversed()).collect(Collectors.toList())) {
Optional<Emoji> element = allAvailableEmojis.stream().filter(e -> e.shortcode.equals(emojiCode)).findFirst();
element.ifPresent(recentEmojiList::add);
}
emojis.add(0, new EmojiCategory(activity.getString(R.string.mo_emoji_recent), recentEmojiList));
}
for(EmojiCategory category:emojis)
adapter.addAdapter(new SingleCategoryAdapter(category));
list.setAdapter(adapter);
@@ -120,11 +100,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
list.setBackgroundColor(UiUtils.getThemeColor(activity, android.R.attr.colorBackground));
list.setSelector(null);
//remove recently used afterwards, it would get duplicated otherwise
if (!recentEmojis.isEmpty()) {
emojis.remove(0);
}
return list;
}
@@ -132,19 +107,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
this.listener=listener;
}
private void increaseEmojiCount(Emoji emoji) {
Integer usageCount = recentEmojis.get(emoji.shortcode);
if (usageCount != null) {
recentEmojis.put(emoji.shortcode, usageCount + 1);
} else {
recentEmojis.put(emoji.shortcode, NEW_RECENT_VALUE);
}
recentEmojis.entrySet().removeIf(e -> e.getValue() <= 0);
recentEmojis.replaceAll((k, v) -> v - 1);
GlobalUserPreferences.save();
}
@SuppressLint("NotifyDataSetChanged")
@Subscribe
public void onEmojiUpdated(EmojiUpdatedEvent ev){
@@ -241,7 +203,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
@Override
public void onClick(){
increaseEmojiCount(item);
listener.accept(item);
}
}

View File

@@ -4,6 +4,7 @@ import android.app.AlertDialog;
import android.content.Context;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import me.grishka.appkit.utils.V;
@@ -31,8 +32,16 @@ public class M3AlertDialogBuilder extends AlertDialog.Builder{
if(titleID!=0){
View title=alert.findViewById(titleID);
if(title!=null){
int iconID=getContext().getResources().getIdentifier("icon", "id", "android");
int alertTitleID=getContext().getResources().getIdentifier("alertTitle", "id", "android");
if (alertTitleID != 0 && iconID != 0) {
ImageView icon = title.findViewById(iconID);
if (icon.getDrawable() != null) {
title.findViewById(alertTitleID).setPadding(V.dp(8), 0, 0, 0);
}
}
int pad=V.dp(24);
title.setPadding(pad, pad, pad, V.dp(18));
title.setPadding(pad, pad, pad, V.dp(12));
}
}
int titleDividerID=getContext().getResources().getIdentifier("titleDividerNoCustom", "id", "android");

View File

@@ -1,7 +1,6 @@
package org.joinmastodon.android.ui.displayitems;
import android.content.Context;
import android.os.Build;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewGroup;
@@ -10,7 +9,6 @@ import android.widget.SeekBar;
import android.widget.TextView;
import org.joinmastodon.android.AudioPlayerService;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Attachment;
@@ -105,7 +103,6 @@ public class AudioStatusDisplayItem extends StatusDisplayItem{
}else{
seekBar.setEnabled(false);
}
}
private void onPlayPauseClick(View v){
@@ -129,10 +126,6 @@ public class AudioStatusDisplayItem extends StatusDisplayItem{
lastKnownPositionTime=SystemClock.uptimeMillis();
this.playing=playing;
playPauseBtn.setImageResource(playing ? R.drawable.ic_fluent_pause_circle_24_filled : R.drawable.ic_fluent_play_circle_24_filled);
playPauseBtn.setContentDescription(MastodonApp.context.getResources().getString(playing ? R.string.pause : R.string.play));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
playPauseBtn.setTooltipText(playPauseBtn.getContentDescription());
}
if(!playing){
lastRemainingSeconds=-1;
time.setText(formatDuration((int) item.attachment.getDuration()));

View File

@@ -80,7 +80,7 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
editHistory.setVisibility(View.GONE);
}
String timeStr=TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault()));
if (item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)) {
time.setText(item.parentFragment.getString(R.string.timestamp_via_app, timeStr, ""));
applicationName.setText(item.status.application.name);
@@ -134,4 +134,4 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
Nav.go(item.parentFragment.getActivity(), StatusEditHistoryFragment.class, args);
}
}
}
}

View File

@@ -15,9 +15,6 @@ import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.BounceInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -61,8 +58,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private final TextView reply, boost, favorite, bookmark;
private final ImageView share;
private static final Animation opacityOut, opacityIn;
private static AnimationSet animSet;
private View touchingView = null;
private boolean longClickPerformed = false;
@@ -91,15 +86,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
opacityIn = new AlphaAnimation(0.55f, 1);
opacityIn.setDuration(400);
opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT);
Animation spin = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
animSet = new AnimationSet(true);
animSet.setInterpolator(CubicBezierInterpolator.DEFAULT);
animSet.addAnimation(spin);
animSet.addAnimation(opacityIn);
animSet.setDuration(400);
}
public Holder(Activity activity, ViewGroup parent){
@@ -153,7 +139,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
bookmark.setSelected(item.status.bookmarked);
boost.setEnabled(item.status.visibility==StatusPrivacy.PUBLIC || item.status.visibility==StatusPrivacy.UNLISTED || item.status.visibility==StatusPrivacy.LOCAL
|| (item.status.visibility==StatusPrivacy.PRIVATE && item.status.account.id.equals(AccountSessionManager.getInstance().getAccount(item.accountID).self.id)));
}
private void bindButton(TextView btn, long count){
@@ -311,15 +296,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void onFavoriteClick(View v){
favorite.setSelected(!item.status.favourited);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
if (item.status.favourited) {
if(GlobalUserPreferences.reduceMotion){
v.startAnimation(opacityIn);
}else{
v.startAnimation(animSet);
}
} else {
v.startAnimation(opacityIn);
}
v.startAnimation(opacityIn);
bindButton(favorite, r.favouritesCount);
});
}
@@ -386,4 +363,4 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
return 0;
}
}
}
}

View File

@@ -9,9 +9,6 @@ import android.os.Build;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
@@ -23,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;
@@ -140,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, botIcon;
private final View collapseBtn;
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, collapseBtnIcon;
private final PopupMenu optionsMenu;
private Relationship relationship;
private APIRequest<?> currentRelationshipRequest;
@@ -163,7 +163,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
visibility=findViewById(R.id.visibility);
deleteNotification=findViewById(R.id.delete_notification);
unreadIndicator=findViewById(R.id.unread_indicator);
botIcon=findViewById(R.id.bot_icon);
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);
@@ -175,11 +176,10 @@ 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);
optionsMenu.setOnMenuItemClickListener(menuItem->{
Account account=item.user;
int id=menuItem.getItemId();
@@ -277,29 +277,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
args.putString("profileDisplayUsername", account.getDisplayUsername());
Nav.go(item.parentFragment.getActivity(), ListTimelinesFragment.class, args);
}
if(!item.status.filterRevealed){
this.itemView.setVisibility(View.GONE);
ViewGroup.LayoutParams params = this.itemView.getLayoutParams();
params.height = 0;
params.width = 0;
this.itemView.setLayoutParams(params);
// item.parentFragment.notifyItemsChanged(this.getAbsoluteAdapterPosition());
}
return true;
});
UiUtils.enablePopupMenuIcons(activity, optionsMenu);
}
// public void setFilteredShown(){
// this.itemView.setVisibility(View.VISIBLE);
// params = this.itemView.getLayoutParams();
// params.height = 0;
// params.width = 0;
// this.itemView.setLayoutParams(params);
// }
private void populateAccountsMenu(Menu menu) {
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
sessions.stream().filter(s -> !s.getID().equals(item.accountID)).forEach(s -> {
@@ -315,8 +297,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
public void onBind(HeaderStatusDisplayItem item){
name.setText(item.parsedName);
username.setText('@'+item.user.acct);
botIcon.setVisibility(item.user.bot ? View.VISIBLE : View.GONE);
botIcon.setColorFilter(username.getCurrentTextColor());
separator.setVisibility(View.VISIBLE);
if (item.scheduledStatus!=null)
@@ -326,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)));
@@ -400,6 +380,16 @@ 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

View File

@@ -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

View File

@@ -73,7 +73,6 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
photo.setImageDrawable(null);
if(item.imgRequest!=null){
crossfadeDrawable.setSize(card.width, card.height);
if (card.width > 0) {
// akkoma servers don't provide width and height
crossfadeDrawable.setSize(card.width, card.height);
@@ -105,4 +104,3 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
}
}
}

View File

@@ -37,150 +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);
}
}
if(!item.status.filterRevealed){
this.itemView.setVisibility(View.GONE);
ViewGroup.LayoutParams params = this.itemView.getLayoutParams();
params.height = 0;
params.width = 0;
this.itemView.setLayoutParams(params);
// item.parentFragment.notifyItemsChanged(this.getAbsoluteAdapterPosition());
}
}
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;
}
});
}
}
}

View File

@@ -100,7 +100,6 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
if (visibilityText != 0) text.setContentDescription(item.text + " (" + ctx.getString(visibilityText) + ")");
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
UiUtils.fixCompoundDrawableTintOnAndroid6(text);
}
@Override

View File

@@ -8,7 +8,6 @@ import android.view.View;
import android.view.ViewGroup;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
@@ -81,34 +80,40 @@ public abstract class StatusDisplayItem{
case ACCOUNT -> new AccountStatusDisplayItem.Holder(activity, parent);
case HASHTAG -> new HashtagStatusDisplayItem.Holder(activity, parent);
case GAP -> new GapStatusDisplayItem.Holder(activity, parent);
case WARNING -> new WarningFilteredStatusDisplayItem.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, Filter.FilterContext filterContext){
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, 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, Filter.FilterContext 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){
String parentID=parentObject.getID();
ArrayList<StatusDisplayItem> items=new ArrayList<>();
ArrayList<StatusDisplayItem> filtered=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());
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->{
@@ -141,12 +146,11 @@ public abstract class StatusDisplayItem{
}
)));
}
HeaderStatusDisplayItem header;
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, notification, scheduledStatus));
if(!TextUtils.isEmpty(statusForContent.content)){
if(!TextUtils.isEmpty(statusForContent.content))
items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID), fragment, statusForContent, disableTranslate));
} else
else
header.needBottomPadding=true;
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream().filter(att->att.type.isImage()).collect(Collectors.toList());
if(!imageAttachments.isEmpty()){
@@ -178,20 +182,19 @@ public abstract class StatusDisplayItem{
}
if(addFooter){
items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID));
if(status.hasGapAfter && !(fragment instanceof ThreadFragment)){
if(status.hasGapAfter && !(fragment instanceof ThreadFragment))
items.add(new GapStatusDisplayItem(parentID, fragment));
}
}
int i=1;
for(StatusDisplayItem item:items){
item.inset=inset;
item.index=i++;
}
if(!statusForContent.filterRevealed){
filtered.add(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items));
return filtered;
if (!statusForContent.filterRevealed) {
return new ArrayList<>(List.of(
new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)
));
}
return items;

View File

@@ -3,15 +3,19 @@ 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;
import org.joinmastodon.android.api.requests.statuses.TranslateStatus;
import org.joinmastodon.android.api.session.AccountSession;
@@ -19,12 +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;
@@ -44,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);
@@ -81,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 Drawable backgroundColor, borderColor;
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);
@@ -101,28 +113,33 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
translateInfo=findViewById(R.id.translate_info);
translateProgress=findViewById(R.id.translate_progress);
itemView.setOnClickListener(v->item.parentFragment.onRevealSpoilerClick(this));
TypedValue outValue=new TypedValue();
activity.getTheme().resolveAttribute(R.attr.colorBackgroundLight, outValue, true);
backgroundColor=activity.getDrawable(outValue.resourceId);
// activity.getTheme().resolveAttribute(R.attr.colorBackgroundLightest, outValue, true);
// backgroundColorInset=activity.getDrawable(outValue.resourceId);
activity.getTheme().resolveAttribute(R.attr.colorPollVoted, outValue, true);
borderColor=activity.getDrawable(outValue.resourceId);
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
public void onBind(TextStatusDisplayItem item){
text.setText(item.translated
? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
: item.text);
? 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.setBackground(item.inset ? null : backgroundColor);
spoilerTitleInline.setBackgroundColor(item.inset ? 0 : backgroundColor);
spoilerTitleInline.setPadding(spoilerTitleInline.getPaddingLeft(), item.inset ? 0 : V.dp(14), spoilerTitleInline.getPaddingRight(), item.inset ? 0 : V.dp(14));
borderTop.setBackground(item.inset ? null : borderColor);
borderBottom.setBackground(item.inset ? null : borderColor);
borderTop.setBackgroundColor(item.inset ? 0 : borderColor);
borderBottom.setBackgroundColor(item.inset ? 0 : borderColor);
if(!TextUtils.isEmpty(item.status.spoilerText)){
spoilerTitle.setText(item.parsedSpoilerText);
spoilerTitleInline.setText(item.parsedSpoilerText);
@@ -149,18 +166,30 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null &&
instanceInfo.v2.configuration.translation.enabled;
translateWrap.setVisibility(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);
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))))
&& (!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();
@@ -190,6 +219,25 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
}
});
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

View File

@@ -3,60 +3,50 @@ package org.joinmastodon.android.ui.displayitems;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable;
import java.util.ArrayList;
import java.util.List;
// Mind the gap!
public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
public boolean loading;
public final Status status;
public ArrayList<StatusDisplayItem> filteredItems;
public boolean loading;
public final Status status;
public List<StatusDisplayItem> filteredItems;
public WarningFilteredStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status, ArrayList<StatusDisplayItem> items){
super(parentID, parentFragment);
this.status=status;
this.filteredItems = items;
}
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;
}
@Override
public Type getType(){
return Type.WARNING;
}
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
public final View warningWrap;
public final Button showBtn;
public final TextView text;
public ArrayList<StatusDisplayItem> filteredItems;
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_warning, parent);
warningWrap=findViewById(R.id.warning_wrap);
showBtn=findViewById(R.id.reveal_btn);
showBtn.setOnClickListener(i -> item.parentFragment.onWarningClick(this));
text=findViewById(R.id.text);
// itemView.setOnClickListener(v->item.parentFragment.onRevealFilteredClick(this));
}
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.mo_filtered, item.status.filtered.get(item.status.filtered.size() -1).filter.title));
}
@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(){
}
}
@Override
public void onClick() {
item.parentFragment.onWarningClick(this);
}
}
}

View File

@@ -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

View File

@@ -27,7 +27,6 @@ public class ClickableLinksDelegate {
if (selectedSpan != null) selectedSpan.onLongClick(view);
};
public ClickableLinksDelegate(TextView view) {
this.view=view;
hlPaint=new Paint();

View File

@@ -111,7 +111,7 @@ public class HtmlParser{
@Override
public void head(@NonNull Node node, int depth){
if(node instanceof TextNode textNode){
ssb.append(textNode.text());
ssb.append(textNode.getWholeText());
}else if(node instanceof Element el){
switch(el.nodeName()){
case "a" -> {

View File

@@ -1,10 +1,8 @@
package org.joinmastodon.android.ui.text;
import android.content.Context;
import android.content.Intent;
import android.text.TextPaint;
import android.text.style.CharacterStyle;
import android.util.Log;
import android.view.View;
import org.joinmastodon.android.ui.utils.UiUtils;
@@ -18,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;
@@ -34,24 +36,18 @@ public class LinkSpan extends CharacterStyle {
public void updateDrawState(TextPaint tp) {
tp.setColor(color=tp.linkColor);
}
public void onClick(Context context){
switch(getType()){
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);
}
}
public void onLongClick(View view) {
if (getType() == Type.URL) {
Intent shareIntent = new Intent(Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(Intent.EXTRA_TEXT, link);
view.getContext().startActivity(Intent.createChooser(shareIntent, null));
} else {
UiUtils.copyText(view, text);
}
UiUtils.copyText(view, getType() == Type.URL ? link : text);
}
public String getLink(){
@@ -73,6 +69,7 @@ public class LinkSpan extends CharacterStyle {
public enum Type{
URL,
MENTION,
HASHTAG
HASHTAG,
CUSTOM
}
}

View File

@@ -25,8 +25,7 @@ public class ColorPalette {
ColorPreference.BLUE, new ColorPalette(R.style.ColorPalette_Blue),
ColorPreference.BROWN, new ColorPalette(R.style.ColorPalette_Brown),
ColorPreference.RED, new ColorPalette(R.style.ColorPalette_Red),
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow),
ColorPreference.NORD, new ColorPalette(R.style.ColorPalette_Nord)
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
);
private @StyleRes int base;

View File

@@ -65,4 +65,4 @@ public class DiscoverInfoBannerHelper{
POST_NOTIFICATIONS,
// ACCOUNTS
}
}
}

View File

@@ -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);
}
}
}

Some files were not shown because too many files have changed in this diff Show More