Compare commits

..

735 Commits

Author SHA1 Message Date
sk
c8122aa65b fuck it, production release 2023-10-28 15:09:00 +02:00
sk
ef1584de55 merge upstream strings 2023-10-28 14:50:56 +02:00
sk
3075030b1c add todo 2023-10-27 17:38:54 +02:00
sk
42c56401db fix wrong check for gap item
re sk22#898
2023-10-27 17:34:47 +02:00
sk
a18a4383e5 update gap in database when deleting status
closes sk22#898
2023-10-27 17:19:59 +02:00
sk
375b5b3133 fix gaps not showing time
closes sk22#889
2023-10-27 16:14:16 +02:00
sk
4cab916957 move status list fragment check out of predicate 2023-10-27 16:02:14 +02:00
sk
7902691093 avoid index out of bounds
closes sk22#904
2023-10-27 01:28:27 +02:00
sk
d5d9e20a06 update strings 2023-10-26 18:53:40 +02:00
Codeberg Translate
1eb55428db Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/
2023-10-26 16:39:24 +00:00
reindex
9b82d704f6 Translated using Weblate (Japanese)
Currently translated at 11.1% (2 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ja/
2023-10-26 16:39:24 +00:00
reindex
dbf3d2776e Translated using Weblate (Japanese)
Currently translated at 86.4% (345 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ja/
2023-10-26 16:39:24 +00:00
Espasant3
c077b9d47c Translated using Weblate (Galician)
Currently translated at 98.4% (393 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-10-26 16:39:24 +00:00
kallekn
34157805a1 Translated using Weblate (Finnish)
Currently translated at 100.0% (399 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-10-26 16:39:24 +00:00
AiOO
576da2a3eb Translated using Weblate (Korean)
Currently translated at 99.2% (396 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-10-26 16:39:24 +00:00
SomeTr
e99e5b2836 Translated using Weblate (Ukrainian)
Currently translated at 99.7% (398 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-26 16:39:24 +00:00
Oliebol
fe25974958 Translated using Weblate (Dutch)
Currently translated at 91.7% (366 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-10-26 16:39:24 +00:00
Linerly
1a95b4e361 Translated using Weblate (Indonesian)
Currently translated at 100.0% (399 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-26 16:39:24 +00:00
Choukajohn
35e3d5afc4 Translated using Weblate (French)
Currently translated at 100.0% (399 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-26 16:39:24 +00:00
gallegonovato
cc1e13d1bd Translated using Weblate (Spanish)
Currently translated at 100.0% (399 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-26 16:39:24 +00:00
poesty
0b622f8f2a Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (398 of 399 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-26 16:39:24 +00:00
gallegonovato
9cf7da6419 Translated using Weblate (Spanish)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-26 16:39:24 +00:00
sk
812ab7198c revert, i said!
actually, the cached posts limit can stay
2023-10-26 18:38:06 +02:00
sk
e8c9253a76 don't remove gap when removing status
re: sk22#898
2023-10-26 18:32:46 +02:00
sk
c8f633ae3b don't hide gap behind warning
closes sk22#899
2023-10-26 18:23:56 +02:00
sk
af339a833f fix gap time being wrong when next status is own
closes sk22#902
2023-10-26 18:11:54 +02:00
sk
708142e1b8 Revert "refresh data from cache"
This reverts commit 60a998be89.
2023-10-26 17:53:36 +02:00
sk
55f32671c5 Revert "fix timeline breaking when max_id is null"
This reverts commit 289db09770.
2023-10-26 17:52:43 +02:00
sk
289db09770 fix timeline breaking when max_id is null 2023-10-25 14:42:35 +02:00
sk
89d7dfd694 don't globally remove status on refresh
closes sk22#896
2023-10-23 23:55:04 +02:00
sk
60a998be89 refresh data from cache 2023-10-23 01:00:26 +02:00
sk
128e75bc24 fix animatable avatars not playing in notification headers
closes sk22#882
2023-10-22 23:35:09 +02:00
sk
69c60d484c load custom emoji in reply header
closes sk22#886
2023-10-22 23:30:33 +02:00
sk
c70750a508 fix strings 2023-10-22 23:21:47 +02:00
sk
5553ca25a1 Merge remote-tracking branch 'upstream/l10n_master' 2023-10-22 23:10:56 +02:00
sk
ff87829e72 Merge remote-tracking branch 'weblate/main' 2023-10-22 23:09:45 +02:00
sk
02983c76b9 add mutuals follow button state
closes sk22#890
2023-10-22 23:09:35 +02:00
sk
3e28eb2ccf fix polls not updating when behind spoiler
closes sk22#892
2023-10-22 22:39:10 +02:00
sk
3cf23474e3 fix issue with too-wide context menu icons
closes sk22#893
2023-10-22 22:10:25 +02:00
sk
9f0ff2dcd4 fix editing scheduled/drafted polls
closes sk22#894
2023-10-22 21:44:02 +02:00
Eugen Rochko
8ed9fb6276 New translations strings.xml (Chinese Traditional) 2023-10-22 08:53:38 +02:00
SomeTr
df7a0ee490 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-10-21 20:53:12 +00:00
Espasant3
2e360dc275 Translated using Weblate (Galician)
Currently translated at 98.7% (393 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-10-21 20:53:12 +00:00
poesty
8dc88d2fd7 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (397 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-21 20:53:12 +00:00
Eugen Rochko
901c70efc3 New translations strings.xml (Icelandic) 2023-10-21 19:24:31 +02:00
Eugen Rochko
3d44e5d2cc New translations strings.xml (Icelandic) 2023-10-21 18:27:37 +02:00
Eugen Rochko
33ea3da84d New translations strings.xml (Basque) 2023-10-21 11:37:37 +02:00
Eugen Rochko
e97203a6e3 New translations strings.xml (Thai) 2023-10-21 09:36:50 +02:00
Eugen Rochko
b3f2987b14 New translations strings.xml (Vietnamese) 2023-10-21 03:54:29 +02:00
Eugen Rochko
c7426453a5 New translations strings.xml (German) 2023-10-21 02:52:53 +02:00
sk
b60c1a5db3 add back old see_new_posts strings 2023-10-21 01:43:03 +02:00
Eugen Rochko
664d5cc4c3 New translations strings.xml (German) 2023-10-21 01:04:51 +02:00
sk
47d1b182ac fix see new posts button design 2023-10-21 01:00:51 +02:00
sk
c33c3d9112 fix compatibility issue 2023-10-21 00:54:38 +02:00
sk
ff99e1023a Revert "use tonal background for see new posts button"
This reverts commit 8009dc0a75.
2023-10-20 16:23:02 +02:00
sk
8009dc0a75 use tonal background for see new posts button 2023-10-20 15:31:06 +02:00
sk
20039ec97e bump version 2023-10-20 13:33:02 +02:00
SomeTr
172d25eeb0 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-20 11:32:21 +00:00
alextecplayz
fa04e00032 Translated using Weblate (Romanian)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-20 11:32:21 +00:00
Linerly
3ff442894d Translated using Weblate (Indonesian)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-20 11:32:21 +00:00
Choukajohn
edb0823bf9 Translated using Weblate (French)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-20 11:32:21 +00:00
sk
9de83355e1 revert api timeout and increase for search
closes sk22#881
2023-10-20 13:31:27 +02:00
sk
183fb0e8c0 use fluent back button 2023-10-20 12:54:51 +02:00
sk
d624a04e18 fix see new posts button font size 2023-10-20 12:50:34 +02:00
sk
303461d803 take switcher width into account for button 2023-10-20 12:17:12 +02:00
sk
11c7816bb1 make show new posts button less disruptive 2023-10-20 11:43:35 +02:00
sk
b5eae13a16 introduce separate tonal selector backgrounds 2023-10-20 11:43:15 +02:00
sk
59026286a1 don't cache as many posts 2023-10-20 10:46:56 +02:00
sk
ef0fbb26a4 don't return before refreshDone 2023-10-20 10:33:45 +02:00
sk
387b31193f hopefully unfuck removing statuses and reblogs 2023-10-19 21:42:17 +02:00
sk22
95fa547f15 Translated using Weblate (German)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-19 15:13:41 +00:00
sk22
3198c9adb1 Translated using Weblate (German)
Currently translated at 99.2% (395 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-19 15:07:29 +00:00
SomeTr
e1af6f4643 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-10-19 15:07:29 +00:00
SomeTr
cc52e491b0 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (396 of 396 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 15:07:29 +00:00
Choukajohn
b0db0d9f2e Translated using Weblate (French)
Currently translated at 100.0% (396 of 396 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-19 15:07:29 +00:00
sk
d699788a12 fix string 2023-10-19 17:07:18 +02:00
sk
bdbf441e1a Merge remote-tracking branch 'upstream/l10n_master' 2023-10-19 17:01:46 +02:00
sk
0deba2885b Merge remote-tracking branch 'weblate/main' 2023-10-19 17:01:13 +02:00
sk
48b39fd3bc boop version 2023-10-19 16:59:45 +02:00
sk
875b235e6d restart when show replies/boosts changes
closes sk22#879
2023-10-19 16:58:26 +02:00
sk
1711682322 don't display extra text if visibility == local 2023-10-19 16:54:23 +02:00
sk
70f5ec7500 update header layout 2023-10-19 16:54:07 +02:00
sk
d34c73c210 add options for locking account and default vis 2023-10-19 16:49:23 +02:00
sk
50a0586e8a fix content type index and title 2023-10-19 16:02:51 +02:00
Jacoco
1d2ca1e500 fix: hiding discovery on Akkoma + hiding privacy settings (#867)
* Hide privacy settings on Akkoma

* Fix Akkoma skipping discovery

* Make settings order more clear in the code
2023-10-19 15:42:29 +02:00
EndermanCo
34b7123a8d Translated using Weblate (Persian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-10-19 10:17:38 +00:00
butterflyoffire
ec718ff58e Translated using Weblate (Arabic)
Currently translated at 80.4% (317 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-10-19 10:17:38 +00:00
ihor_ck
20a442e27f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 10:17:38 +00:00
SomeTr
47cb74abc9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 10:17:37 +00:00
SomeTr
a11e53c89a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 10:17:37 +00:00
David Lapshin
d721e8ca46 Translated using Weblate (Russian)
Currently translated at 99.7% (393 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-19 10:17:37 +00:00
alextecplayz
23e5dcd030 Translated using Weblate (Romanian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-19 10:17:37 +00:00
Linerly
25dd2cfab8 Translated using Weblate (Indonesian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-19 10:17:37 +00:00
Choukajohn
8537c7a7ae Translated using Weblate (French)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-19 10:17:37 +00:00
gallegonovato
ebd7f9c36c Translated using Weblate (Spanish)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-19 10:17:37 +00:00
poesty
49cda3aeb2 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (393 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-19 10:17:37 +00:00
sk
67cbc8aff2 don't load new posts every time we hit the top 2023-10-19 01:06:03 +02:00
sk
5db44cbf9d don't save bidi-safe string in account
also support custom emoji in account switcher
closes sk22#859
2023-10-19 01:01:53 +02:00
sk
95858e3280 remove debug println 2023-10-19 00:44:10 +02:00
sk
36846acbe5 fix null pointer when content language is null 2023-10-19 00:38:06 +02:00
sk
b95d944003 save own posts from timeline before removing them 2023-10-19 00:22:52 +02:00
sk
f52886af74 don't add own boosts to home
closes sk22#875
2023-10-19 00:09:09 +02:00
sk
6cbe406cef load new posts on reload 2023-10-19 00:04:54 +02:00
sk
3097bc7168 oops: put home timeline if result NOT empty 2023-10-18 23:28:44 +02:00
sk
5f7faa69e8 remove existing statuses to move them up 2023-10-18 22:07:10 +02:00
sk
ed24e89a96 don't compare newly fetched posts to created post
closes sk22#866
2023-10-18 21:48:11 +02:00
sk
8ea05c6ebd fix menu grouping 2023-10-18 21:24:59 +02:00
sk
a30fcbbe34 reorder profile menu
closes sk22#873
2023-10-18 21:23:58 +02:00
sk
39f76f9988 always show "boosted" text in reply/boost line
closes sk22#874
2023-10-18 21:21:03 +02:00
sk
5135653cd3 wow!! configurable first fraction 2023-10-18 21:11:48 +02:00
sk
2e4f04cd88 fix divide by zero error 2023-10-18 20:40:23 +02:00
Eugen Rochko
a44e0e036a New translations strings.xml (Persian) 2023-10-18 20:27:30 +02:00
Eugen Rochko
5d54c1bae4 New translations strings.xml (Spanish) 2023-10-18 20:27:29 +02:00
sk
09577074a9 merge settings changes 2023-10-18 20:26:20 +02:00
sk
53f0e2a933 change extra text size 2023-10-18 19:39:12 +02:00
sk
b8dccbbef1 now hopefully fixing header/subtitle extra sizing 2023-10-18 19:23:13 +02:00
Eugen Rochko
2ef17ba051 New translations strings.xml (Spanish) 2023-10-18 19:15:17 +02:00
Eugen Rochko
f63daf3a4e New translations strings.xml (Thai) 2023-10-18 19:15:16 +02:00
Eugen Rochko
52b079be2a New translations strings.xml (Thai) 2023-10-18 18:11:40 +02:00
Eugen Rochko
efeca17106 New translations strings.xml (Chinese Traditional) 2023-10-18 11:34:03 +02:00
Eugen Rochko
6827166c1d New translations strings.xml (Galician) 2023-10-18 08:51:11 +02:00
Eugen Rochko
04483e61e8 New translations strings.xml (Galician) 2023-10-18 07:49:15 +02:00
Eugen Rochko
22fe174922 New translations strings.xml (Icelandic) 2023-10-17 20:07:09 +02:00
Eugen Rochko
f143da3913 New translations strings.xml (Kabyle) 2023-10-17 04:25:08 +02:00
Eugen Rochko
7e9f41c74b New translations strings.xml (Scottish Gaelic) 2023-10-17 04:25:05 +02:00
Eugen Rochko
a1474d0d29 New translations strings.xml (Filipino) 2023-10-17 04:25:03 +02:00
Eugen Rochko
0dce936ad3 New translations strings.xml (Persian) 2023-10-17 04:24:58 +02:00
Eugen Rochko
6ebbbb4c6c New translations strings.xml (Indonesian) 2023-10-17 04:24:57 +02:00
Eugen Rochko
dc6ddbd0ee New translations strings.xml (Portuguese, Brazilian) 2023-10-17 04:24:56 +02:00
Eugen Rochko
86c81d6b53 New translations strings.xml (Galician) 2023-10-17 04:24:55 +02:00
Eugen Rochko
451a92aa36 New translations strings.xml (Vietnamese) 2023-10-17 04:24:53 +02:00
Eugen Rochko
5c42e67e73 New translations strings.xml (Chinese Simplified) 2023-10-17 04:24:52 +02:00
Eugen Rochko
d20d36d964 New translations strings.xml (Turkish) 2023-10-17 04:24:51 +02:00
Eugen Rochko
1a8d46c71e New translations strings.xml (Slovenian) 2023-10-17 04:24:50 +02:00
Eugen Rochko
91da10eca3 New translations strings.xml (Portuguese) 2023-10-17 04:24:49 +02:00
Eugen Rochko
3bb0dcee53 New translations strings.xml (Polish) 2023-10-17 04:24:48 +02:00
Eugen Rochko
d3fd4b200f New translations strings.xml (Norwegian) 2023-10-17 04:24:47 +02:00
Eugen Rochko
fed96864e1 New translations strings.xml (Dutch) 2023-10-17 04:24:46 +02:00
Eugen Rochko
3b351bea27 New translations strings.xml (Korean) 2023-10-17 04:24:45 +02:00
Eugen Rochko
254e01dca1 New translations strings.xml (Armenian) 2023-10-17 04:24:44 +02:00
Eugen Rochko
19158e1d48 New translations strings.xml (Hungarian) 2023-10-17 04:24:43 +02:00
Eugen Rochko
bffb78fccf New translations strings.xml (Basque) 2023-10-17 04:24:41 +02:00
Eugen Rochko
a3800592a2 New translations strings.xml (Greek) 2023-10-17 04:24:39 +02:00
Eugen Rochko
22a498dfc9 New translations strings.xml (German) 2023-10-17 04:24:38 +02:00
Eugen Rochko
9ea96e32bd New translations strings.xml (Danish) 2023-10-17 04:24:37 +02:00
Eugen Rochko
68f51a123e New translations strings.xml (Czech) 2023-10-17 04:24:36 +02:00
Eugen Rochko
43b1b63581 New translations strings.xml (Catalan) 2023-10-17 04:24:35 +02:00
Eugen Rochko
43b4a2c515 New translations strings.xml (Belarusian) 2023-10-17 04:24:34 +02:00
Eugen Rochko
5b9cfdb689 New translations strings.xml (Arabic) 2023-10-17 04:24:33 +02:00
Eugen Rochko
b43cd7103a New translations strings.xml (Spanish) 2023-10-17 04:24:32 +02:00
Eugen Rochko
30e4f6e0f5 New translations strings.xml (French) 2023-10-17 04:24:30 +02:00
Eugen Rochko
1d0ebf889b New translations strings.xml (Chinese Traditional) 2023-10-17 04:24:28 +02:00
Eugen Rochko
7c4f1da485 New translations strings.xml (Finnish) 2023-10-17 04:24:27 +02:00
Eugen Rochko
8163921014 New translations strings.xml (Russian) 2023-10-17 04:24:26 +02:00
Eugen Rochko
993393dd96 New translations strings.xml (Swedish) 2023-10-17 04:24:25 +02:00
Eugen Rochko
82aed43934 New translations strings.xml (Italian) 2023-10-17 04:24:24 +02:00
Eugen Rochko
fa65134c26 New translations strings.xml (Ukrainian) 2023-10-17 04:24:23 +02:00
Eugen Rochko
af4266c739 New translations strings.xml (Japanese) 2023-10-17 04:24:22 +02:00
Eugen Rochko
f72ea2e763 New translations strings.xml (Icelandic) 2023-10-17 04:24:21 +02:00
Eugen Rochko
c5540270a3 New translations strings.xml (Thai) 2023-10-17 04:24:20 +02:00
sk
5840c94395 isolate bi-directional text in display name 2023-10-17 01:03:06 +02:00
sk
92d7ae67ef don't break custom emoji in pronouns 2023-10-17 00:38:27 +02:00
sk
fc09514a4d the pronouns are stored in the balls (extra text)
also, improve max-width behavior
2023-10-17 00:28:00 +02:00
sk
300fa97781 remove comment 2023-10-16 19:36:30 +02:00
sk
e8f0891f3a re-aligning buttons with avatar 2023-10-16 19:36:12 +02:00
sk
f25906a694 Merge remote-tracking branch 'upstream/l10n_master' 2023-10-16 19:28:27 +02:00
sk
e52699bb1c Merge remote-tracking branch 'weblate/main' 2023-10-16 19:27:38 +02:00
SomeTr
712826451f Translated using Weblate (Welsh)
Currently translated at 77.7% (14 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/cy/
2023-10-16 17:27:28 +00:00
ihor_ck
3b3065d8bd Translated using Weblate (Ukrainian)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-16 17:27:28 +00:00
alextecplayz
e11fe7d8cf Translated using Weblate (Romanian)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-16 17:27:28 +00:00
SomeTr
9a2f7475c9 Translated using Weblate (German)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-16 17:27:28 +00:00
sk
6dffb10906 make version go up 2023-10-16 19:27:12 +02:00
sk
71039d6901 the changes i made were wrong (what a surprise) 2023-10-16 19:26:29 +02:00
sk
db18c7a0d0 events for boosts, adapt removeStatus method 2023-10-16 19:14:16 +02:00
sk
7e80ed6af2 fix and refactor removing statuses 2023-10-16 18:28:47 +02:00
sk
bdd2b90581 allow entering full handles instead of domain
closes sk22#646
2023-10-16 01:03:19 +02:00
sk
50d017d8ba fix account context menu
closes sk22#652
2023-10-16 00:44:47 +02:00
sk
98e003437c fix confirm unfollow 2023-10-16 00:11:47 +02:00
sk
d5d06af614 fix keyboard gap in scheduled post list height 2023-10-15 23:59:26 +02:00
sk
1c930ca3bb check for draft before checking alt texts 2023-10-15 23:42:53 +02:00
sk
0f0c1093d4 don't hide draft options when redrafting 2023-10-15 23:35:01 +02:00
sk
2ad5dc5a74 make unfinished attachment dialog make more sense 2023-10-15 23:20:40 +02:00
sk
e02e0865bd fix softlock when re-saving draft
closes sk22#659
2023-10-15 23:05:29 +02:00
sk
59ee1af75d fix border radius
closes sk22#861
2023-10-15 22:53:23 +02:00
sk
c04584dfa6 fix alignments 2023-10-15 21:17:38 +02:00
sk
190a3b5b08 use fluent dismiss button 2023-10-15 21:17:26 +02:00
sk
f5a67e65f0 fix missing content descriptions, button alignment 2023-10-15 21:16:42 +02:00
Eugen Rochko
498078b6e0 New translations strings.xml (Swedish) 2023-10-15 20:37:55 +02:00
sk
de8c289ca7 finally!! fix reblog/-ply line with extra emoji
closes sk22#468
2023-10-15 20:29:15 +02:00
sk
07b205a746 remove fullText emoji helper, fix content description 2023-10-15 20:18:40 +02:00
sk
a7941310bc no more vertical reblog/reply line layout
closes sk22#834
2023-10-15 20:11:03 +02:00
sk
864b6dcdac remove outdated comment 2023-10-15 20:04:39 +02:00
sk
d3744bb397 remove compact reblog line setting 2023-10-15 19:57:22 +02:00
sk
7d1853bc88 fix saving wrong item
closes sk22#863
2023-10-15 19:46:14 +02:00
sk
9f0db755d1 fix text/buttons alignment, margin
closes sk22#864
2023-10-15 19:44:37 +02:00
sk
06819806be "fix" trends loading indefinitely
closes sk22#781
2023-10-15 19:23:57 +02:00
Eugen Rochko
526f5e319b New translations strings.xml (Swedish) 2023-10-15 18:51:35 +02:00
sk
30a4d0efd9 rename vars, compare content status id for reply 2023-10-15 18:10:57 +02:00
Eugen Rochko
d419dba44a New translations strings.xml (Swedish) 2023-10-15 14:26:36 +02:00
Choukajohn
87da6b9b81 Translated using Weblate (French)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-15 01:20:04 +00:00
Linerly
67cc1553da Translated using Weblate (Indonesian)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-14 05:22:21 +00:00
sk
9a985aad29 fix deleting boosted posts in profile 2023-10-14 01:47:13 +02:00
Eugen Rochko
fd98159fce New translations strings.xml (Greek) 2023-10-14 00:27:35 +02:00
sk
42fac30e63 wrap into full-width view 2023-10-13 23:50:49 +02:00
sk
18e7f14c16 remove duplicate selectable background 2023-10-13 23:49:54 +02:00
sk
7b263800a6 reduce button margins, realign buttons
closes sk22#
2023-10-13 23:27:49 +02:00
sk
17387a32b2 don't scale buttons with text
re: sk22#787
2023-10-13 23:04:45 +02:00
sk
3fe642c2f2 remove unwanted margin 2023-10-13 22:36:15 +02:00
sk
9225447409 use action bar icons color for toolbar
closes sk22#860
2023-10-13 22:27:53 +02:00
SomeTr
e05dee64b7 Translated using Weblate (Ukrainian)
Currently translated at 99.4% (391 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-13 20:23:08 +00:00
Choukajohn
7f30973b39 Translated using Weblate (French)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-13 20:23:08 +00:00
gallegonovato
25da9bb2d0 Translated using Weblate (Spanish)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-13 20:23:08 +00:00
poesty
e17b49e704 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (392 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-13 20:23:08 +00:00
sk
db661b56cb fix inconsistent styles, fix non-sp font
closes sk22#862
2023-10-13 22:17:45 +02:00
sk
638e1bf8e9 do show labels per default
This reverts commit a1c81e89e8.
2023-10-13 21:16:52 +02:00
sk
83786171a7 ellipsize tab bar labels 2023-10-13 13:49:54 +02:00
sk
f638a538c1 Merge remote-tracking branch 'upstream/l10n_master' 2023-10-13 13:45:36 +02:00
sk22
11e2316cbc Translated using Weblate (German)
Currently translated at 100.0% (393 of 393 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-13 11:45:15 +00:00
ihor_ck
1b372c7dca Translated using Weblate (Ukrainian)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-13 11:43:24 +00:00
ihor_ck
cf4e37fade Translated using Weblate (Ukrainian)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-13 11:43:24 +00:00
SomeTr
f3fc60ac00 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-13 11:43:24 +00:00
butterflyoffire
1026d99025 Translated using Weblate (Arabic)
Currently translated at 81.2% (317 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-10-13 11:43:24 +00:00
ihor_ck
3fb947fbfe Translated using Weblate (Ukrainian)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-13 11:43:24 +00:00
David Lapshin
f097506d49 Translated using Weblate (Russian)
Currently translated at 99.7% (389 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-13 11:43:24 +00:00
alextecplayz
3df7d74fbf Translated using Weblate (Romanian)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-13 11:43:24 +00:00
Oliebol
3fc17eb9c9 Translated using Weblate (Dutch)
Currently translated at 81.0% (316 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-10-13 11:43:24 +00:00
Linerly
67ee74c1a0 Translated using Weblate (Indonesian)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-13 11:43:24 +00:00
Espasant3
bcebba8896 Translated using Weblate (Galician)
Currently translated at 97.9% (382 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-10-13 11:43:24 +00:00
Choukajohn
451b0c1ac5 Translated using Weblate (French)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-13 11:43:24 +00:00
butterflyoffire
5d08b4923b Translated using Weblate (French)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-13 11:43:24 +00:00
kallekn
9ba948c721 Translated using Weblate (Finnish)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-10-13 11:43:24 +00:00
gallegonovato
23e7513133 Translated using Weblate (Spanish)
Currently translated at 100.0% (390 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-13 11:43:24 +00:00
poesty
aaed8e53c8 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (389 of 390 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-13 11:43:24 +00:00
sk
f2754cc5c9 bump version 2023-10-13 13:43:08 +02:00
sk
6a65edd089 fix draft/schedule view for large display sizes
cc @LucasGGamerM
see 77e19b4d6f
2023-10-13 13:39:51 +02:00
LucasGGamerM
4d49b10585 fix(compose): make 'This post will be saved as a draft' view work better on smaller screens
cc: @sk22
2023-10-13 13:27:13 +02:00
sk
86bfab81bd lucas is right
closes sk22#857
2023-10-13 02:27:34 +02:00
sk
50e313cff0 fix gap max_id when post before gap is filtered
hopefully fixes sk22#856
2023-10-13 02:22:03 +02:00
sk
5d07cde6dd fix gap not filtering posts 2023-10-13 01:48:45 +02:00
sk
f84a923102 implement global default color
closes sk22#853
2023-10-13 01:28:59 +02:00
sk
c9eac34ae6 fix gap item alpha not being reset
closes sk22#851
2023-10-13 00:27:35 +02:00
sk
181a0577c8 fix missing gap item when status removed 2023-10-13 00:24:32 +02:00
sk
0426084194 fix changes breaking off-screen bound holders
i hope i didn't break everything lol
2023-10-13 00:14:29 +02:00
Eugen Rochko
197d0caf44 New translations strings.xml (Japanese) 2023-10-11 18:34:49 +02:00
Eugen Rochko
a4a082f76a New translations strings.xml (Japanese) 2023-10-11 17:14:57 +02:00
Eugen Rochko
2528d48010 New translations strings.xml (Icelandic) 2023-10-10 18:10:41 +02:00
Eugen Rochko
5456d71979 New translations strings.xml (Chinese Traditional) 2023-10-10 10:25:33 +02:00
Eugen Rochko
e36aae3cf3 New translations strings.xml (Thai) 2023-10-09 20:31:09 +02:00
Grishka
d6040c0895 Hide the FAB while editing profile 2023-10-09 19:42:54 +02:00
Eugen Rochko
6d12e2dd72 New translations strings.xml (Thai) 2023-10-09 19:20:32 +02:00
sk
ff47e6edba remove unused method 2023-10-09 18:46:52 +02:00
sk
327ceb04d4 fix deleting notifications
closes sk22#677
closes sk22#633
2023-10-09 18:35:27 +02:00
sk
40a34b07de add option to disable underlined links
closes sk22#847
2023-10-09 18:07:19 +02:00
Eugen Rochko
f117249bb5 New translations strings.xml (Thai) 2023-10-09 18:02:31 +02:00
sk
1c90164ece fix broken hashtag links
closes sk22#848
2023-10-09 17:59:22 +02:00
sk
0d5fb250bc migrate theme colors
closes sk22#849
2023-10-09 17:54:54 +02:00
sk
e9bd5a373a remove unused icons and replace some wrong ones 2023-10-09 17:39:18 +02:00
sk
c494d283ba remove duplicate section, replace icons
closes sk22#850
2023-10-09 17:38:55 +02:00
Eugen Rochko
cf1d537367 New translations strings.xml (Vietnamese) 2023-10-09 06:03:28 +02:00
Eugen Rochko
517d13b400 New translations strings.xml (Vietnamese) 2023-10-09 05:07:06 +02:00
Eugen Rochko
fae870c93a New translations strings.xml (Urdu (India)) 2023-10-08 21:13:23 +02:00
Eugen Rochko
f8e00dcc80 New translations strings.xml (Kabyle) 2023-10-08 21:13:22 +02:00
Eugen Rochko
5fdbb597bb New translations strings.xml (Igbo) 2023-10-08 21:13:21 +02:00
Eugen Rochko
d74b286a9d New translations strings.xml (Occitan) 2023-10-08 21:13:20 +02:00
Eugen Rochko
ecb3c521ff New translations strings.xml (Scottish Gaelic) 2023-10-08 21:13:19 +02:00
Eugen Rochko
1d093ce928 New translations strings.xml (Sinhala) 2023-10-08 21:13:18 +02:00
Eugen Rochko
46b711af2e New translations strings.xml (Bosnian) 2023-10-08 21:13:17 +02:00
Eugen Rochko
772e6ddb5d New translations strings.xml (Filipino) 2023-10-08 21:13:16 +02:00
Eugen Rochko
f84e8443d2 New translations strings.xml (Burmese) 2023-10-08 21:13:15 +02:00
Eugen Rochko
250c18ebf1 New translations strings.xml (Hindi) 2023-10-08 21:13:14 +02:00
Eugen Rochko
e3d0f38b79 New translations strings.xml (Croatian) 2023-10-08 21:13:14 +02:00
Eugen Rochko
c512f97783 New translations strings.xml (Bengali) 2023-10-08 21:13:13 +02:00
Eugen Rochko
0594680775 New translations strings.xml (Persian) 2023-10-08 21:13:12 +02:00
Eugen Rochko
f999881f59 New translations strings.xml (Indonesian) 2023-10-08 21:13:11 +02:00
Eugen Rochko
4fe9192ac6 New translations strings.xml (Portuguese, Brazilian) 2023-10-08 21:13:10 +02:00
Eugen Rochko
d936702fa9 New translations strings.xml (Galician) 2023-10-08 21:13:08 +02:00
Eugen Rochko
74e284b0de New translations strings.xml (Vietnamese) 2023-10-08 21:13:07 +02:00
Eugen Rochko
4c42b72ed8 New translations strings.xml (Chinese Simplified) 2023-10-08 21:13:06 +02:00
Eugen Rochko
0e0046df65 New translations strings.xml (Turkish) 2023-10-08 21:13:05 +02:00
Eugen Rochko
c80d1d10c2 New translations strings.xml (Slovenian) 2023-10-08 21:13:05 +02:00
Eugen Rochko
da97971011 New translations strings.xml (Portuguese) 2023-10-08 21:13:04 +02:00
Eugen Rochko
700447dbe7 New translations strings.xml (Polish) 2023-10-08 21:13:03 +02:00
Eugen Rochko
37e7b5ee93 New translations strings.xml (Norwegian) 2023-10-08 21:13:02 +02:00
Eugen Rochko
1265afa93f New translations strings.xml (Dutch) 2023-10-08 21:13:01 +02:00
Eugen Rochko
1e09481b02 New translations strings.xml (Korean) 2023-10-08 21:13:00 +02:00
Eugen Rochko
9996a5a05e New translations strings.xml (Armenian) 2023-10-08 21:12:59 +02:00
Eugen Rochko
f20aac7c81 New translations strings.xml (Hungarian) 2023-10-08 21:12:58 +02:00
Eugen Rochko
98f7b0bacd New translations strings.xml (Hebrew) 2023-10-08 21:12:57 +02:00
Eugen Rochko
3f6d3fb3a2 New translations strings.xml (Irish) 2023-10-08 21:12:56 +02:00
Eugen Rochko
663b49c76b New translations strings.xml (Basque) 2023-10-08 21:12:55 +02:00
Eugen Rochko
16e38f2541 New translations strings.xml (Greek) 2023-10-08 21:12:54 +02:00
Eugen Rochko
842cc55e47 New translations strings.xml (German) 2023-10-08 21:12:53 +02:00
Eugen Rochko
72db099e6f New translations strings.xml (Danish) 2023-10-08 21:12:52 +02:00
Eugen Rochko
be130bc3a7 New translations strings.xml (Czech) 2023-10-08 21:12:51 +02:00
Eugen Rochko
42253336e1 New translations strings.xml (Catalan) 2023-10-08 21:12:50 +02:00
Eugen Rochko
572631e1d7 New translations strings.xml (Belarusian) 2023-10-08 21:12:49 +02:00
Eugen Rochko
723777a800 New translations strings.xml (Arabic) 2023-10-08 21:12:48 +02:00
Eugen Rochko
b825d534c1 New translations strings.xml (Spanish) 2023-10-08 21:12:47 +02:00
Eugen Rochko
b9749620a8 New translations strings.xml (French) 2023-10-08 21:12:46 +02:00
Eugen Rochko
70ea9989aa New translations strings.xml (Romanian) 2023-10-08 21:12:45 +02:00
Eugen Rochko
b3ec9c981c New translations strings.xml (Chinese Traditional) 2023-10-08 21:12:44 +02:00
Eugen Rochko
bf72085abb New translations strings.xml (Finnish) 2023-10-08 21:12:43 +02:00
Eugen Rochko
64dd416b59 New translations strings.xml (Russian) 2023-10-08 21:12:42 +02:00
Eugen Rochko
ab2a920455 New translations strings.xml (Swedish) 2023-10-08 21:12:41 +02:00
Eugen Rochko
7580446d60 New translations strings.xml (Italian) 2023-10-08 21:12:40 +02:00
Eugen Rochko
ade18ac6fc New translations strings.xml (Ukrainian) 2023-10-08 21:12:39 +02:00
Eugen Rochko
005c851d72 New translations strings.xml (Japanese) 2023-10-08 21:12:38 +02:00
Eugen Rochko
0f1d46c765 New translations strings.xml (Icelandic) 2023-10-08 21:12:36 +02:00
Eugen Rochko
21fbb07b1d New translations strings.xml (Thai) 2023-10-08 21:12:36 +02:00
sk
58e0ce3970 add tooltips 2023-10-08 16:36:56 +02:00
sk
139a7d7c98 change settings order 2023-10-08 16:36:48 +02:00
sk
a1c81e89e8 don't show labels per default 2023-10-08 16:36:41 +02:00
sk
a5c197b496 hearts everywhere
closes sk22#846
2023-10-08 13:04:26 +02:00
sk
df49ef9d58 redder red 2023-10-08 12:54:59 +02:00
sk
f747d4c979 toggle label font weight according to m3 2023-10-08 12:49:29 +02:00
sk
98677cd307 on page change listener may also load first page 2023-10-08 11:48:59 +02:00
sk
cd3de97d55 Merge remote-tracking branch 'upstream/l10n_master' 2023-10-07 23:47:36 +02:00
sk
4853a25710 bump version 2023-10-07 23:47:01 +02:00
SomeTr
eba9a1da7b Translated using Weblate (Ukrainian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-10-07 21:46:18 +00:00
SomeTr
068c62b060 Translated using Weblate (Ukrainian)
Currently translated at 98.9% (385 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-07 21:46:18 +00:00
David Lapshin
5d7f06eba0 Translated using Weblate (Russian)
Currently translated at 97.6% (380 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-07 21:46:18 +00:00
Linerly
fed9dec33a Translated using Weblate (Indonesian)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-07 21:46:18 +00:00
Choukajohn
7973914a5f Translated using Weblate (French)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-07 21:46:18 +00:00
kallekn
35efb3f047 Translated using Weblate (Finnish)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-10-07 21:46:18 +00:00
sk
0a4ed50904 i think i fixed the offset issue 2023-10-07 23:45:33 +02:00
sk
002c66174a fix type filter, wrong max id, refactor max id 2023-10-07 23:32:10 +02:00
Eugen Rochko
22aac3d943 New translations strings.xml (Finnish) 2023-10-07 22:49:20 +02:00
sk
872f47305a Revert "temporary fix for pre-release users"
This reverts commit 2314871246.
2023-10-07 22:38:42 +02:00
sk
75d5332411 don't add existing posts to timeline 2023-10-07 22:38:30 +02:00
sk
035da8a517 update blocks and languages 2023-10-07 22:17:36 +02:00
sk
4c2c877d41 bump version 2023-10-07 22:11:35 +02:00
sk
0cc8cddfc3 support recently used emoji
closes sk22#832
2023-10-07 22:10:52 +02:00
sk
4428ef7ac2 display recent languages
closes sk22#654
2023-10-07 19:47:49 +02:00
sk
44912b7982 display timestamp in notification header
closes sk22#668
2023-10-07 19:17:45 +02:00
sk
c930db6068 refactor filtering
hopefully also fixes sk22#816
2023-10-07 18:25:37 +02:00
sk
d96d4dd581 unselect add button on bind
closes sk22#830
2023-10-07 17:52:39 +02:00
sk
67e3a5bb47 fix warning not clickable if main status 2023-10-07 17:50:24 +02:00
sk22
b0a5aa93e1 Translated using Weblate (German)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-07 15:39:39 +00:00
sk22
0bc1459898 Translated using Weblate (English)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2023-10-07 15:39:38 +00:00
sk
fae25e93a5 Merge remote-tracking branch 'weblate/main' 2023-10-07 17:29:18 +02:00
kallekn
c0c121050c Translated using Weblate (Finnish)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-10-07 15:29:11 +00:00
teknopata
afe572ca7f Translated using Weblate (Basque)
Currently translated at 78.6% (305 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-10-07 15:29:11 +00:00
sk
8cb4db5fcf Merge remote-tracking branch 'weblate/main' 2023-10-07 17:28:51 +02:00
sk
de235ec7cc use upstream filtering for warn item 2023-10-07 17:21:20 +02:00
sk
140c2a7b9d remove status filter predicate from thread 2023-10-07 17:04:55 +02:00
sk
c833513344 use same filtering function everywhere 2023-10-07 17:02:03 +02:00
sk
1e95536208 fix issue with loading more 2023-10-07 17:00:16 +02:00
sk
b58fda9795 remove unused method 2023-10-07 16:12:35 +02:00
sk
3135aef398 fix wrong overflow button style 2023-10-07 16:03:30 +02:00
sk
c83dc51322 re-add ripple to filter warning 2023-10-07 15:43:16 +02:00
sk
9cfaed89e6 fix filter warning background color
closes sk22#823
2023-10-07 15:26:10 +02:00
sk
5374ac766c prettier visibility toggle animation
maybe fix sk22#845
2023-10-07 15:21:06 +02:00
sk
98596e77f2 fix interaction button colors
closes sk22#841
2023-10-07 12:44:39 +02:00
sk
54aa89c7f8 OOPS 2023-10-07 12:44:33 +02:00
sk
f59157b160 fix text not selectable
closes sk22#824
2023-10-07 12:33:14 +02:00
sk
6b38db9607 add heart symbol to extended footer 2023-10-07 12:08:37 +02:00
Eugen Rochko
53afc120f3 New translations strings.xml (Chinese Traditional) 2023-10-07 03:46:12 +02:00
sk
c10cdfd795 fix color inheritance issue 2023-10-06 18:44:15 +02:00
sk
c2184e7bd8 don't dismiss when restarting activity 2023-10-06 18:00:59 +02:00
sk
baf756e163 allow using heart as fav icon ❤️
closes sk22#81
2023-10-06 17:53:43 +02:00
sk
efc67fd7e8 remove inset poll styles
closes sk22#801
2023-10-06 17:26:59 +02:00
sk
43e737425a fix null reference 2023-10-06 17:20:49 +02:00
sk
b5b3cb42a1 re-implement missing "translate opened only" 2023-10-06 17:09:57 +02:00
sk
f72f7cb831 hide username wrap in edit mode
closes sk22#828
2023-10-06 17:02:52 +02:00
sk
f86d60be23 fix color palette dialog title 2023-10-06 17:00:09 +02:00
sk
7c8624bd53 fix alpha animations
closes sk22#839
2023-10-06 16:55:02 +02:00
Eugen Rochko
a75ce70615 New translations strings.xml (Finnish) 2023-10-06 16:38:40 +02:00
sk
331548b38d fix crash 2023-10-06 16:20:16 +02:00
sk
8b8f192dfa fix posts/bubble banner not disappearing
closes sk22#833
2023-10-06 16:17:18 +02:00
sk
061b2ee3de per-account color palette preference 2023-10-06 16:13:38 +02:00
sk
5ea2864bd5 Merge remote-tracking branch 'upstream/master' 2023-10-06 15:17:49 +02:00
LucasGGamerM
ee2b4b6a1f fix(hashtag-fragment): fix crash when opening some hashtags (#842) 2023-10-06 15:04:02 +02:00
LucasGGamerM
697f801c1a fix(hashtags): fix crash when hashtag is null (#844) 2023-10-06 15:03:25 +02:00
sk
ebb49c44fe refactor code 2023-10-06 15:01:46 +02:00
LucasGGamerM
bc4619e6b1 fix(translations): fix crash when status language is null 2023-10-06 15:01:46 +02:00
Eugen Rochko
4a3b948760 New translations strings.xml (Finnish) 2023-10-05 22:23:12 +02:00
Eugen Rochko
f81283c892 New translations strings.xml (Italian) 2023-10-05 21:19:39 +02:00
Eugen Rochko
7eae879037 New translations strings.xml (Russian) 2023-10-05 16:06:00 +02:00
Eugen Rochko
1b0ce5d893 New translations strings.xml (Swedish) 2023-10-05 12:02:19 +02:00
butterflyoffire
5d26ea85e9 Translated using Weblate (Arabic)
Currently translated at 80.1% (311 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-10-05 07:53:14 +00:00
ihor_ck
6efe263dd8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-05 07:53:14 +00:00
David Lapshin
0379347f2d Translated using Weblate (Russian)
Currently translated at 87.1% (338 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-05 07:53:14 +00:00
alextecplayz
1299b2ad42 Translated using Weblate (Romanian)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-05 07:53:14 +00:00
Linerly
f3b3bcaa0a Translated using Weblate (Indonesian)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-05 07:53:14 +00:00
Choukajohn
b1bec870c5 Translated using Weblate (French)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-05 07:53:13 +00:00
butterflyoffire
36e05a6d14 Translated using Weblate (French)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-05 07:53:13 +00:00
gallegonovato
2e11f78e9d Translated using Weblate (Spanish)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-05 07:53:13 +00:00
poesty
9fcfbe5593 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (387 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-05 07:53:12 +00:00
Eugen Rochko
c17745368d New translations strings.xml (Italian) 2023-10-04 22:24:20 +02:00
Eugen Rochko
e78b518654 New translations strings.xml (Ukrainian) 2023-10-04 18:44:26 +02:00
Eugen Rochko
55a8634be2 New translations strings.xml (Japanese) 2023-10-04 16:52:54 +02:00
Eugen Rochko
ac891eea53 New translations strings.xml (Icelandic) 2023-10-04 15:28:52 +02:00
Eugen Rochko
74fa2a3081 New translations strings.xml (Thai) 2023-10-03 21:27:27 +02:00
Grishka
6c1c5b7759 Merge branch 'l10n_master' 2023-10-03 03:53:50 +03:00
Grishka
1f4152b588 Fix #705 and improve handling of unknown attachment dimensions 2023-10-03 02:52:07 +03:00
Grishka
70386ea1b2 Update appkit to finally fix that ViewPager2 crash 2023-10-03 02:11:04 +03:00
Eugen Rochko
cbce90c461 New translations strings.xml (Sinhala) 2023-10-02 21:16:49 +02:00
Eugen Rochko
74ae3bf706 New translations strings.xml (Armenian) 2023-10-02 07:26:27 +02:00
Grishka
1feccdc26d Fixes 2023-10-01 23:11:33 +03:00
Eugen Rochko
c38c2a425b New translations strings.xml (Indonesian) 2023-10-01 17:30:46 +02:00
Eugen Rochko
f43352b790 New translations strings.xml (Indonesian) 2023-10-01 16:30:51 +02:00
Grishka
c5b52b2781 Fix default server not loading sometimes 2023-10-01 12:17:21 +03:00
Grishka
b91840fb95 Another attempt to fix ZoomPanView crash 2023-10-01 07:16:21 +03:00
sk
1988849b26 Merge remote-tracking branch 'upstream/master' 2023-09-30 21:21:47 +02:00
Grishka
fc10fbffb0 Clear fragment stack instead of restarting activity
grishka/appkit#13
2023-09-30 21:53:02 +03:00
Eugen Rochko
e40841c128 New translations strings.xml (Portuguese, Brazilian) 2023-09-30 20:26:54 +02:00
sk
a21a74a8e7 bonk version 2023-09-30 19:26:15 +02:00
sk
20e5d2a545 Merge remote-tracking branch 'upstream/l10n_master' 2023-09-30 19:24:52 +02:00
butterflyoffire
7da363fb87 Translated using Weblate (Arabic)
Currently translated at 80.3% (310 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-30 17:23:53 +00:00
sk
c46f78272d Merge remote-tracking branch 'weblate/main' 2023-09-30 19:23:42 +02:00
Tyler Baker
95685d4de8 Feature: Support filtering custom emoji in reaction view (#836)
* Support filtering custom emojis in reaction keyboard.

* Move creation of EditText to conditional block.

* Clear unused comment

* Update requests variable when publishing filter results so the images displayed will be correct.

* Combine text fields in emoji reaction keyboard, create new initializer for EmojiCategory so it can be copied properly.

* Performance optimization and fixed a typo in filter.

* improve layout

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-09-30 19:21:36 +02:00
FineFindus
cbee0fe72e fix: show individual chips (#838) 2023-09-30 19:04:04 +02:00
FineFindus
6d085ae6f0 fix: show multiline poll options (#837)
* fix: show multiline poll options

* fix resources not found exception

* don't force height on poll options

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-09-30 19:03:17 +02:00
LucasGGamerM
4de7211523 Fix notifications replies visibility/language not being consistent with replied status (#831)
* fix(notifications): make reply visibility consistent with status being replied to

* fix(notifications): make reply language consistent with status being replied to
2023-09-30 18:30:53 +02:00
FineFindus
05f7a44bd5 fix(timeline/gap): use plurals for time (#829)
Co-authored-by: sk <sk22@mailbox.org>
2023-09-30 18:30:18 +02:00
Jacoco
1079f600bc Revert "Fix media layout with unknown sizes" (#827)
This reverts commit a014fe9443.
2023-09-30 18:25:52 +02:00
FineFindus
72580dadd0 feat: display blocks and mutes list (#821)
* feat: add mutes fragment

* feat: add blocks fragment

* refactor: add query params

* rename "mutes" and "blocks"

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-09-30 18:24:24 +02:00
Eugen Rochko
98a02e874b New translations strings.xml (Vietnamese) 2023-09-30 15:05:49 +02:00
butterflyoffire
d219d7aa4b Translated using Weblate (Arabic)
Currently translated at 78.2% (302 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-30 03:45:04 +00:00
alextecplayz
68a9fe8376 Translated using Weblate (Romanian)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-09-30 03:45:04 +00:00
sk
f2f8620312 fix menu item icons and state 2023-09-29 21:45:41 +02:00
sk
4ee229ea79 Merge remote-tracking branch 'upstream/master' into try-to-merge-upstream 2023-09-29 20:59:12 +02:00
sk
c261214e49 implement new translation 2023-09-29 18:46:26 +02:00
Eugen Rochko
b06df8c3d0 New translations strings.xml (Galician) 2023-09-29 07:53:31 +02:00
Grishka
a00afd5d7f Same crash fix in 2 more places ugh 2023-09-29 03:20:58 +03:00
Grishka
9a41a2d6fb Merge branch 'l10n_master' 2023-09-28 20:14:21 +03:00
Grishka
2cd98a6620 More crash fixes 2023-09-28 20:11:43 +03:00
Grishka
283b56be5b Finally fix the mysterious RecyclerView crash 2023-09-28 19:56:25 +03:00
Eugen Rochko
6d56771aba New translations strings.xml (Galician) 2023-09-28 16:51:59 +02:00
Grishka
1724d8a532 Probably fix #703 2023-09-27 19:50:59 +03:00
butterflyoffire
52030b3b2d Translated using Weblate (Arabic)
Currently translated at 76.1% (294 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-27 07:53:09 +00:00
Eugen Rochko
b4cdf35d36 New translations strings.xml (Russian) 2023-09-25 23:39:42 +02:00
Eugen Rochko
cad0ad7a59 New translations strings.xml (Ukrainian) 2023-09-25 22:25:17 +02:00
Grishka
ca60003c39 Fix #682 2023-09-25 23:11:10 +03:00
Grishka
0f030e0bac Fix #683 2023-09-25 23:07:34 +03:00
Grishka
6d4f212a18 Probably need to set this too 2023-09-25 23:00:15 +03:00
Grishka
183b39bc24 Specify LED color for notifications
closes #695
2023-09-25 22:58:08 +03:00
Grishka
27ad0c6fcf Crash fixes 2023-09-25 22:52:51 +03:00
Grishka
b5f661f1af I forgot to increment the version code 2023-09-25 19:25:59 +03:00
Grishka
0015f3f0bf Merge branch 'l10n_master' 2023-09-25 19:22:38 +03:00
Eugen Rochko
c5d0fdd645 New translations strings.xml (Turkish) 2023-09-25 18:20:56 +02:00
Grishka
2d09ad44fb Merge branch 'l10n_master' 2023-09-25 19:18:24 +03:00
Eugen Rochko
667fffd124 New translations strings.xml (Chinese Traditional) 2023-09-25 18:18:22 +02:00
Eugen Rochko
699233d8c7 New translations strings.xml (Filipino) 2023-09-25 18:18:05 +02:00
Grishka
56aabdc4a6 Fix empty view text style
closes #701
2023-09-25 19:12:04 +03:00
Grishka
443e2c7a6f Add a tool to detect invalid formatting in localized strings 2023-09-25 18:51:49 +03:00
Eugen Rochko
985b0f6e63 New translations strings.xml (Filipino) 2023-09-25 17:49:57 +02:00
Grishka
cc86edf276 Fix #700 2023-09-25 17:18:42 +03:00
Grishka
4071b9342d Update appkit 2023-09-25 17:13:59 +03:00
Eugen Rochko
f71d1bc5d3 New translations strings.xml (Greek) 2023-09-24 23:27:13 +02:00
Andrewblasco
2b926ffa46 Translated using Weblate (Spanish)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-24 08:53:08 +00:00
Eugen Rochko
6bcdbaba34 New translations strings.xml (Turkish) 2023-09-24 08:49:38 +02:00
Eugen Rochko
a2beead3a5 New translations strings.xml (Chinese Simplified) 2023-09-23 18:34:38 +02:00
Eugen Rochko
e7a25e353d New translations strings.xml (Japanese) 2023-09-23 14:15:37 +02:00
Eugen Rochko
af04a01130 New translations strings.xml (Japanese) 2023-09-23 13:16:04 +02:00
Grishka
fe1cfa1d7b Fix indexable setting 2023-09-22 21:33:21 +03:00
Eugen Rochko
b248797bb0 New translations strings.xml (Russian) 2023-09-22 20:28:14 +02:00
Grishka
f24eba08d3 Fix custom emojis in names setting 2023-09-22 21:27:30 +03:00
Eugen Rochko
0e89559a47 New translations strings.xml (Slovenian) 2023-09-22 19:30:53 +02:00
Espasant3
858657799f Translated using Weblate (Galician)
Currently translated at 98.1% (379 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-09-22 12:53:08 +00:00
Eugen Rochko
d02a72e079 New translations strings.xml (Japanese) 2023-09-22 13:01:51 +02:00
Eugen Rochko
3be57d1b0b New translations strings.xml (Japanese) 2023-09-22 11:08:13 +02:00
Eugen Rochko
bed550e97c New translations strings.xml (Russian) 2023-09-22 09:19:11 +02:00
Eugen Rochko
7e2619ea75 New translations strings.xml (Italian) 2023-09-22 01:48:10 +02:00
Eugen Rochko
4b22f1d3a7 New translations strings.xml (Thai) 2023-09-21 21:39:59 +02:00
Eugen Rochko
9dcc7e293f New translations strings.xml (Icelandic) 2023-09-21 15:39:27 +02:00
Eugen Rochko
6a68cf5e41 New translations strings.xml (Persian) 2023-09-21 13:13:31 +02:00
Grishka
29297be4a3 Merge branch 'l10n_master' 2023-09-20 22:43:16 +03:00
Eugen Rochko
90b87529e0 New translations strings.xml (Swedish) 2023-09-20 21:16:11 +02:00
Grishka
39af05524d Privacy settings 2023-09-20 21:44:28 +03:00
Grishka
e3fb2cd03c Scroll profile tab views to top when tab is reselected 2023-09-20 14:47:25 +03:00
Gregory K
90f84d628a Merge pull request #694 from LucasGGamerM/mastodon-android
fix(compose): fix photoPicker not popping up when there is less than 2 spaces available for media
2023-09-20 14:10:26 +03:00
LucasGGamerM
b89e0b5c5a fix(compose): fix photoPicker not popping up when there is less than 2 spaces available for media 2023-09-20 07:55:23 -03:00
Espasant3
f724644d84 Translated using Weblate (Galician)
Currently translated at 89.6% (346 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-09-19 21:53:09 +00:00
Eugen Rochko
aac89c354c New translations full_description.txt (Thai) 2023-09-18 20:35:41 +02:00
Eugen Rochko
a032f9af10 New translations strings.xml (French) 2023-09-18 20:34:32 +02:00
Eugen Rochko
642aaec6da New translations strings.xml (Persian) 2023-09-17 14:08:04 +02:00
Eugen Rochko
ff667d6aed New translations strings.xml (Persian) 2023-09-17 12:27:57 +02:00
Eugen Rochko
5e98496ea6 New translations strings.xml (Vietnamese) 2023-09-17 10:39:46 +02:00
Eugen Rochko
972fe1d15b New translations strings.xml (Italian) 2023-09-17 10:39:45 +02:00
Eugen Rochko
26eaa36faa New translations strings.xml (Finnish) 2023-09-17 10:39:44 +02:00
Grishka
c517f41595 Paginate search results 2023-09-17 11:20:12 +03:00
Grishka
56a6d7243f Crash fixes 2023-09-17 10:49:13 +03:00
Grishka
18e43dfc22 Crash fix 2023-09-17 10:32:59 +03:00
Grishka
816f6370ef Fix #690 2023-09-17 10:26:27 +03:00
butterflyoffire
30866a5292 Translated using Weblate (Arabic)
Currently translated at 71.5% (276 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-16 08:53:08 +00:00
Espasant3
3e1403d18a Translated using Weblate (Galician)
Currently translated at 85.2% (329 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-09-16 08:53:08 +00:00
Eugen Rochko
ebc2b2e59d New translations strings.xml (Arabic) 2023-09-15 11:51:46 +02:00
Eugen Rochko
c9a796dbfe New translations strings.xml (Arabic) 2023-09-15 10:16:56 +02:00
Eugen Rochko
1ba185ea9c New translations strings.xml (Vietnamese) 2023-09-15 03:45:44 +02:00
EndermanCo
1a50c3ff5f Translated using Weblate (Persian)
Currently translated at 66.6% (12 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-09-14 17:53:07 +00:00
EndermanCo
35a85c3247 Translated using Weblate (Persian)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-09-14 17:53:07 +00:00
GunChleoc
6a729fa97f Translated using Weblate (Gaelic)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gd/
2023-09-14 17:53:07 +00:00
kallekn
923639a329 Translated using Weblate (Finnish)
Currently translated at 94.5% (365 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-09-14 17:53:07 +00:00
Eugen Rochko
a78be8bc1d New translations strings.xml (Chinese Traditional) 2023-09-14 12:55:27 +02:00
Eugen Rochko
abfb497577 New translations strings.xml (Chinese Traditional) 2023-09-14 11:17:24 +02:00
Eugen Rochko
a10b184508 New translations full_description.txt (Finnish) 2023-09-13 21:32:19 +02:00
Eugen Rochko
f0ea6660e6 New translations strings.xml (Finnish) 2023-09-13 21:32:18 +02:00
Eugen Rochko
a829f25d56 New translations strings.xml (Thai) 2023-09-13 20:36:48 +02:00
Eugen Rochko
deff3dd8e0 New translations strings.xml (Finnish) 2023-09-13 20:36:47 +02:00
EndermanCo
dab596f527 Translated using Weblate (Persian)
Currently translated at 55.5% (10 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-09-13 09:53:07 +00:00
EndermanCo
0c18ab2319 Translated using Weblate (Persian)
Currently translated at 95.5% (369 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-09-13 09:53:07 +00:00
Eugen Rochko
6c5fb5ea09 New translations strings.xml (Dutch) 2023-09-12 12:25:35 +02:00
Eugen Rochko
afe0c9e0db New translations strings.xml (Dutch) 2023-09-12 10:19:31 +02:00
Eugen Rochko
1f2213042f New translations strings.xml (Urdu (India)) 2023-09-12 06:51:43 +02:00
Eugen Rochko
5edd2466f9 New translations strings.xml (Kabyle) 2023-09-12 06:51:42 +02:00
Eugen Rochko
f3b3a1a577 New translations strings.xml (Igbo) 2023-09-12 06:51:41 +02:00
Eugen Rochko
068619b815 New translations strings.xml (Occitan) 2023-09-12 06:51:40 +02:00
Eugen Rochko
f121e94979 New translations strings.xml (Scottish Gaelic) 2023-09-12 06:51:39 +02:00
Eugen Rochko
b5b52529d4 New translations strings.xml (Sinhala) 2023-09-12 06:51:38 +02:00
Eugen Rochko
876bf73454 New translations strings.xml (Bosnian) 2023-09-12 06:51:37 +02:00
Eugen Rochko
522dbf6e4a New translations strings.xml (Filipino) 2023-09-12 06:51:36 +02:00
Eugen Rochko
ae685095ba New translations strings.xml (Burmese) 2023-09-12 06:51:35 +02:00
Eugen Rochko
30d5fe2f12 New translations strings.xml (Hindi) 2023-09-12 06:51:34 +02:00
Eugen Rochko
2bf27c561c New translations strings.xml (Croatian) 2023-09-12 06:51:33 +02:00
Eugen Rochko
bbdc72323d New translations strings.xml (Thai) 2023-09-12 06:51:31 +02:00
Eugen Rochko
6e335930f3 New translations strings.xml (Bengali) 2023-09-12 06:51:31 +02:00
Eugen Rochko
9b309939da New translations strings.xml (Persian) 2023-09-12 06:51:30 +02:00
Eugen Rochko
faf2e5115d New translations strings.xml (Indonesian) 2023-09-12 06:51:28 +02:00
Eugen Rochko
dc5d9412c8 New translations strings.xml (Portuguese, Brazilian) 2023-09-12 06:51:27 +02:00
Eugen Rochko
fc0680d66f New translations strings.xml (Icelandic) 2023-09-12 06:51:26 +02:00
Eugen Rochko
56c9a5433f New translations strings.xml (Galician) 2023-09-12 06:51:25 +02:00
Eugen Rochko
60e473ee55 New translations strings.xml (Vietnamese) 2023-09-12 06:51:24 +02:00
Eugen Rochko
ae34ecd5c3 New translations strings.xml (Chinese Traditional) 2023-09-12 06:51:23 +02:00
Eugen Rochko
fd1caa8729 New translations strings.xml (Chinese Simplified) 2023-09-12 06:51:22 +02:00
Eugen Rochko
1182e5c60c New translations strings.xml (Ukrainian) 2023-09-12 06:51:21 +02:00
Eugen Rochko
d99d515dfa New translations strings.xml (Turkish) 2023-09-12 06:51:20 +02:00
Eugen Rochko
70a15e7d9c New translations strings.xml (Swedish) 2023-09-12 06:51:19 +02:00
Eugen Rochko
1691382369 New translations strings.xml (Slovenian) 2023-09-12 06:51:18 +02:00
Eugen Rochko
b7da9c6d51 New translations strings.xml (Russian) 2023-09-12 06:51:17 +02:00
Eugen Rochko
3426538dca New translations strings.xml (Portuguese) 2023-09-12 06:51:16 +02:00
Eugen Rochko
63de2b200b New translations strings.xml (Polish) 2023-09-12 06:51:15 +02:00
Eugen Rochko
ff1ee766dc New translations strings.xml (Norwegian) 2023-09-12 06:51:14 +02:00
Eugen Rochko
f033411adf New translations strings.xml (Dutch) 2023-09-12 06:51:13 +02:00
Eugen Rochko
a738eaf8c0 New translations strings.xml (Korean) 2023-09-12 06:51:12 +02:00
Eugen Rochko
5074aadd6e New translations strings.xml (Japanese) 2023-09-12 06:51:11 +02:00
Eugen Rochko
0854961470 New translations strings.xml (Italian) 2023-09-12 06:51:10 +02:00
Eugen Rochko
227b077935 New translations strings.xml (Armenian) 2023-09-12 06:51:09 +02:00
Eugen Rochko
1e4358290a New translations strings.xml (Hungarian) 2023-09-12 06:51:08 +02:00
Eugen Rochko
925169eb31 New translations strings.xml (Hebrew) 2023-09-12 06:51:07 +02:00
Eugen Rochko
e1abeb9252 New translations strings.xml (Irish) 2023-09-12 06:51:07 +02:00
Eugen Rochko
cbe0add211 New translations strings.xml (Finnish) 2023-09-12 06:51:06 +02:00
Eugen Rochko
299b524d62 New translations strings.xml (Basque) 2023-09-12 06:51:05 +02:00
Eugen Rochko
31c094e696 New translations strings.xml (Greek) 2023-09-12 06:51:04 +02:00
Eugen Rochko
a8038a2863 New translations strings.xml (German) 2023-09-12 06:51:02 +02:00
Eugen Rochko
29933bb916 New translations strings.xml (Danish) 2023-09-12 06:51:01 +02:00
Eugen Rochko
5ec0c078d8 New translations strings.xml (Czech) 2023-09-12 06:51:00 +02:00
Eugen Rochko
e6287f1ff2 New translations strings.xml (Catalan) 2023-09-12 06:50:59 +02:00
Eugen Rochko
be9caf8905 New translations strings.xml (Belarusian) 2023-09-12 06:50:58 +02:00
Eugen Rochko
f375142084 New translations strings.xml (Arabic) 2023-09-12 06:50:57 +02:00
Eugen Rochko
fd3668d520 New translations strings.xml (Spanish) 2023-09-12 06:50:56 +02:00
Eugen Rochko
d5e03e9d9e New translations strings.xml (French) 2023-09-12 06:50:55 +02:00
Eugen Rochko
d62f094919 New translations strings.xml (Romanian) 2023-09-12 06:50:54 +02:00
Grishka
6d84f28600 Hashtag following
closes #684, closes #233
2023-09-12 07:49:14 +03:00
Grishka
209e603f2c oops 2023-09-12 06:05:45 +03:00
Grishka
1b4dc01c74 Post translation
closes #267, closes #671, closes #502
2023-09-12 06:00:40 +03:00
Andrewblasco
6aab8f6578 Translated using Weblate (Spanish)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-12 02:43:45 +00:00
Grishka
645af12c3f Merge branch 'l10n_master' 2023-09-12 02:32:38 +03:00
Grishka
fadc42d72b New version 2023-09-12 02:32:23 +03:00
Eugen Rochko
fc831e7d42 New translations strings.xml (Portuguese, Brazilian) 2023-09-11 22:36:20 +02:00
Eugen Rochko
2998ee9145 New translations strings.xml (Finnish) 2023-09-11 20:09:41 +02:00
Eugen Rochko
971c4e5879 New translations strings.xml (Finnish) 2023-09-11 19:00:28 +02:00
Linerly
48c53ee88b Translated using Weblate (Indonesian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2023-09-11 14:53:07 +00:00
Linerly
acf1fa15da Translated using Weblate (Indonesian)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-09-11 14:53:07 +00:00
poesty
1c3b28f9d7 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (385 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-09-11 14:53:07 +00:00
Eugen Rochko
b396ee7987 New translations strings.xml (Indonesian) 2023-09-10 15:07:27 +02:00
butterflyoffire
90856a414a Translated using Weblate (Arabic)
Currently translated at 16.6% (3 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ar/
2023-09-09 20:53:07 +00:00
butterflyoffire
ea19925be6 Translated using Weblate (Arabic)
Currently translated at 69.1% (267 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-09 20:53:07 +00:00
ihor_ck
03b3775843 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-09-09 20:53:07 +00:00
edxkl
38b39751ae Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.1% (375 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-09-09 20:53:07 +00:00
Oliebol
54a4b0fe41 Translated using Weblate (Dutch)
Currently translated at 81.8% (316 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-09-09 20:53:07 +00:00
Choukajohn
3bf591c944 Translated using Weblate (French)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-09-09 20:53:06 +00:00
gallegonovato
584a6bbfa3 Translated using Weblate (Spanish)
Currently translated at 100.0% (386 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-09 20:53:06 +00:00
Eugen Rochko
0f803cd4fa New translations strings.xml (Finnish) 2023-09-09 20:30:25 +02:00
Eugen Rochko
167a14b8db New translations strings.xml (Finnish) 2023-09-09 19:29:29 +02:00
Eugen Rochko
81cbc2d10c New translations strings.xml (Ukrainian) 2023-09-09 15:40:28 +02:00
Eugen Rochko
9bd8aff99b New translations strings.xml (Finnish) 2023-09-09 12:08:15 +02:00
Eugen Rochko
a770828165 New translations strings.xml (Finnish) 2023-09-09 11:09:40 +02:00
Eugen Rochko
ab457035ff New translations strings.xml (Finnish) 2023-09-09 08:34:27 +02:00
Grishka
f886e4c1d2 Fix #658, fix #620 2023-09-09 03:39:27 +03:00
sk
380e4ff77e remove unused member 2023-09-09 01:48:49 +02:00
sk
58f0c07357 determine next display item using items list
closes sk22#815
2023-09-09 01:27:32 +02:00
sk
77dee59b9c fix string and tweak banner margin
closes sk22#812
2023-09-09 01:24:36 +02:00
edxkl
464dc93d99 Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.8% (368 of 384 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-09-08 20:22:51 +00:00
gallegonovato
dcdfd3e5d3 Translated using Weblate (Spanish)
Currently translated at 100.0% (384 of 384 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-08 20:22:51 +00:00
sk
646f83ff0a boop verison 2023-09-08 22:19:41 +02:00
sk
fdf0414698 fix missing banner icons and wrong strings
closes sk22#805
2023-09-08 22:05:06 +02:00
sk
cc699a3f5e fix spacing stuff in report fragment 2023-09-08 21:58:08 +02:00
LucasGGamerM
12eaa8d5f1 fix: fix window insets on ScheduledStatusListFragment
cc: @sk22
2023-09-08 21:49:29 +02:00
sk22
70680e39c6 Translated using Weblate (German)
Currently translated at 100.0% (384 of 384 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-09-08 19:46:45 +00:00
sk
8bd8f90d58 remove unused strings 2023-09-08 21:44:31 +02:00
edxkl
54b53a266e Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.2% (362 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-09-08 19:40:59 +00:00
sk22
66921e3b5a Translated using Weblate (German)
Currently translated at 97.1% (377 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-09-08 19:40:59 +00:00
sk22
9d7af3964b Translated using Weblate (English)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2023-09-08 19:40:59 +00:00
ihor_ck
ec73687e9b Translated using Weblate (Ukrainian)
Currently translated at 100.0% (382 of 382 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-09-08 19:17:03 +00:00
Choukajohn
c8af800b88 Translated using Weblate (French)
Currently translated at 100.0% (382 of 382 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-09-08 19:17:02 +00:00
gallegonovato
e74ac5da56 Translated using Weblate (Spanish)
Currently translated at 99.4% (380 of 382 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-08 19:17:02 +00:00
sk
efa003a9a5 implement bidirectional missing posts gap 2023-09-08 21:16:42 +02:00
butterflyoffire
de5165434d Translated using Weblate (Arabic)
Currently translated at 16.6% (3 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ar/
2023-09-08 15:43:13 +00:00
sk
be648cc5ab Merge remote-tracking branch 'upstream/l10n_master' 2023-09-08 17:42:47 +02:00
sk
90f1f464dc reset strings.xml to upstream 2023-09-08 17:41:30 +02:00
sk
734aa52816 Merge remote-tracking branch 'weblate/main' 2023-09-08 17:37:31 +02:00
sk
068d42175e Merge remote-tracking branch 'upstream/master' 2023-09-08 17:37:00 +02:00
sk
2314871246 temporary fix for pre-release users 2023-09-08 17:36:17 +02:00
butterflyoffire
e4f13c900b Translated using Weblate (Arabic)
Currently translated at 67.5% (250 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-07 19:23:10 +00:00
ppnplus
4ddfa483d4 Translated using Weblate (Thai)
Currently translated at 23.5% (87 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/th/
2023-09-07 19:23:10 +00:00
butterflyoffire
20f41ce7c9 Translated using Weblate (Kabyle)
Currently translated at 0.5% (2 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/kab/
2023-09-07 19:23:10 +00:00
Arkxv
c8df9e085e Translated using Weblate (Japanese)
Currently translated at 78.3% (290 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ja/
2023-09-07 19:23:10 +00:00
GunChleoc
0238aa4375 Translated using Weblate (Gaelic)
Currently translated at 84.3% (312 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gd/
2023-09-07 19:23:09 +00:00
butterflyoffire
79d7873790 Translated using Weblate (French)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-09-07 19:23:09 +00:00
kallekn
996842489d Translated using Weblate (Finnish)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-09-07 19:23:09 +00:00
Andrewblasco
23c2c2b5e7 Translated using Weblate (Spanish)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-07 19:23:08 +00:00
sk
9dd694ce2e Merge branch 'merge/load-more-direction' 2023-09-07 18:32:21 +02:00
FineFindus
f51f2a1197 fix: use random account id in notification endpoint (#806)
Closes https://github.com/sk22/megalodon/issues/803. This was due to registering with the actual accounId, whilst saving a random one. Once receiving a notification, the id could not be found.
2023-09-07 18:28:32 +02:00
LucasGGamerM
3020cab243 fix: fixes crashes when currentQuery is null and suicide prevention dialog is enabled (#807)
cc: @FineFindus
2023-09-07 10:03:22 +02:00
Eugen Rochko
be73c9e81c New translations strings.xml (Basque) 2023-09-07 02:28:42 +02:00
Eugen Rochko
1c2183bf1a New translations strings.xml (Slovenian) 2023-09-06 22:29:03 +02:00
Gregory K
1789d90dc3 Merge pull request #685 from LucasGGamerM/mastodon-android
fix(editing-alt-text): fix small oversight on editing existing attachments without alt text
2023-09-06 01:42:41 +03:00
LucasGGamerM
57306ff7fe fix(editing-alt-text): fix small oversight on editing existing attachments without alt text
This makes the implementation hopefully bug free
2023-09-05 19:37:12 -03:00
sk
2aba90f353 add media indicator for spoiler
closes sk22#598
2023-09-05 00:18:47 +02:00
sk
5065c7e7e2 add dummy to add spacing
closes sk22#782
2023-09-04 23:42:00 +02:00
sk
a10e661b21 fix wrong info banner color
closes sk22#790
2023-09-04 23:37:34 +02:00
sk
4975bde76f fix tab layout horizontal paddings 2023-09-04 23:33:35 +02:00
FineFindus
ebbd56e3bc feat(search): show suicide help dialog (#767)
* feat(search): show suicide help dialog

* change wording, add helpline url, change behavior

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-09-04 23:07:24 +02:00
Jacoco
454ec6b4c0 Fix errors when some entries were missing when retrieving account information (#757)
* Handle null avatar

* Handle empty account
2023-09-04 22:24:17 +02:00
FineFindus
10a8b195b1 fix: move tabbar padding to tabbar items (#792)
* feat: increase padding without labels

* fix: move tabbar padding to individual items
2023-09-04 22:19:47 +02:00
sk
6f273df060 use single-line linear layout 2023-09-04 19:54:07 +02:00
sk
7cfade62d3 fix click listener target 2023-09-04 19:53:33 +02:00
starstuff
0a338ad607 Translated using Weblate (Swedish)
Currently translated at 41.6% (154 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sv/
2023-09-04 08:05:19 +00:00
Arkxv
0cb3e1863e Translated using Weblate (Japanese)
Currently translated at 5.4% (20 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ja/
2023-09-04 08:05:19 +00:00
kallekn
209081f1f0 Translated using Weblate (Finnish)
Currently translated at 0.8% (3 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-09-04 08:05:19 +00:00
Eugen Rochko
f0eb6573f4 New translations strings.xml (Portuguese, Brazilian) 2023-09-04 08:10:24 +02:00
Eugen Rochko
e7f5dd3357 New translations strings.xml (Bengali) 2023-09-04 07:10:06 +02:00
Eugen Rochko
8101bb9ea1 New translations strings.xml (Portuguese, Brazilian) 2023-09-04 07:10:05 +02:00
butterflyoffire
54d48253d5 Translated using Weblate (Arabic)
Currently translated at 12.4% (46 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-04 00:53:06 +00:00
ca
3373b2bb04 Translated using Weblate (Catalan)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ca/
2023-09-04 00:53:06 +00:00
ca
a7e23aa228 Translated using Weblate (Catalan)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2023-09-04 00:53:06 +00:00
FineFindus
8cd55fc365 feat: display icon for bots (#793)
* feat(profile): display bot icon for bots

* feat(status): display bot icon

* use 16sp size and 4sp spacing

* don't add lock/bot icon as image spans

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-09-03 21:34:22 +02:00
LucasGGamerM
f14df2bb0f fix: allows for editing timeline badges again. fixes sk22#800 (#804) 2023-09-03 20:49:29 +02:00
Eugen Rochko
228fdc8ffe New translations strings.xml (Swedish) 2023-09-03 11:26:37 +02:00
Angelo Suzuki
2d24e50ff2 Add a setting for "Load missing posts behavior"
This will make sure that items that are filtered out don't show up on the interface.
Fixes sk22#311
2023-09-01 21:51:14 +02:00
Jacoco
53369eb2d4 Fix unreliable Preferences from Account Source (#798)
* Create empty Preferences object on error

* Update prefs from account when preferences fails
2023-09-01 21:28:02 +02:00
Eugen Rochko
e9df125cde New translations strings.xml (Swedish) 2023-09-01 16:10:32 +02:00
sk
807010893a support static url for emoji reacts and keyboard 2023-09-01 14:38:55 +02:00
sk
ea01b14ffb more options for showing emoji reactions
closes sk22#796
re: sk22#788
2023-09-01 14:23:38 +02:00
arnav
3fd9dc1dcd Translated using Weblate (Hindi)
Currently translated at 4.3% (16 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/hi/
2023-08-31 23:18:52 +00:00
sk
02a4a77885 Merge remote-tracking branch 'weblate/main' 2023-09-01 01:18:30 +02:00
sk
651090a504 Merge remote-tracking branch 'upstream/master' 2023-09-01 01:17:18 +02:00
sk
203254c9f4 fix crash in onEmojiReactionsChanged 2023-09-01 01:16:52 +02:00
Gregory K
16ef577a7a Merge pull request #678 from LucasGGamerM/mastodon-android
fix: fix alt texts not being able to be edited
2023-08-31 20:31:39 +03:00
LucasGGamerM
734b3bced6 fix: fix alt texts not being able to be edited
fixes #70 cc: @sk22
2023-08-31 14:18:32 -03:00
sk
e26c641dc7 fix drafts being all on the same-ish day 2023-08-31 18:07:43 +02:00
sk
9295cf4e9c fix emoji reaction spacing not updating
closes sk22#784
2023-08-31 17:24:29 +02:00
sk
dd9237e9ca enable emojiReactionsInTimelines by default 2023-08-31 17:20:44 +02:00
sk
ea81c1fad6 Merge remote-tracking branch 'upstream/master' 2023-08-31 17:09:18 +02:00
sk
d334703c65 adhere to showEmojiReactionsInLists setting
closes sk22#788
2023-08-31 17:04:22 +02:00
Gregory K
5f6f3c94c9 Merge pull request #677 from tinsukE/gap-local-filter
When loading gap posts, apply filters before building display items.
2023-08-31 15:06:07 +03:00
Angelo Suzuki
09ba42a974 When loading gap posts, apply filters before building display items.
This will make sure that items that are filtered out don't show up on the interface.
Fixes #675
2023-08-31 14:01:58 +02:00
ihor_ck
b1e43d6f97 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-08-30 18:04:05 +00:00
ppnplus
ea92a61d13 Translated using Weblate (Thai)
Currently translated at 20.5% (76 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/th/
2023-08-30 18:04:05 +00:00
Linerly
7fda69a6aa Translated using Weblate (Indonesian)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-30 18:04:05 +00:00
gallegonovato
cf8b9ac649 Translated using Weblate (Spanish)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-30 18:04:05 +00:00
ppnplus
3c122b005d Translated using Weblate (Thai)
Currently translated at 3.7% (14 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/th/
2023-08-29 22:37:15 +00:00
edxkl
f9dc6105f4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.5% (361 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-08-29 22:37:15 +00:00
Oliebol
d7fe3c80e6 Translated using Weblate (Dutch)
Currently translated at 82.9% (307 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-08-29 22:37:15 +00:00
Choukajohn
e996deea0b Translated using Weblate (French)
Currently translated at 100.0% (370 of 370 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-08-29 22:37:14 +00:00
S1m
580ae15af6 Fix unifiedpush (#785)
* [UnifiedPush] Register the new endpoint

* [UnifiedPush] Get account linked to instance
2023-08-29 12:22:12 +02:00
Eugen Rochko
d76e823489 New translations strings.xml (Italian) 2023-08-29 11:52:38 +02:00
sk
e66078e52e fix poll options outline provider
closes sk22#702
2023-08-29 00:53:02 +02:00
FineFindus
f84356f5d0 fix: display 'Lists with' with username (#780) 2023-08-29 00:19:34 +02:00
sk
1fa5a8436b highlight verified links again!
closes sk22#713
2023-08-29 00:18:12 +02:00
sk
2a471ffa96 fix broken "edit avatar" overlay.. again!!
closes sk22#727
closes sk22#738
2023-08-28 23:48:18 +02:00
sk
1ee5e1ab3a fix cut-off settings item titles
closes sk22#723
2023-08-28 23:42:34 +02:00
sk
4d90cad034 Merge remote-tracking branch 'weblate/main' 2023-08-28 23:35:18 +02:00
sk
45615b1fc5 Merge remote-tracking branch 'upstream/l10n_master' 2023-08-28 23:35:04 +02:00
sk
9fd0e7fea4 return if fcm device token is empty
closes sk22#779
2023-08-28 23:33:28 +02:00
sk
696016bd8f use hasSpoiler method 2023-08-28 23:29:18 +02:00
sk
cc46e09853 fix issue with visibility button
closes sk22#740
2023-08-28 23:24:56 +02:00
sk
83e84836b5 fix slightly wrong margins
closes sk22#778
2023-08-28 22:47:43 +02:00
sk
14bb544344 replace donation link 2023-08-28 22:35:17 +02:00
sk
ceec18ff5e fix divider not being full-width 2023-08-28 22:33:19 +02:00
sk
d36ad43700 fix reporting crashing the app 2023-08-28 22:26:53 +02:00
sk
fb39f74ba5 fix bottom padding for above emoji reactions 2023-08-28 20:22:16 +02:00
sk
9bfc73d6ee fix wrong bottom padding
hopefully, lol
2023-08-28 20:04:52 +02:00
EndermanCo
efb72eace9 Translated using Weblate (Persian)
Currently translated at 50.0% (9 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-08-28 14:53:05 +00:00
edxkl
84b15f4a49 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.5% (360 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-08-28 14:53:05 +00:00
ca
2c793fd83b Translated using Weblate (Catalan)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2023-08-28 14:53:05 +00:00
Eugen Rochko
900b204bb0 New translations strings.xml (Portuguese, Brazilian) 2023-08-27 16:51:00 +02:00
Eugen Rochko
17d679901a New translations strings.xml (Japanese) 2023-08-27 15:42:52 +02:00
Eugen Rochko
d8036779f8 New translations strings.xml (Japanese) 2023-08-27 14:46:15 +02:00
0que
3a35674ea2 Translated using Weblate (Russian)
Currently translated at 77.7% (14 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2023-08-27 05:53:05 +00:00
0que
3235cf1c4f Translated using Weblate (Russian)
Currently translated at 89.7% (331 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-08-27 05:53:04 +00:00
Eugen Rochko
3f6bda28b3 New translations strings.xml (Vietnamese) 2023-08-26 17:43:48 +02:00
Eugen Rochko
c0b4f4dd79 New translations strings.xml (Vietnamese) 2023-08-26 16:06:27 +02:00
starstuff
2a913e26e7 Translated using Weblate (Swedish)
Currently translated at 41.4% (153 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sv/
2023-08-25 14:53:06 +00:00
edxkl
f60375cd5f Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.0% (358 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-08-25 14:53:06 +00:00
poesty
5920270899 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-08-25 14:53:06 +00:00
Eugen Rochko
f36aee44c6 New translations strings.xml (Scottish Gaelic) 2023-08-25 09:54:23 +02:00
Eugen Rochko
cd24526a9d New translations strings.xml (Swedish) 2023-08-24 17:48:37 +02:00
Eugen Rochko
a345ac1390 New translations strings.xml (Icelandic) 2023-08-24 17:48:36 +02:00
Eugen Rochko
3d987b8e1d New translations strings.xml (Thai) 2023-08-23 21:39:07 +02:00
Eugen Rochko
57043912e0 New translations strings.xml (Chinese Traditional) 2023-08-23 19:16:40 +02:00
Eugen Rochko
00aef5ea6b New translations full_description.txt (Arabic) 2023-08-23 13:02:31 +02:00
Eugen Rochko
369b69668c New translations strings.xml (Arabic) 2023-08-23 13:02:29 +02:00
Eugen Rochko
65245f4560 New translations strings.xml (Arabic) 2023-08-23 09:39:50 +02:00
Eugen Rochko
4d4fdc97d4 New translations strings.xml (French) 2023-08-23 09:39:49 +02:00
Eugen Rochko
c96577891c New translations strings.xml (Scottish Gaelic) 2023-08-23 07:00:18 +02:00
Eugen Rochko
f48b2fc9cb New translations strings.xml (Thai) 2023-08-23 07:00:13 +02:00
Eugen Rochko
2fca2580ed New translations strings.xml (Bengali) 2023-08-23 07:00:12 +02:00
Eugen Rochko
7adc1da361 New translations strings.xml (Persian) 2023-08-23 07:00:11 +02:00
Eugen Rochko
6dc24dde43 New translations strings.xml (Indonesian) 2023-08-23 07:00:10 +02:00
Eugen Rochko
4929e0e6ec New translations strings.xml (Portuguese, Brazilian) 2023-08-23 07:00:09 +02:00
Eugen Rochko
16a8b8ed71 New translations strings.xml (Icelandic) 2023-08-23 07:00:08 +02:00
Eugen Rochko
ad1412817e New translations strings.xml (Galician) 2023-08-23 07:00:07 +02:00
Eugen Rochko
d9e6bb3bea New translations strings.xml (Vietnamese) 2023-08-23 07:00:06 +02:00
Eugen Rochko
8970404638 New translations strings.xml (Chinese Traditional) 2023-08-23 07:00:05 +02:00
Eugen Rochko
2a2241d7f9 New translations strings.xml (Chinese Simplified) 2023-08-23 07:00:04 +02:00
Eugen Rochko
db1a47e8eb New translations strings.xml (Ukrainian) 2023-08-23 07:00:03 +02:00
Eugen Rochko
3e57061cef New translations strings.xml (Turkish) 2023-08-23 07:00:02 +02:00
Eugen Rochko
cd200f8450 New translations strings.xml (Slovenian) 2023-08-23 07:00:00 +02:00
Eugen Rochko
782013079f New translations strings.xml (Russian) 2023-08-23 06:59:59 +02:00
Eugen Rochko
e5db8acd66 New translations strings.xml (Polish) 2023-08-23 06:59:57 +02:00
Eugen Rochko
1a6a8019c8 New translations strings.xml (Norwegian) 2023-08-23 06:59:57 +02:00
Eugen Rochko
e935eef29f New translations strings.xml (Dutch) 2023-08-23 06:59:56 +02:00
Eugen Rochko
381defda51 New translations strings.xml (Japanese) 2023-08-23 06:59:54 +02:00
Eugen Rochko
02ae80c204 New translations strings.xml (Italian) 2023-08-23 06:59:53 +02:00
Eugen Rochko
82214b30e8 New translations strings.xml (Armenian) 2023-08-23 06:59:52 +02:00
Eugen Rochko
33a1f48602 New translations strings.xml (Greek) 2023-08-23 06:59:48 +02:00
Eugen Rochko
aee845e5cc New translations strings.xml (German) 2023-08-23 06:59:47 +02:00
Eugen Rochko
cd780f6006 New translations strings.xml (Danish) 2023-08-23 06:59:46 +02:00
Eugen Rochko
d4741fefa0 New translations strings.xml (Czech) 2023-08-23 06:59:46 +02:00
Eugen Rochko
7e1e8a2616 New translations strings.xml (Belarusian) 2023-08-23 06:59:44 +02:00
Eugen Rochko
d73c05cdfc New translations strings.xml (Arabic) 2023-08-23 06:59:43 +02:00
Eugen Rochko
78323023cb New translations strings.xml (Spanish) 2023-08-23 06:59:42 +02:00
Eugen Rochko
2cf084c98f New translations strings.xml (French) 2023-08-23 06:59:41 +02:00
1118 changed files with 11709 additions and 11797 deletions

3
.github/FUNDING.yml vendored
View File

@@ -1,7 +1,6 @@
# These are supported funding model platforms
github: LucasGGamerM
custom: ["https://liberapay.com/LucasGGamerM/donate", liberapay.com]
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
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel

View File

@@ -22,6 +22,8 @@ Steps to reproduce the behavior:
**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.
@@ -33,7 +35,7 @@ If applicable, add screenshots (and screen recordings, if possible) to help expl
**Version**
Moshidon version: [e.g. v1.1.4+fork.#]
Megalodon version: [e.g. v1.1.4+fork.#]
**Crash log**

View File

@@ -1,70 +0,0 @@
name: Nightly builds
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Appkit Repo
uses: actions/checkout@v3
with:
repository: grishka/appkit
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
cache: gradle
- name: Comment out signing config in appkits gradle file
run: |
sed -i 's/sign publishing\.publications\.release/\/\/ sign publishing.publications.release/' appkit/maven-push.gradle
- name: Grant execute permission for gradlew for Appkit
run: chmod +x gradlew
- name: Compile appkit
run: ./gradlew publishToMavenLocal
- uses: actions/checkout@v3
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
cache: gradle
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Decode Keystore
id: decode_keystore
uses: timheuer/base64-to-file@v1
with:
fileName: 'nightly_keystore.jks'
fileDir: './mastodon/keystore/'
encodedString: ${{ secrets.KEYSTORE }}
- name: Build with Gradle
run: ./gradlew assembleNightly
env:
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
CURRENT_DATE: ${{ steps.date.outputs.date }}
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.2
with:
name: moshidon-nightly.apk
path: ./mastodon/build/outputs/apk/nightly/moshidon-nightly.apk

2
.gitignore vendored
View File

@@ -9,5 +9,3 @@
.cxx
local.properties
*.jks
*.keystore
/mastodon/keystore/nightly_keystore.keystore

9
FAQ.md
View File

@@ -1,9 +0,0 @@
## F.A.Q
Q: What are the main differences between Moshidon and Megalodon?
A: There are many, but the most outstanding differences are: the ability to have other server's local timeline inside the app. It can be acessed in the "Add community" option in the top right corner of the Edit timelines screen. Other outstanding features that Moshidon has are some quality of life improvements, such as notification actions and allowing for unlisted replies by default. Most other features are pretty minor, such as profile notes directly available in the person's profile. Other features are quite minor usability and visibility improvements. All of which can be found in the settings page.
Q: Will there ever be a versjon of Moshidon for iOS?
A: No. As android and iOS apps do not share code, it is incredibly hard to port.

231
README.md
View File

@@ -1,123 +1,128 @@
![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.
[![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)
[![Download nightly release](https://img.shields.io/badge/dynamic/json?color=282C37&label=Download%20Nightly%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-nightly/releases/latest/download/moshidon-nightly.apk)
[![Translation status](https://translate.codeberg.org/widgets/moshidon/-/svg-badge.svg)](https://translate.codeberg.org/engage/moshidon/)
[![Translation status](https://translate.codeberg.org/widgets/megalodon/-/svg-badge.svg)](https://translate.codeberg.org/engage/megalodon/)
&nbsp;
[![Nightly build](https://github.com/LucasGGamerM/moshidon/actions/workflows/nightly-builds.yml/badge.svg)](https://github.com/LucasGGamerM/moshidon/actions/workflows/nightly-builds.yml)
[![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.moshinda"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
<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="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
## Help out the project by donating at: https://github.com/sponsors/LucasGGamerM!
### We also support LiberaPay at: https://liberapay.com/LucasGGamerM/donate (Currently broken)
> A fork of the [Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app, focusing on [Glitch](https://glitch-soc.github.io/docs) compatibility, a pretty UI and adding new features that I feel make using the Fediverse a more pleasant experience.
### You can also donate some Monero through this wallet address as well:
4886mdarcyB6Yf8Qc6vDJBK1fz6ibHFLZUmHb4GZZz9yLGNhcG3XC64e5UZ8dVQYTLZb82W6P9WhteowW4STJEec97Gf22j
---
## Key features
### **The ability to add other server's local timeline to your timelines**
It can be accessed in the "Edit timelines" menu, where you can add a new "Community" to see other server's local posts!
### **View remote profiles**
You can now see all of a profile follows and followers, by directly loading them from the profile's home instance. In case of a failed lookup, the app will automatically fall back to the older method.
### **Translate posts easily**
Allows you to easily translate posts in another language with a translate button! Your instance must support translation, otherwise it will not work.
### **Show posts filtered with a warning**
Allows you to have filtered posts collapsed with a warning! As shown in the screenshots:
Before | After
:-------------------------:|:-------------------------:
![Screenshot_20230205-100200edited](https://user-images.githubusercontent.com/71328265/216820539-20802dc5-e433-4511-b2d9-291d810e4ef2.png) | ![Screenshot_20230205-100203edited](https://user-images.githubusercontent.com/71328265/216820544-231b2966-f38f-4ec6-b555-d39c62433839.png)
### **Color themes**
Allows you to change theme within the app. Supports Material You, purple, pink, green, blue, red, orange, yellow and Nord!
### **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”).**
<details>
<p><summary>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”).</summary></p>
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.
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.
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).
</details>
### **Federated timeline**
**This allows you to chronologically see all Public posts from people on all other Fediverse neighborhoods your home instance is connected to.**
<details>
<p><summary>This allows you to chronologically see all Public posts from people on all other Fediverse neighborhoods your home instance is connected to.</summary></p>
Despite being one of the main features of federated social media, the Federated timeline wasnt included in the official Mastodon app supposedly, because this conflicts with Googles safety requirements for apps on the Play Store.
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!
</details>
### **Image description viewer**
### **Customizable timelines**
**Allows you to quickly check whether an image or video has an alternative text attached to it.**
<details>
<p><summary>You can customize Megalodons home tab and not only add local and federated timelines, but also pin lists and hashtags.</summary></p>
This is important to **ensure the content youre sharing is as accessible as possible** to people who cant see the images and rely on software to read back the provided content descriptions. Thankfully, its quite common for people on the Fediverse to provide such alt texts, and hopefully things stay this way!
Even better: You can rename every timeline however you please and pick a distinct icon for each timeline. This way, you can pin the hashtag “#Caturday”, rename your timeline to “CUTENESS OVERLOAD” and set <img src="img/ic_fluent_animal_cat_24_regular.svg" alt="Cat icon from Microsoft Fluent UI icons"> as its icon. :3 You can find the timelines editor by opening your home tab, tapping the `⋮` button in the top right and going to “Edit timelines”.
</details>
### **Reminder to add alt text to attached media**
### **Draft and schedule posts**
By default, Moshidon will show a warning to add alt text if your post has any attachments without any alt text. This is for better accessibility, and it can easily be bypassed and disabled in settings.
<details>
<p><summary>
Allows to prepare a post and schedule it to send it automatically at a specific time.</summary></p>
### **Pinning posts**
**This lets you can highlight important posts on your profile. A dedicated “Pinned” tab in peoples profiles shows all the posts they pinned.**
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.
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.
</details>
## 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.**
### Google Play Store
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.
[https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk](https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk)
Moshidon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)s automatic update checker. Moshidon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
<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 via IzzyOnDroid
[https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk)
<a href="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk"><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)
### F-Droid via saunarepo
[https://repo.the-sauna.icu](https://repo.the-sauna.icu/)
<a href="https://repo.the-sauna.icu"><img height="28" alt="Get it on SaunaRepo" src="img/saunarepo-badge.svg"></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!
---
Moshidon is also available in [IzzyOnDroid repo](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda), compatible with all F-Droid clients. The APK provided here is the same as the one included in the Releases.
## Release variants
### Stable variant
All downloads can be found on the [Releases](https://github.com/sk22/megalodon/releases) page. When downloading a pre-release, expect to see unfinished features and bugs. If you dont want that, just download the [latest full release](https://github.com/sk22/megalodon/releases/latest/download/megalodon.apk).
All stable version downloads can be found on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
**`megalodon.apk`**
**`moshidon.apk`**
Variant with an integrated updater. If you download Megalodon from here (and not from an app store), just download the regular `megalodon.apk`.
Variant with an integrated updater. If you download Moshidon from here (and not from an app store), just download the regular `moshidon.apk`.
**`upstream-1234abc.apk`**
### Nightly variant
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.
All nightly builds can be downloaded at [Nightly Releases](https://github.com/LucasGGamerM/moshidon-nightly/releases) page.
<!-- **`megalodon-fdroid.apk`**
**`moshidon-nightly.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
The translation for the base of the app is sourced from the upstream **Mastodon for Android** project, which you can contribute to on its Crowdin project: [https://crowdin.com/project/mastodon-for-android](https://crowdin.com/project/mastodon-for-android)
There's also a bunch of custom strings exclusive to this project that need to be translated. You can help translate **Megalodon** on Weblate: [https://translate.codeberg.org/projects/megalodon](https://translate.codeberg.org/projects/megalodon)
[![Translation status](https://translate.codeberg.org/widgets/megalodon/-/horizontal-auto.svg)](https://translate.codeberg.org/engage/megalodon)
Unstable variant with an integrated updater. It's for development and testing purposes. If you find any bugs with it, please file a bug report at our [issues](https://github.com/LucasGGamerM/moshidon/issues) page.
---
@@ -126,25 +131,16 @@ Unstable variant with an integrated updater. It's for development and testing pu
### Features
* [Adding the ability to view other server's local timelines](https://github.com/LucasGGamerM/moshidon/tree/feature/local-timelines)
* [Adding the ability to load followers and following from remote instance](https://github.com/LucasGGamerM/moshidon/tree/feature/remote-followers)
* [Adding the ability to have filtered posts show with a warning](https://github.com/LucasGGamerM/moshidon/tree/feature/filters_again)
* [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 ability to remind yourself to add alt text to images
* An indicator for if an image has alt text or not
* 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)
@@ -154,13 +150,27 @@ Unstable variant with an integrated updater. It's for development and testing pu
* [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
* Support for copying the URL to posts/accounts/… in Pixel launchers Recent apps view
* Compatibility for Akkoma Bubble timeline
* Listings of followers/following/favorites/boosts can be loaded from the origin instance (theres an option to disable this in in the settings)
* Allow opening posts/accounts in-app by sharing a URL/handle to Megalodon (Originally implemented in [Moshidon](https://github.com/LucasGGamerM/moshidon), [PR](https://github.com/sk22/megalodon/pull/531))
### Behavior
* Allow for confirmation before reblogging
* Adding a bottom option for the publish button, allowing for easier use 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))
@@ -168,6 +178,22 @@ Unstable variant with an integrated updater. It's for development and testing pu
* [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)
* [Replies are inserted below the replied-to post in thread view](https://github.com/sk22/megalodon/commit/87c37df370ec24aeea0d2dbaeb29468aa4fb5808)
* Option to auto-reveal equal content warnings in threads
### Visual
@@ -175,6 +201,17 @@ Unstable variant with an integrated updater. It's for development and testing pu
* [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)
* Visually grouped (by removing divider lines and reducing padding) threaded replies in thread view
## Building
@@ -185,18 +222,12 @@ As this app is using Java 17 features, you need JDK 17 or newer to build it. Oth
./gradlew assembleRelease
```
Note that Megalodon might be depending on an in-development version of [AppKit](https://github.com/grishka/appkit) a library by Mastodon for Androids developer. In case the used AppKit version isnt published to Maven Central yet, you might have to clone, build and publish it to your local Maven repository. For more information, see [this GitHub issue](https://github.com/mastodon/mastodon-android/issues/375#issuecomment-1507678585).
## License
This project is released under the [GPL-3 License](./LICENSE).
## Links
[F.A.Q](FAQ.md)
[Official matrix chatroom:](https://matrix.to/#/#moshidon:floss.social) https://matrix.to/#/#moshidon:floss.social
[Moshidon roadmap](https://github.com/users/LucasGGamerM/projects/1)
<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/@megalodon">
<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>

View File

@@ -9,7 +9,6 @@ buildscript {
includeModule 'com.github.UnifiedPush', 'android-connector'
}
}
mavenLocal()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.0'

View File

@@ -11,41 +11,16 @@ java {
android {
compileSdk 33
defaultConfig {
manifestPlaceholders = [oAuthScheme:"moshidon-android-auth"]
archivesBaseName = "moshidon"
applicationId "org.joinmastodon.android.moshinda"
archivesBaseName = "megalodon"
applicationId "org.joinmastodon.android.sk"
minSdk 23
targetSdk 33
versionCode 101
versionName "1.2.3+fork.101.moshinda"
versionCode 108
versionName "2.1.6+fork.108"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW']
}
signingConfigs {
nightly{
storeFile = file("keystore/nightly_keystore.jks")
storePassword System.getenv("SIGNING_STORE_PASSWORD")
if (storePassword == null) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
storePassword = properties.getProperty('SIGNING_STORE_PASSWORD')
}
keyAlias System.getenv("SIGNING_KEY_ALIAS")
if (keyAlias == null) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
keyAlias = properties.getProperty('SIGNING_KEY_ALIAS')
}
keyPassword System.getenv("SIGNING_KEY_PASSWORD")
if (keyPassword == null) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
keyPassword = properties.getProperty('SIGNING_KEY_PASSWORD')
}
}
}
buildTypes {
release {
minifyEnabled true
@@ -56,29 +31,6 @@ android {
debuggable true
versionNameSuffix '-debug'
applicationIdSuffix '.debug'
manifestPlaceholders = [oAuthScheme:"moshidon-android-debug-auth"]
}
githubRelease{
initWith release
}
nightly{
if(System.getenv("CURRENT_DATE") != null){
versionNameSuffix '-nightly+@' + System.getenv("CURRENT_DATE")
} else {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
versionNameSuffix '-nightly+@' + properties.getProperty('CURRENT_DATE')
}
applicationIdSuffix '.nightly'
signingConfig signingConfigs.nightly
manifestPlaceholders = [oAuthScheme:"moshidon-android-nightly-auth"]
}
playRelease{
initWith release
minifyEnabled true
shrinkResources true
versionNameSuffix '-play'
}
githubRelease { initWith release }
playRelease { initWith release }
@@ -94,7 +46,7 @@ android {
setRoot "src/github"
}
debug {
setRoot "src/debug"
setRoot "src/github"
}
}
namespace 'org.joinmastodon.android'
@@ -118,7 +70,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.9'
implementation 'me.grishka.appkit:appkit:1.2.14'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'

View File

@@ -45,13 +45,6 @@
-keepattributes LineNumberTable
-keepattributes *
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
#-keep class javax.** { *; }
-keep class org.joinmastodon.android.** { *; }
# Parceler library
-keep interface org.parceler.Parcel
-keep @org.parceler.Parcel class * { *; }

View File

@@ -1,378 +0,0 @@
package org.joinmastodon.android.updater;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageInstaller;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import java.io.File;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import androidx.annotation.Keep;
import okhttp3.Call;
import okhttp3.Request;
import okhttp3.Response;
@Keep
public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
private static final long CHECK_PERIOD=6*3600*1000L;
private static final String TAG="GithubSelfUpdater";
private UpdateState state=UpdateState.NO_UPDATE;
private UpdateInfo info;
private long downloadID;
private BroadcastReceiver downloadCompletionReceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent){
if(downloadID!=0 && intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)==downloadID){
MastodonApp.context.unregisterReceiver(this);
setState(UpdateState.DOWNLOADED);
}
}
};
public GithubSelfUpdaterImpl(){
SharedPreferences prefs=getPrefs();
int checkedByBuild=prefs.getInt("checkedByBuild", 0);
if(prefs.contains("version") && checkedByBuild==BuildConfig.VERSION_CODE){
info=new UpdateInfo();
info.version=prefs.getString("version", null);
info.size=prefs.getLong("apkSize", 0);
info.changelog=prefs.getString("changelog", null);
downloadID=prefs.getLong("downloadID", 0);
if(downloadID==0 || !getUpdateApkFile().exists()){
state=UpdateState.UPDATE_AVAILABLE;
}else{
DownloadManager dm=MastodonApp.context.getSystemService(DownloadManager.class);
state=dm.getUriForDownloadedFile(downloadID)==null ? UpdateState.DOWNLOADING : UpdateState.DOWNLOADED;
if(state==UpdateState.DOWNLOADING){
MastodonApp.context.registerReceiver(downloadCompletionReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
}
}else if(checkedByBuild!=BuildConfig.VERSION_CODE && checkedByBuild>0){
// We are in a new version, running for the first time after update. Gotta clean things up.
long id=getPrefs().getLong("downloadID", 0);
if(id!=0){
MastodonApp.context.getSystemService(DownloadManager.class).remove(id);
}
getUpdateApkFile().delete();
getPrefs().edit()
.remove("apkSize")
.remove("version")
.remove("apkURL")
.remove("checkedByBuild")
.remove("downloadID")
.remove("changelog")
.apply();
}
}
private SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("githubUpdater", Context.MODE_PRIVATE);
}
@Override
public void maybeCheckForUpdates(){
if(state!=UpdateState.NO_UPDATE && state!=UpdateState.UPDATE_AVAILABLE)
return;
long timeSinceLastCheck=System.currentTimeMillis()-getPrefs().getLong("lastCheck", CHECK_PERIOD);
if(timeSinceLastCheck>=CHECK_PERIOD){
setState(UpdateState.CHECKING);
MastodonAPIController.runInBackground(this::actuallyCheckForUpdates);
}
}
@Override
public void checkForUpdates() {
setState(UpdateState.CHECKING);
MastodonAPIController.runInBackground(this::actuallyCheckForUpdates);
}
private void actuallyCheckForUpdates(){
Request req=new Request.Builder()
.url("https://api.github.com/repos/LucasGGamerM/moshidon/releases")
.build();
Call call=MastodonAPIController.getHttpClient().newCall(req);
try(Response resp=call.execute()){
JsonArray arr=JsonParser.parseReader(resp.body().charStream()).getAsJsonArray();
for (JsonElement jsonElement : arr) {
JsonObject obj = jsonElement.getAsJsonObject();
if (obj.get("prerelease").getAsBoolean() && !GlobalUserPreferences.enablePreReleases) continue;
String tag=obj.get("tag_name").getAsString();
String changelog=obj.get("body").getAsString();
Pattern pattern=Pattern.compile("v?(\\d+)\\.(\\d+)\\.(\\d+)\\+fork\\.(\\d+)");
Matcher matcher=pattern.matcher(tag);
if(!matcher.find()){
Log.w(TAG, "actuallyCheckForUpdates: release tag has wrong format: "+tag);
return;
}
int newMajor=Integer.parseInt(matcher.group(1)),
newMinor=Integer.parseInt(matcher.group(2)),
newRevision=Integer.parseInt(matcher.group(3)),
newForkNumber=Integer.parseInt(matcher.group(4));
matcher=pattern.matcher(BuildConfig.VERSION_NAME);
String[] currentParts=BuildConfig.VERSION_NAME.split("[.+]");
if(!matcher.find()){
Log.w(TAG, "actuallyCheckForUpdates: current version has wrong format: "+BuildConfig.VERSION_NAME);
return;
}
int curMajor=Integer.parseInt(matcher.group(1)),
curMinor=Integer.parseInt(matcher.group(2)),
curRevision=Integer.parseInt(matcher.group(3)),
curForkNumber=Integer.parseInt(matcher.group(4));
long newVersion=((long)newMajor << 32) | ((long)newMinor << 16) | newRevision;
long curVersion=((long)curMajor << 32) | ((long)curMinor << 16) | curRevision;
if(newVersion>curVersion || newForkNumber>curForkNumber){
String version=newMajor+"."+newMinor+"."+newRevision+"+fork."+newForkNumber;
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())){
long size=asset.get("size").getAsLong();
String url=asset.get("browser_download_url").getAsString();
UpdateInfo info=new UpdateInfo();
info.size=size;
info.version=version;
info.changelog=changelog;
this.info=info;
getPrefs().edit()
.putLong("apkSize", size)
.putString("version", version)
.putString("apkURL", url)
.putString("changelog", changelog)
.putInt("checkedByBuild", BuildConfig.VERSION_CODE)
.remove("downloadID")
.apply();
break;
}
}
}
getPrefs().edit().putLong("lastCheck", System.currentTimeMillis()).apply();
break;
}
}catch(Exception x){
Log.w(TAG, "actuallyCheckForUpdates", x);
}finally{
setState(info==null ? UpdateState.NO_UPDATE : UpdateState.UPDATE_AVAILABLE);
}
}
private void setState(UpdateState state){
this.state=state;
E.post(new SelfUpdateStateChangedEvent(state));
}
@Override
public UpdateState getState(){
return state;
}
@Override
public UpdateInfo getUpdateInfo(){
return info;
}
public File getUpdateApkFile(){
return new File(MastodonApp.context.getExternalCacheDir(), "update.apk");
}
@Override
public void downloadUpdate(){
if(state==UpdateState.DOWNLOADING)
throw new IllegalStateException();
DownloadManager dm=MastodonApp.context.getSystemService(DownloadManager.class);
MastodonApp.context.registerReceiver(downloadCompletionReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
downloadID=dm.enqueue(
new DownloadManager.Request(Uri.parse(getPrefs().getString("apkURL", null)))
.setDestinationUri(Uri.fromFile(getUpdateApkFile()))
);
getPrefs().edit().putLong("downloadID", downloadID).apply();
setState(UpdateState.DOWNLOADING);
}
@Override
public void installUpdate(Activity activity){
if(state!=UpdateState.DOWNLOADED)
throw new IllegalStateException();
Uri uri;
Intent intent=new Intent(Intent.ACTION_INSTALL_PACKAGE);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
uri=new Uri.Builder().scheme("content").authority(activity.getPackageName()+".self_update_provider").path("update.apk").build();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}else{
uri=Uri.fromFile(getUpdateApkFile());
}
intent.setDataAndType(uri, "application/vnd.android.package-archive");
activity.startActivity(intent);
// TODO figure out how to restart the app when updating via this new API
/*
PackageInstaller installer=activity.getPackageManager().getPackageInstaller();
try{
final int sid=installer.createSession(new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));
installer.registerSessionCallback(new PackageInstaller.SessionCallback(){
@Override
public void onCreated(int i){
}
@Override
public void onBadgingChanged(int i){
}
@Override
public void onActiveChanged(int i, boolean b){
}
@Override
public void onProgressChanged(int id, float progress){
}
@Override
public void onFinished(int id, boolean success){
activity.getPackageManager().setComponentEnabledSetting(new ComponentName(activity, AfterUpdateRestartReceiver.class), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
});
activity.getPackageManager().setComponentEnabledSetting(new ComponentName(activity, AfterUpdateRestartReceiver.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
PackageInstaller.Session session=installer.openSession(sid);
try(OutputStream out=session.openWrite("mastodon.apk", 0, info.size); InputStream in=new FileInputStream(getUpdateApkFile())){
byte[] buffer=new byte[16384];
int read;
while((read=in.read(buffer))>0){
out.write(buffer, 0, read);
}
}
// PendingIntent intent=PendingIntent.getBroadcast(activity, 1, new Intent(activity, InstallerStatusReceiver.class), PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
PendingIntent intent=PendingIntent.getActivity(activity, 1, new Intent(activity, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(intent.getIntentSender());
}catch(IOException x){
Log.w(TAG, "installUpdate", x);
Toast.makeText(activity, x.getMessage(), Toast.LENGTH_SHORT).show();
}
*/
}
@Override
public float getDownloadProgress(){
if(state!=UpdateState.DOWNLOADING)
throw new IllegalStateException();
DownloadManager dm=MastodonApp.context.getSystemService(DownloadManager.class);
try(Cursor cursor=dm.query(new DownloadManager.Query().setFilterById(downloadID))){
if(cursor.moveToFirst()){
long loaded=cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
long total=cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
// Log.d(TAG, "getDownloadProgress: "+loaded+" of "+total);
return total>0 ? (float)loaded/total : 0f;
}
}
return 0;
}
@Override
public void cancelDownload(){
if(state!=UpdateState.DOWNLOADING)
throw new IllegalStateException();
DownloadManager dm=MastodonApp.context.getSystemService(DownloadManager.class);
dm.remove(downloadID);
downloadID=0;
getPrefs().edit().remove("downloadID").apply();
setState(UpdateState.UPDATE_AVAILABLE);
}
@Override
public void handleIntentFromInstaller(Intent intent, Activity activity){
int status=intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);
if(status==PackageInstaller.STATUS_PENDING_USER_ACTION){
Intent confirmIntent=intent.getParcelableExtra(Intent.EXTRA_INTENT);
activity.startActivity(confirmIntent);
}else if(status!=PackageInstaller.STATUS_SUCCESS){
String msg=intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
Toast.makeText(activity, activity.getString(R.string.error)+":\n"+msg, Toast.LENGTH_LONG).show();
}
}
@Override
public void reset(){
getPrefs().edit().clear().apply();
File apk=getUpdateApkFile();
if(apk.exists())
apk.delete();
state=UpdateState.NO_UPDATE;
}
/*public static class InstallerStatusReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent){
int status=intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);
if(status==PackageInstaller.STATUS_PENDING_USER_ACTION){
Intent confirmIntent=intent.getParcelableExtra(Intent.EXTRA_INTENT);
context.startActivity(confirmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}else if(status!=PackageInstaller.STATUS_SUCCESS){
String msg=intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
Toast.makeText(context, context.getString(R.string.error)+":\n"+msg, Toast.LENGTH_LONG).show();
}
}
}
public static class AfterUpdateRestartReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent){
if(Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())){
context.getPackageManager().setComponentEnabledSetting(new ComponentName(context, AfterUpdateRestartReceiver.class), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Toast.makeText(context, R.string.update_installed, Toast.LENGTH_SHORT).show();
Intent restartIntent=new Intent(context, MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setPackage(context.getPackageName());
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.P){
context.startActivity(restartIntent);
}else{
// Bypass activity starting restrictions by starting it from a notification
NotificationManager nm=context.getSystemService(NotificationManager.class);
NotificationChannel chan=new NotificationChannel("selfUpdateRestart", context.getString(R.string.update_installed), NotificationManager.IMPORTANCE_HIGH);
nm.createNotificationChannel(chan);
Notification n=new Notification.Builder(context, "selfUpdateRestart")
.setContentTitle(context.getString(R.string.update_installed))
.setContentIntent(PendingIntent.getActivity(context, 1, restartIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
.setFullScreenIntent(PendingIntent.getActivity(context, 1, restartIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE), true)
.setSmallIcon(R.drawable.ic_ntf_logo)
.build();
nm.notify(1, n);
}
}
}
}*/
}

View File

@@ -1,62 +0,0 @@
package org.joinmastodon.android.updater;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import java.io.FileNotFoundException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class SelfUpdateContentProvider extends ContentProvider{
@Override
public boolean onCreate(){
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder){
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri){
if(isCorrectUri(uri))
return "application/vnd.android.package-archive";
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values){
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs){
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs){
return 0;
}
@Nullable
@Override
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException{
if(isCorrectUri(uri)){
return ParcelFileDescriptor.open(((GithubSelfUpdaterImpl)GithubSelfUpdater.getInstance()).getUpdateApkFile(), ParcelFileDescriptor.MODE_READ_ONLY);
}
throw new FileNotFoundException();
}
private boolean isCorrectUri(Uri uri){
return "/update.apk".equals(uri.getPath());
}
}

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

@@ -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="M10 2c4.418 0 8 3.582 8 8 0 2.706-1.142 4.5-3 4.5-1.226 0-2.14-0.781-2.62-2.09C11.784 13.393 10.781 14 9.5 14 7.36 14 6 12.307 6 10c0-2.337 1.313-4 3.5-4 1.052 0 1.901 0.385 2.5 1.044V6.5C12 6.224 12.224 6 12.5 6c0.245 0 0.45 0.177 0.492 0.41L13 6.5V10c0 2.223 0.813 3.5 2 3.5s2-1.277 2-3.5c0-3.866-3.134-7-7-7s-7 3.134-7 7 3.134 7 7 7c0.823 0 1.626-0.142 2.383-0.416 0.26-0.094 0.547 0.04 0.64 0.3 0.095 0.26-0.04 0.546-0.3 0.64C11.859 17.838 10.94 18 10 18c-4.418 0-8-3.582-8-8s3.582-8 8-8zM9.5 7C7.924 7 7 8.17 7 10c0 1.797 0.966 3 2.5 3s2.5-1.203 2.5-3c0-1.83-0.924-3-2.5-3z" 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="M6.25 4.5C5.283 4.5 4.5 5.284 4.5 6.25v11.5c0 0.966 0.783 1.75 1.75 1.75h11.5c0.966 0 1.75-0.784 1.75-1.75v-4c0-0.414 0.335-0.75 0.75-0.75 0.414 0 0.75 0.336 0.75 0.75v4c0 1.795-1.456 3.25-3.25 3.25H6.25C4.455 21 3 19.545 3 17.75V6.25C3 4.455 4.455 3 6.25 3h4C10.664 3 11 3.336 11 3.75S10.664 4.5 10.25 4.5h-4zM13 3.75C13 3.336 13.335 3 13.75 3h6.5C20.664 3 21 3.336 21 3.75v6.5c0 0.414-0.336 0.75-0.75 0.75s-0.75-0.336-0.75-0.75V5.56l-5.22 5.22c-0.293 0.293-0.768 0.293-1.06 0-0.293-0.293-0.293-0.768 0-1.06l5.22-5.22h-4.69C13.335 4.5 13 4.164 13 3.75z" 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="M8.502 11.5c0.554 0 1.002 0.448 1.002 1.002 0 0.553-0.448 1.002-1.002 1.002-0.553 0-1.002-0.449-1.002-1.002 0-0.554 0.449-1.003 1.002-1.003zM12 4.353v6.651h7.442L17.72 9.28c-0.267-0.266-0.29-0.683-0.073-0.977L17.72 8.22c0.266-0.266 0.683-0.29 0.976-0.072L18.78 8.22l2.997 2.998c0.266 0.266 0.29 0.682 0.073 0.976l-0.073 0.084-2.996 3.003c-0.293 0.294-0.767 0.294-1.06 0.002-0.267-0.266-0.292-0.683-0.075-0.977l0.073-0.084 1.713-1.717h-7.431L12 19.25c0 0.466-0.421 0.82-0.88 0.738l-8.5-1.501C2.26 18.424 2 18.112 2 17.748V5.75c0-0.368 0.266-0.681 0.628-0.74l8.5-1.396C11.585 3.539 12 3.89 12 4.354zm-1.5 0.883l-7 1.15v10.732l7 1.236V5.237zM13 18.5h0.765l0.102-0.007c0.366-0.05 0.649-0.364 0.648-0.744l-0.007-4.25H13v5zm0.002-8.502L13 8.726V5h0.745c0.38 0 0.693 0.281 0.743 0.647l0.007 0.101L14.502 10h-1.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="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M14.704 3.44C14.895 3.667 15 3.953 15 4.248V19.75c0 0.69-0.56 1.25-1.25 1.25-0.296 0-0.582-0.105-0.808-0.296l-4.967-4.206H4.25c-1.243 0-2.25-1.008-2.25-2.25v-4.5c0-1.243 1.007-2.25 2.25-2.25h3.725l4.968-4.204c0.526-0.446 1.315-0.38 1.761 0.147zM13.5 4.787l-4.975 4.21H4.25c-0.414 0-0.75 0.337-0.75 0.75v4.5c0 0.415 0.336 0.75 0.75 0.75h4.275L13.5 19.21V4.787z" 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="M16.5 4.814c0-1.094-1.307-1.66-2.105-0.912l-4.937 4.63C9.134 8.836 8.706 9.005 8.261 9.005H5.25C3.455 9.005 2 10.46 2 12.255v3.492c0 1.795 1.455 3.25 3.25 3.25h3.012c0.444 0 0.872 0.17 1.196 0.473l4.937 4.626c0.799 0.748 2.105 0.182 2.105-0.912V4.814zm-6.016 4.812L15 5.39v17.216l-4.516-4.232c-0.602-0.564-1.397-0.878-2.222-0.878H5.25c-0.966 0-1.75-0.784-1.75-1.75v-3.492c0-0.966 0.784-1.75 1.75-1.75h3.011c0.826 0 1.62-0.314 2.223-0.88z" 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="M3.28 2.22c-0.293-0.293-0.767-0.293-1.06 0-0.293 0.293-0.293 0.767 0 1.06L6.438 7.5H4.25C3.007 7.499 2 8.506 2 9.749v4.497c0 1.243 1.007 2.25 2.25 2.25h3.68c0.183 0 0.36 0.068 0.498 0.19l4.491 3.994C13.725 21.396 15 20.824 15 19.746V16.06l5.72 5.72c0.292 0.292 0.767 0.292 1.06 0 0.293-0.293 0.293-0.768 0-1.061L3.28 2.22zM13.5 14.56v4.629l-4.075-3.624c-0.412-0.366-0.944-0.569-1.495-0.569H4.25c-0.414 0-0.75-0.335-0.75-0.75V9.75C3.5 9.335 3.836 9 4.25 9h3.688l5.562 5.56zm0-9.753v5.511l1.5 1.5V4.25c0-1.079-1.274-1.65-2.08-0.934l-3.4 3.022 1.063 1.063L13.5 4.807zm3.641 9.152l1.138 1.138C18.741 14.163 19 13.111 19 12c0-1.203-0.304-2.338-0.84-3.328-0.198-0.364-0.653-0.5-1.017-0.303-0.364 0.197-0.5 0.653-0.303 1.017 0.42 0.777 0.66 1.666 0.66 2.614 0 0.691-0.127 1.351-0.359 1.96zm2.247 2.247l1.093 1.094C21.445 15.763 22 13.946 22 12c0-2.226-0.728-4.284-1.96-5.946-0.246-0.333-0.716-0.403-1.048-0.157-0.333 0.247-0.403 0.716-0.157 1.05C19.881 8.358 20.5 10.106 20.5 12c0 1.531-0.404 2.966-1.112 4.206z" 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="M3.28 2.22c-0.293-0.293-0.767-0.293-1.06 0-0.293 0.293-0.293 0.767 0 1.06l5.724 5.725H5.25C3.455 9.005 2 10.46 2 12.255v3.492c0 1.795 1.455 3.25 3.25 3.25h3.012c0.444 0 0.872 0.17 1.196 0.473l4.937 4.626c0.799 0.748 2.105 0.182 2.105-0.912v-5.623l8.22 8.22c0.292 0.292 0.767 0.292 1.06 0 0.293-0.293 0.293-0.768 0-1.061L3.28 2.22zM15 16.06v6.547l-4.516-4.231c-0.602-0.565-1.397-0.879-2.222-0.879H5.25c-0.966 0-1.75-0.783-1.75-1.75v-3.492c0-0.966 0.784-1.75 1.75-1.75h3.011c0.35 0 0.693-0.056 1.02-0.164L15 16.061zm-4.378-8.62l1.061 1.061L15 5.392v6.427l1.5 1.5V4.814c0-1.094-1.307-1.66-2.105-0.912L10.622 7.44zm9.55 9.55l1.137 1.137C21.912 16.88 22.25 15.478 22.25 14c0-2.136-0.706-4.11-1.897-5.697-0.249-0.332-0.719-0.399-1.05-0.15-0.332 0.249-0.399 0.719-0.15 1.05C20.156 10.54 20.75 12.199 20.75 14c0 1.058-0.205 2.067-0.578 2.99zm2.803 2.803l1.095 1.096c1.224-2.008 1.93-4.366 1.93-6.89 0-3.35-1.245-6.414-3.298-8.747-0.274-0.31-0.747-0.341-1.058-0.068-0.311 0.274-0.342 0.748-0.068 1.059C23.396 8.313 24.5 11.027 24.5 14c0 2.107-0.554 4.084-1.525 5.793z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -1,20 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#FF000000"
android:pathData="M54,90L54,90c-19.9,0 -36,-16.1 -36,-36v0c0,-19.9 16.1,-36 36,-36h0c19.9,0 36,16.1 36,36v0C90,73.9 73.9,90 54,90z"
android:strokeAlpha="0"
android:fillAlpha="0"/>
<path
android:pathData="M52.5,41.6c-2.4,0 -4.3,0.9 -5.5,2.8l-1.2,2l-1.2,-2c-1.2,-1.9 -3.1,-2.8 -5.5,-2.8c-2.1,0 -3.8,0.8 -5.1,2.2c-1.2,1.4 -1.9,3.4 -1.9,5.9v12h4.7V50c0,-2.4 1.1,-3.7 3.1,-3.7c2.3,0 3.4,1.4 3.4,4.4v6.4h4.7v-6.4c0,-2.9 1.1,-4.4 3.4,-4.4c2.1,0 3.1,1.2 3.1,3.7v11.7h4.7v-12c0,-2.4 -0.6,-4.4 -1.9,-5.9C56.2,42.3 54.6,41.6 52.5,41.6z"
android:fillColor="#33D17A"/>
<path
android:pathData="M65.9,58.1h0.8c0,0 0,0 -0.1,0c-0.6,-0.3 -1.1,-0.8 -1.4,-1.4c-0.3,-0.6 -0.5,-1.4 -0.5,-2.1c0,-0.8 0.2,-1.5 0.5,-2.1c0.4,-0.6 0.8,-1.1 1.4,-1.4c0.6,-0.3 1.2,-0.5 1.9,-0.5c0.7,0 1.3,0.2 1.9,0.5s1.1,0.8 1.4,1.4s0.5,1.3 0.5,2.1c0,0.2 0,0.4 0,0.6l0.7,0.7c0.4,0 0.8,0 1.1,0l1.5,-1.5l0.2,-0.2c-0.1,-1.2 -0.4,-2.3 -0.9,-3.4c-0.6,-1.1 -1.4,-2 -2.6,-2.6c-1.1,-0.6 -2.4,-1 -3.7,-1c-1.4,0 -2.7,0.3 -3.8,1c-1.1,0.6 -2,1.5 -2.6,2.6c-0.6,1.1 -0.9,2.4 -0.9,3.7s0.3,2.7 0.9,3.7c0.6,1.1 1.5,2 2.6,2.6c0.4,0.2 0.8,0.4 1.1,0.5v-1.8V58.1z"
android:fillColor="#33D17A"/>
<path
android:pathData="M76,58.3l1.2,-1.2L76.2,56l-1.7,1.7c-0.4,-0.1 -0.7,-0.2 -1.1,-0.2s-0.8,0.1 -1.1,0.2L70.7,56l-1,1.1l1.2,1.2c-0.5,0.4 -1.1,0.9 -1.4,1.5h-2.1v1.5H69c0,0.2 -0.1,0.5 -0.1,0.8v0.8h-1.5v1.5h1.5v0.8c0,0.2 0,0.5 0.1,0.8h-1.6v1.5h2.1c0.8,1.4 2.3,2.3 4,2.3s3.1,-0.9 4,-2.3h2.1v-1.5H78c0,-0.2 0.1,-0.5 0.1,-0.8v-0.8h1.5v-1.5h-1.5v-0.8c0,-0.2 0,-0.5 -0.1,-0.8h1.6v-1.5h-2.1C77.1,59.2 76.6,58.8 76,58.3zM75,65.9H72v-1.5H75V65.9zM75,62.9H72v-1.5H75V62.9z"
android:fillColor="#33D17A"/>
</vector>

View File

@@ -1,20 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#FF000000"
android:pathData="M54,90L54,90c-19.9,0 -36,-16.1 -36,-36v0c0,-19.9 16.1,-36 36,-36h0c19.9,0 36,16.1 36,36v0C90,73.9 73.9,90 54,90z"
android:strokeAlpha="0"
android:fillAlpha="0"/>
<path
android:pathData="M52.5,41.6c-2.4,0 -4.3,0.9 -5.5,2.8l-1.2,2l-1.2,-2c-1.2,-1.9 -3.1,-2.8 -5.5,-2.8c-2.1,0 -3.8,0.8 -5.1,2.2c-1.2,1.4 -1.9,3.4 -1.9,5.9v12h4.7V50c0,-2.4 1.1,-3.7 3.1,-3.7c2.3,0 3.4,1.4 3.4,4.4v6.4h4.7v-6.4c0,-2.9 1.1,-4.4 3.4,-4.4c2.1,0 3.1,1.2 3.1,3.7v11.7h4.7v-12c0,-2.4 -0.6,-4.4 -1.9,-5.9C56.2,42.3 54.6,41.6 52.5,41.6z"
android:fillColor="#33D17A"/>
<path
android:pathData="M65.9,58.1h0.8c0,0 0,0 -0.1,0c-0.6,-0.3 -1.1,-0.8 -1.4,-1.4c-0.3,-0.6 -0.5,-1.4 -0.5,-2.1c0,-0.8 0.2,-1.5 0.5,-2.1c0.4,-0.6 0.8,-1.1 1.4,-1.4c0.6,-0.3 1.2,-0.5 1.9,-0.5c0.7,0 1.3,0.2 1.9,0.5s1.1,0.8 1.4,1.4s0.5,1.3 0.5,2.1c0,0.2 0,0.4 0,0.6l0.7,0.7c0.4,0 0.8,0 1.1,0l1.5,-1.5l0.2,-0.2c-0.1,-1.2 -0.4,-2.3 -0.9,-3.4c-0.6,-1.1 -1.4,-2 -2.6,-2.6c-1.1,-0.6 -2.4,-1 -3.7,-1c-1.4,0 -2.7,0.3 -3.8,1c-1.1,0.6 -2,1.5 -2.6,2.6c-0.6,1.1 -0.9,2.4 -0.9,3.7s0.3,2.7 0.9,3.7c0.6,1.1 1.5,2 2.6,2.6c0.4,0.2 0.8,0.4 1.1,0.5v-1.8V58.1z"
android:fillColor="#33D17A"/>
<path
android:pathData="M76,58.3l1.2,-1.2L76.2,56l-1.7,1.7c-0.4,-0.1 -0.7,-0.2 -1.1,-0.2s-0.8,0.1 -1.1,0.2L70.7,56l-1,1.1l1.2,1.2c-0.5,0.4 -1.1,0.9 -1.4,1.5h-2.1v1.5H69c0,0.2 -0.1,0.5 -0.1,0.8v0.8h-1.5v1.5h1.5v0.8c0,0.2 0,0.5 0.1,0.8h-1.6v1.5h2.1c0.8,1.4 2.3,2.3 4,2.3s3.1,-0.9 4,-2.3h2.1v-1.5H78c0,-0.2 0.1,-0.5 0.1,-0.8v-0.8h1.5v-1.5h-1.5v-0.8c0,-0.2 0,-0.5 -0.1,-0.8h1.6v-1.5h-2.1C77.1,59.2 76.6,58.8 76,58.3zM75,65.9H72v-1.5H75V65.9zM75,62.9H72v-1.5H75V62.9z"
android:fillColor="#33D17A"/>
</vector>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground_debug"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground_monochrome_debug"/>
</adaptive-icon>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground_debug"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground_monochrome_debug"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#000000</color>
</resources>

View File

@@ -1,14 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.joinmastodon.android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application
tools:replace="android:label"
android:label="@string/mo_app_name_debug">
<application>
<!-- <receiver android:name=".updater.GithubSelfUpdaterImpl$InstallerStatusReceiver" android:exported="false"/>-->
<!-- <receiver android:name=".updater.GithubSelfUpdaterImpl$AfterUpdateRestartReceiver" android:exported="true" android:enabled="false">-->
<!-- <intent-filter>-->

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()){
@@ -154,7 +154,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,21 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
package="org.joinmastodon.android">
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<queries>
<intent>
@@ -30,12 +25,11 @@
<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"
android:theme="@style/Theme.Mastodon.AutoLightDark"
android:windowSoftInputMode="adjustPan"
android:largeHeap="true">
<activity android:name=".MainActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize" android:launchMode="singleTask">
@@ -64,7 +58,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="${oAuthScheme}" 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"
@@ -104,16 +98,6 @@
</intent-filter>
</receiver>
<provider
android:name="org.joinmastodon.android.utils.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

@@ -1,56 +1,43 @@
13bells.com
1611.social
4aem.com
5dollah.click
adachi.party
anime.website
adtension.com
annihilation.social
anon-kenkai.com
asbestos.cafe
bae.st
bajax.us
banepo.st
baraag.net
bassam.social
battlepenguin.video
beefyboys.win
beepboop.ga
berserker.town
bikeshed.party
boks.moe
boymoder.biz
brainsoap.net
breastmilk.club
brighteon.social
bungle.online
cachapa.xyz
canary.fedinuke.example.com
catgirl.life
cawfee.club
childlove.space
clew.lol
clubcyberia.co
collapsitarian.io
comfyboy.club
contrapointsfan.club
crucible.world
cum.camp
cum.salon
darknight-coffee.org
decayable.ink
dembased.xyz
desupost.soy
detroitriotcity.com
eatthebugs.social
djsumdog.com
eientei.org
elementality.org
eveningzoo.club
firedragonstudios.com
firefaithfellowship.com
fluf.club
foxfam.club
freak.university
freeatlantis.com
freedomstrike.org
freesoftwareextremist.com
freespeech.group
freespeechextremist.com
freetalklive.com
froth.zone
fulltermprivacy.com
gameliberty.club
gearlandia.haus
genderheretics.xyz
@@ -59,42 +46,34 @@ gleasonator.com
glee.li
glindr.org
goyim.app
goyslop.cafe
h5q.net
haeder.net
handholding.io
hitchhiker.social
hunk.city
iddqd.social
intkos.link
justicewarrior.social
kawa-kun.com
kitsunemimi.club
kiwifarms.cc
kompost.cz
kurosawa.moe
kyaruc.moe
leafposter.club
leftychan.net
lewdieheaven.com
liberdon.com
ligma.pro
lolicon.rocks
lolison.network
lolison.top
lovingexpressions.net
mahodou.moe
makemysarcophagus.com
maladaptive.art
marsey.moe
masochi.st
mastinator.com
merovingian.club
midwaytrades.com
mirr0r.city
moa.st
morale.ch
mouse.services
mugicha.club
narrativerry.xyz
natehiggers.online
neckbeard.xyz
needs.vodka
neenster.org
nicecrew.digital
@@ -103,18 +82,18 @@ noagendasocial.com
noagendasocial.nl
noagendatube.com
nobodyhasthe.biz
nukem.biz
obo.sh
norwoodzero.net
nyanide.com
onionfarms.org
pawlicker.com
pawoo.net
pedo.school
peervideo.club
piazza.today
pibvt.net
pieville.net
pisskey.io
plagu.ee
pmth.us
poa.st
poast.org
poast.tv
@@ -123,17 +102,18 @@ prospeech.space
quodverum.com
r18.social
rakket.app
rapemeat.express
rapemeat.solutions
rdrama.cc
rayci.st
rebelbase.site
retardedniggers.forsale
rojogato.com
ryona.agency
sad.cab
schwartzwelt.xyz
seal.cafe
shaw.app
shigusegubu.club
shitpost.cloud
shota.house
shortstacksran.ch
silliness.observer
skinheads.eu
skinheads.io
@@ -148,23 +128,20 @@ sneed.social
sonichu.com
spinster.xyz
springbo.cc
starnix.network
strelizia.net
syspxl.xyz
tastingtraffic.net
teci.world
theapex.social
thechimp.zone
thenobody.club
thepostearthdestination.com
tkammer.de
trumpislovetrumpis.life
truthsocial.co.in
urchan.org
usualsuspects.lol
varishangout.net
whinge.house
whinge.town
wideboys.org
vtuberfan.social
wolfgirl.bar
xn--p1abe3d.xn--80asehdb
yggdrasil.social
youjo.love
zztails.gay

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 358 KiB

View File

@@ -266,7 +266,7 @@ public class AudioPlayerService extends Service{
private void updateNotification(boolean dismissable, boolean removeNotification){
Notification.Builder bldr=new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_ntf_logo)
.setContentTitle(status.account.displayName)
.setContentTitle(status.account.getDisplayName())
.setContentText(HtmlParser.strip(status.content))
.setOngoing(!dismissable)
.setShowWhen(false)
@@ -281,7 +281,7 @@ public class AudioPlayerService extends Service{
if(playerReady){
boolean isPlaying=player.isPlaying();
bldr.addAction(new Notification.Action.Builder(Icon.createWithResource(this, isPlaying ? R.drawable.ic_pause_24 : R.drawable.ic_play_24),
bldr.addAction(new Notification.Action.Builder(Icon.createWithResource(this, isPlaying ? R.drawable.ic_fluent_pause_24_filled : R.drawable.ic_fluent_play_24_filled),
getString(isPlaying ? R.string.pause : R.string.play),
PendingIntent.getBroadcast(this, 2, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_IMMUTABLE))
.build());

View File

@@ -32,10 +32,9 @@ public class ExternalShareActivity extends FragmentStackActivity{
UiUtils.setUserPreferredTheme(this);
super.onCreate(savedInstanceState);
if(savedInstanceState==null){
Optional<String> text = Optional.ofNullable(getIntent().getStringExtra(Intent.EXTRA_TEXT));
Optional<Pair<String, Optional<String>>> fediHandle = text.flatMap(UiUtils::parseFediverseHandle);
boolean isFediUrl = text.map(UiUtils::looksLikeMastodonUrl).orElse(false);
boolean isFediUrl = text.map(UiUtils::looksLikeFediverseUrl).orElse(false);
boolean isOpenable = isFediUrl || fediHandle.isPresent();
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();

View File

@@ -1,24 +1,22 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference.MATERIAL3;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import androidx.annotation.StringRes;
import android.os.Build;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.utils.ColorPalette;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -53,29 +51,19 @@ public class GlobalUserPreferences{
public static boolean collapseLongPosts;
public static boolean spectatorMode;
public static boolean autoHideFab;
public static boolean compactReblogReplyLine;
public static boolean allowRemoteLoading;
public static boolean forwardReportDefault;
public static AutoRevealMode autoRevealEqualSpoilers;
public static ColorPreference color;
public static boolean disableM3PillActiveIndicator;
public static boolean showNavigationLabels;
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
public static boolean overlayMedia;
public static boolean showSuicideHelp;
public static boolean underlinedLinks;
public static ColorPreference color;
public static boolean likeIcon;
// MOSHIDON
public static boolean showDividers;
public static boolean relocatePublishButton;
public static boolean defaultToUnlistedReplies;
public static boolean doubleTapToSwipe;
public static boolean confirmBeforeReblog;
public static boolean hapticFeedback;
public static boolean replyLineAboveHeader;
public static boolean swapBookmarkWithBoostAction;
public static boolean loadRemoteAccountFollowers;
public static boolean mentionRebloggerAutomatically;
public static SharedPreferences getPrefs(){
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
}
@@ -123,7 +111,6 @@ public class GlobalUserPreferences{
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
spectatorMode=prefs.getBoolean("spectatorMode", false);
autoHideFab=prefs.getBoolean("autoHideFab", true);
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
allowRemoteLoading=prefs.getBoolean("allowRemoteLoading", true);
autoRevealEqualSpoilers=AutoRevealMode.valueOf(prefs.getString("autoRevealEqualSpoilers", AutoRevealMode.THREADS.name()));
forwardReportDefault=prefs.getBoolean("forwardReportDefault", true);
@@ -133,22 +120,10 @@ public class GlobalUserPreferences{
displayPronounsInThreads=prefs.getBoolean("displayPronounsInThreads", true);
displayPronounsInUserListings=prefs.getBoolean("displayPronounsInUserListings", true);
overlayMedia=prefs.getBoolean("overlayMedia", false);
// MOSHIDON
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
showDividers =prefs.getBoolean("showDividers", false);
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
defaultToUnlistedReplies=prefs.getBoolean("defaultToUnlistedReplies", false);
doubleTapToSwipe =prefs.getBoolean("doubleTapToSwipe", true);
replyLineAboveHeader=prefs.getBoolean("replyLineAboveHeader", true);
confirmBeforeReblog=prefs.getBoolean("confirmBeforeReblog", false);
hapticFeedback=prefs.getBoolean("hapticFeedback", true);
swapBookmarkWithBoostAction=prefs.getBoolean("swapBookmarkWithBoostAction", false);
loadRemoteAccountFollowers=prefs.getBoolean("loadRemoteAccountFollowers", true);
mentionRebloggerAutomatically=prefs.getBoolean("mentionRebloggerAutomatically", false);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
showSuicideHelp=prefs.getBoolean("showSuicideHelp", true);
underlinedLinks=prefs.getBoolean("underlinedLinks", true);
color=ColorPreference.valueOf(prefs.getString("color", MATERIAL3.name()));
likeIcon=prefs.getBoolean("likeIcon", false);
if (prefs.contains("prefixRepliesWithRe")) {
prefixReplies = prefs.getBoolean("prefixRepliesWithRe", false)
@@ -159,18 +134,11 @@ public class GlobalUserPreferences{
.apply();
}
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()));
}
} catch (IllegalArgumentException|ClassCastException ignored) {
// invalid color name or color was previously saved as integer
color=ColorPreference.PURPLE;
}
if(prefs.getInt("migrationLevel", 0) < 61) migrateToUpstreamVersion61();
int migrationLevel=prefs.getInt("migrationLevel", BuildConfig.VERSION_CODE);
if(migrationLevel < 61)
migrateToUpstreamVersion61();
if(migrationLevel < BuildConfig.VERSION_CODE)
prefs.edit().putInt("migrationLevel", BuildConfig.VERSION_CODE).apply();
}
public static void save(){
@@ -200,8 +168,6 @@ public class GlobalUserPreferences{
.putBoolean("collapseLongPosts", collapseLongPosts)
.putBoolean("spectatorMode", spectatorMode)
.putBoolean("autoHideFab", autoHideFab)
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
.putString("color", color.name())
.putBoolean("allowRemoteLoading", allowRemoteLoading)
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
.putBoolean("forwardReportDefault", forwardReportDefault)
@@ -211,24 +177,34 @@ public class GlobalUserPreferences{
.putBoolean("displayPronounsInThreads", displayPronounsInThreads)
.putBoolean("displayPronounsInUserListings", displayPronounsInUserListings)
.putBoolean("overlayMedia", overlayMedia)
// MOSHIDON
.putBoolean("defaultToUnlistedReplies", defaultToUnlistedReplies)
.putBoolean("doubleTapToSwipe", doubleTapToSwipe)
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
.putBoolean("replyLineAboveHeader", replyLineAboveHeader)
.putBoolean("confirmBeforeReblog", confirmBeforeReblog)
.putBoolean("swapBookmarkWithBoostAction", swapBookmarkWithBoostAction)
.putBoolean("loadRemoteAccountFollowers", loadRemoteAccountFollowers)
.putBoolean("mentionRebloggerAutomatically", mentionRebloggerAutomatically)
.putBoolean("showDividers", showDividers)
.putBoolean("relocatePublishButton", relocatePublishButton)
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
.putInt("theme", theme.ordinal())
.putBoolean("showSuicideHelp", showSuicideHelp)
.putBoolean("underlinedLinks", underlinedLinks)
.putString("color", color.name())
.putBoolean("likeIcon", likeIcon)
.apply();
}
public enum ThemePreference{
AUTO,
LIGHT,
DARK
}
public enum AutoRevealMode {
NEVER,
THREADS,
DISCUSSIONS
}
public enum PrefixRepliesMode {
NEVER,
ALWAYS,
TO_OTHERS
}
//region preferences migrations
private static void migrateToUpstreamVersion61(){
Log.d(TAG, "Migrating preferences to upstream version 61!!");
@@ -275,53 +251,8 @@ public class GlobalUserPreferences{
localPrefs.save();
}
prefs.edit().putInt("migrationLevel", 61).apply();
}
public enum ColorPreference{
MATERIAL3,
PINK,
PURPLE,
GREEN,
BLUE,
BROWN,
RED,
YELLOW,
NORD,
WHITE;
//endregion
public @StringRes int getName() {
return switch(this){
case MATERIAL3 -> R.string.sk_color_palette_material3;
case PINK -> R.string.sk_color_palette_pink;
case PURPLE -> R.string.sk_color_palette_purple;
case GREEN -> R.string.sk_color_palette_green;
case BLUE -> R.string.sk_color_palette_blue;
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;
case WHITE -> R.string.mo_color_palette_black_and_white;
};
}
}
public enum ThemePreference{
AUTO,
LIGHT,
DARK
}
public enum AutoRevealMode {
NEVER,
THREADS,
DISCUSSIONS
}
public enum PrefixRepliesMode {
NEVER,
ALWAYS,
TO_OTHERS
}
}

View File

@@ -1,20 +1,13 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.fragments.ComposeFragment.CAMERA_PERMISSION_CODE;
import static org.joinmastodon.android.fragments.ComposeFragment.CAMERA_PIC_REQUEST_CODE;
import android.Manifest;
import android.app.Activity;
import android.app.Fragment;
import android.app.assist.AssistContent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
@@ -24,7 +17,6 @@ import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.TakePictureRequestEvent;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
@@ -47,54 +39,12 @@ import me.grishka.appkit.api.ErrorResponse;
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState){
UiUtils.setUserPreferredTheme(this);
AccountSession session=getCurrentSession();
UiUtils.setUserPreferredTheme(this, session);
super.onCreate(savedInstanceState);
if(savedInstanceState==null){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new CustomWelcomeFragment());
}else{
AccountSession session;
Bundle args=new Bundle();
Intent intent=getIntent();
if(intent.hasExtra("fromExternalShare")) {
AccountSessionManager.getInstance()
.setLastActiveAccountID(intent.getStringExtra("account"));
AccountSessionManager.getInstance().maybeUpdateLocalInfo(
AccountSessionManager.getInstance().getLastActiveAccount());
showFragmentForExternalShare(intent.getExtras());
return;
}
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
boolean hasNotification = intent.hasExtra("notification");
if(fromNotification){
String accountID=intent.getStringExtra("accountID");
try{
session=AccountSessionManager.getInstance().getAccount(accountID);
if(!hasNotification) args.putString("tab", "notifications");
}catch(IllegalStateException x){
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
}else{
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
AccountSessionManager.getInstance().maybeUpdateLocalInfo(session);
args.putString("account", session.getID());
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
fragment.setArguments(args);
if(fromNotification && hasNotification){
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
showFragmentForNotification(notification, session.getID());
} else if (intent.getBooleanExtra("compose", false)){
showCompose();
} else if (Intent.ACTION_VIEW.equals(intent.getAction())){
handleURL(intent.getData(), null);
} else {
showFragmentClearingBackStack(fragment);
maybeRequestNotificationsPermission();
}
}
restartHomeFragment();
}
if(GithubSelfUpdater.needSelfUpdating()){
@@ -151,7 +101,7 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
}
public void openSearchQuery(String q, String accountID, int progressText, boolean fromSearch){
new GetSearchResults(q, null, true)
new GetSearchResults(q, null, true, null, 0, 0)
.setCallback(new Callback<>(){
@Override
public void onSuccess(SearchResults result){
@@ -251,24 +201,6 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
}
}
// @Override
// public void onActivityResult(int requestCode, int resultCode, Intent data){
// if(requestCode==CAMERA_PIC_REQUEST_CODE && resultCode== Activity.RESULT_OK){
// E.post(new TakePictureRequestEvent());
// }
// }
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_CODE && (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
E.post(new TakePictureRequestEvent());
} else {
Toast.makeText(this, R.string.permission_required, Toast.LENGTH_SHORT);
}
}
public Fragment getCurrentFragment() {
for (int i = fragmentContainers.size() - 1; i >= 0; i--) {
FrameLayout fl = fragmentContainers.get(i);
@@ -285,4 +217,81 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
Fragment fragment = getCurrentFragment();
if (fragment != null) callFragmentToProvideAssistContent(fragment, assistContent);
}
public AccountSession getCurrentSession(){
AccountSession session;
Bundle args=new Bundle();
Intent intent=getIntent();
if(intent.hasExtra("fromExternalShare")) {
return AccountSessionManager.getInstance()
.getAccount(intent.getStringExtra("account"));
}
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
boolean hasNotification = intent.hasExtra("notification");
if(fromNotification){
String accountID=intent.getStringExtra("accountID");
try{
session=AccountSessionManager.getInstance().getAccount(accountID);
if(!hasNotification) args.putString("tab", "notifications");
}catch(IllegalStateException x){
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
}else{
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
return session;
}
public void restartActivity(){
finish();
startActivity(new Intent(this, MainActivity.class));
}
public void restartHomeFragment(){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new CustomWelcomeFragment());
}else{
AccountSession session;
Bundle args=new Bundle();
Intent intent=getIntent();
if(intent.hasExtra("fromExternalShare")) {
AccountSessionManager.getInstance()
.setLastActiveAccountID(intent.getStringExtra("account"));
AccountSessionManager.getInstance().maybeUpdateLocalInfo(
AccountSessionManager.getInstance().getLastActiveAccount());
showFragmentForExternalShare(intent.getExtras());
return;
}
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
boolean hasNotification = intent.hasExtra("notification");
if(fromNotification){
String accountID=intent.getStringExtra("accountID");
try{
session=AccountSessionManager.getInstance().getAccount(accountID);
if(!hasNotification) args.putString("tab", "notifications");
}catch(IllegalStateException x){
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
}else{
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
AccountSessionManager.getInstance().maybeUpdateLocalInfo(session);
args.putString("account", session.getID());
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
fragment.setArguments(args);
if(fromNotification && hasNotification){
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
showFragmentForNotification(notification, session.getID());
} else if (intent.getBooleanExtra("compose", false)){
showCompose();
} else if (Intent.ACTION_VIEW.equals(intent.getAction())){
handleURL(intent.getData(), null);
} else {
showFragmentClearingBackStack(fragment);
maybeRequestNotificationsPermission();
}
}
}
}

View File

@@ -1,8 +1,6 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.GlobalUserPreferences.PrefixRepliesMode.ALWAYS;
import static org.joinmastodon.android.GlobalUserPreferences.PrefixRepliesMode.TO_OTHERS;
import static org.joinmastodon.android.GlobalUserPreferences.getPrefs;
import static org.joinmastodon.android.GlobalUserPreferences.PrefixRepliesMode.*;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -14,15 +12,12 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.opengl.Visibility;
import android.os.Build;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.Log;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.api.requests.notifications.GetNotificationByID;
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
@@ -37,8 +32,6 @@ import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.PushNotification;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
@@ -143,10 +136,9 @@ public class PushNotificationReceiver extends BroadcastReceiver{
switch (NotificationAction.values()[intent.getIntExtra("notificationAction", 0)]) {
case FAVORITE -> new SetStatusFavorited(statusID, true).exec(accountID);
case BOOKMARK -> new SetStatusBookmarked(statusID, true).exec(accountID);
case BOOST -> new SetStatusReblogged(notification.status.id, true, preferences.postingDefaultVisibility).exec(accountID);
case UNBOOST -> new SetStatusReblogged(notification.status.id, false, preferences.postingDefaultVisibility).exec(accountID);
case REBLOG -> new SetStatusReblogged(notification.status.id, true, preferences.postingDefaultVisibility).exec(accountID);
case UNDO_REBLOG -> new SetStatusReblogged(notification.status.id, false, preferences.postingDefaultVisibility).exec(accountID);
case REPLY -> handleReplyAction(context, accountID, intent, notification, notificationId, preferences);
case FOLLOW_BACK -> new SetAccountFollowed(notification.account.id, true, true, false).exec(accountID);
default -> Log.w(TAG, "onReceive: Failed to get NotificationAction");
}
}
@@ -182,6 +174,8 @@ public class PushNotificationReceiver extends BroadcastReceiver{
List<NotificationChannel> channels=Arrays.stream(PushNotification.Type.values())
.map(type->{
NotificationChannel channel=new NotificationChannel(accountID+"_"+type, context.getString(type.localizedName), NotificationManager.IMPORTANCE_DEFAULT);
channel.setLightColor(context.getColor(R.color.primary_700));
channel.enableLights(true);
channel.setGroup(accountID);
return channel;
})
@@ -211,11 +205,12 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setShowWhen(true)
.setCategory(Notification.CATEGORY_SOCIAL)
.setAutoCancel(true)
.setColor(context.getColor(R.color.shortcut_icon_background));
.setLights(UiUtils.getThemeColor(context, android.R.attr.colorAccent), 500, 1000)
.setColor(UiUtils.getThemeColor(context, android.R.attr.colorAccent));
if (!GlobalUserPreferences.uniformNotificationIcon) {
builder.setSmallIcon(switch (pn.notificationType) {
case FAVORITE -> R.drawable.ic_fluent_star_24_filled;
case FAVORITE -> GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_24_filled : R.drawable.ic_fluent_star_24_filled;
case REBLOG -> R.drawable.ic_fluent_arrow_repeat_all_24_filled;
case FOLLOW -> R.drawable.ic_fluent_person_add_24_filled;
case MENTION -> R.drawable.ic_fluent_mention_24_filled;
@@ -257,23 +252,14 @@ public class PushNotificationReceiver extends BroadcastReceiver{
builder.addAction(buildReplyAction(context, id, accountID, notification));
}
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_favorite), NotificationAction.FAVORITE));
if(GlobalUserPreferences.swapBookmarkWithBoostAction){
if(notification.status.visibility != StatusPrivacy.DIRECT) {
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_reblog), NotificationAction.BOOST));
}else{
// This is just so there is a bookmark action if you cannot reblog the toot
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.add_bookmark), NotificationAction.BOOKMARK));
}
} else {
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.add_bookmark), NotificationAction.BOOKMARK));
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.add_bookmark), NotificationAction.BOOKMARK));
if(notification.status.visibility != StatusPrivacy.DIRECT) {
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_reblog), NotificationAction.REBLOG));
}
}
case UPDATE -> {
if(notification.status.reblogged)
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.sk_undo_reblog), NotificationAction.UNBOOST));
}
case FOLLOW -> {
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.follow_back), NotificationAction.FOLLOW_BACK));
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.sk_undo_reblog), NotificationAction.UNDO_REBLOG));
}
}
}
@@ -336,11 +322,11 @@ public class PushNotificationReceiver extends BroadcastReceiver{
CreateStatus.Request req=new CreateStatus.Request();
req.status = initialText + input.toString();
req.language = preferences.postingDefaultLanguage;
req.visibility = preferences.postingDefaultVisibility;
req.language = notification.status.language;
req.visibility = notification.status.visibility;
req.inReplyToId = notification.status.id;
if (!notification.status.spoilerText.isEmpty() &&
if (notification.status.hasSpoiler() &&
(GlobalUserPreferences.prefixReplies == ALWAYS
|| (GlobalUserPreferences.prefixReplies == TO_OTHERS && !ownID.equals(notification.status.account.id)))
&& !notification.status.spoilerText.startsWith("re: ")) {

View File

@@ -27,9 +27,9 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{
public void onNewEndpoint(@NotNull Context context, @NotNull String endpoint, @NotNull String instance) {
// Called when a new endpoint be used for sending push messages
Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint + " for "+ instance);
AccountSession account = AccountSessionManager.getInstance().getLastActiveAccount();
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account != null)
account.getPushSubscriptionManager().registerAccountForPush(null);
account.getPushSubscriptionManager().registerAccountForPush(null, endpoint);
}
@Override
@@ -37,7 +37,7 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{
// called when the registration is not possible, eg. no network
Log.d(TAG, "onRegistrationFailed: " + instance);
//re-register for gcm
AccountSession account = AccountSessionManager.getInstance().getLastActiveAccount();
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account != null)
account.getPushSubscriptionManager().registerAccountForPush(null);
}
@@ -47,7 +47,7 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{
// called when this application is unregistered from receiving push messages
Log.d(TAG, "onUnregistered: " + instance);
//re-register for gcm
AccountSession account = AccountSessionManager.getInstance().getLastActiveAccount();
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account != null)
account.getPushSubscriptionManager().registerAccountForPush(null);
}
@@ -55,7 +55,10 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{
@Override
public void onMessage(@NotNull Context context, @NotNull byte[] message, @NotNull String instance) {
// Called when a new message is received. The message contains the full POST body of the push message
AccountSession account = AccountSessionManager.getInstance().getAccount(instance);
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account == null)
return;
//this is stupid
// Mastodon stores the info to decrypt the message in the HTTP headers, which are not accessible in UnifiedPush,

View File

@@ -26,6 +26,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import me.grishka.appkit.api.Callback;
@@ -69,12 +70,11 @@ public class CacheController{
Status status=MastodonAPIController.gson.fromJson(cursor.getString(0), Status.class);
status.postprocess();
int flags=cursor.getInt(1);
status.hasGapAfter=((flags & POST_FLAG_GAP_AFTER)!=0);
status.hasGapAfter=((flags & POST_FLAG_GAP_AFTER)!=0) ? status.id : null;
newMaxID=status.id;
result.add(status);
}while(cursor.moveToNext());
String _newMaxID=newMaxID;
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME);
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
return;
}
@@ -86,9 +86,7 @@ public class CacheController{
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Status> result){
ArrayList<Status> filtered=new ArrayList<>(result);
AccountSessionManager.get(accountID).filterStatuses(filtered, FilterContext.HOME);
callback.onSuccess(new CacheablePaginatedResponse<>(filtered, result.isEmpty() ? null : result.get(result.size()-1).id, false));
callback.onSuccess(new CacheablePaginatedResponse<>(result, result.isEmpty() ? null : result.get(result.size()-1).id, false));
putHomeTimeline(result, maxID==null);
}
@@ -116,12 +114,14 @@ public class CacheController{
values.put("id", s.id);
values.put("json", MastodonAPIController.gson.toJson(s));
int flags=0;
if(s.hasGapAfter)
if(Objects.equals(s.hasGapAfter, s.id))
flags|=POST_FLAG_GAP_AFTER;
values.put("flags", flags);
values.put("time", s.createdAt.getEpochSecond());
db.insertWithOnConflict("home_timeline", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
if(!clear)
db.delete("home_timeline", "`id` NOT IN (SELECT `id` FROM `home_timeline` ORDER BY `time` DESC LIMIT ?)", new String[]{"1000"});
});
}
@@ -273,6 +273,28 @@ public class CacheController{
public void deleteStatus(String id){
runOnDbThread((db)->{
String gapId=null;
int gapFlags=0;
// select to-be-removed and newer row
try(Cursor cursor=db.query("home_timeline", new String[]{"id", "flags"}, "`time`>=(SELECT `time` FROM `home_timeline` WHERE `id`=?)", new String[]{id}, null, null, "`time` ASC", "2")){
boolean hadGapAfter=false;
// always either one or two iterations (only one if there's no newer post)
while(cursor.moveToNext()){
String currentId=cursor.getString(0);
int currentFlags=cursor.getInt(1);
if(currentId.equals(id)){
hadGapAfter=((currentFlags & POST_FLAG_GAP_AFTER)!=0);
}else if(hadGapAfter){
gapFlags=currentFlags|POST_FLAG_GAP_AFTER;
gapId=currentId;
}
}
}
if(gapId!=null){
ContentValues values=new ContentValues();
values.put("flags", gapFlags);
db.update("home_timeline", values, "`id`=?", new String[]{gapId});
}
db.delete("home_timeline", "`id`=?", new String[]{id});
});
}

View File

@@ -53,9 +53,7 @@ public class MastodonAPIController{
.registerTypeAdapter(Status.class, new Status.StatusDeserializer())
.create();
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
private static OkHttpClient httpClient=new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.MINUTES)
.build();
private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
private AccountSession session;
private static List<String> badDomains = new ArrayList<>();
@@ -89,13 +87,13 @@ public class MastodonAPIController{
final boolean isBad = host == null || badDomains.stream().anyMatch(h -> h.equalsIgnoreCase(host) || host.toLowerCase().endsWith("." + h));
thread.postRunnable(()->{
try{
// if (isBad) throw new IllegalArgumentException();
if (isBad) throw new IllegalArgumentException();
if(req.canceled)
return;
Request.Builder builder=new Request.Builder()
.url(req.getURL().toString())
.method(req.getMethod(), req.getRequestBody())
.header("User-Agent", "MoshidonAndroid/"+BuildConfig.VERSION_NAME);
.header("User-Agent", "MegalodonAndroid/"+BuildConfig.VERSION_NAME);
String token=null;
if(session!=null)
@@ -113,13 +111,13 @@ public class MastodonAPIController{
}
Request hreq=builder.build();
Call call=httpClient.newCall(hreq);
OkHttpClient client=req.timeout>0
? httpClient.newBuilder().readTimeout(req.timeout, TimeUnit.MILLISECONDS).build()
: httpClient;
Call call=client.newCall(hreq);
synchronized(req){
req.okhttpCall=call;
}
if(req.timeout>0){
call.timeout().timeout(req.timeout, TimeUnit.MILLISECONDS);
}
if(BuildConfig.DEBUG)
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);

View File

@@ -153,8 +153,9 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
headers.put(key, value);
}
protected void setTimeout(long timeout){
public MastodonAPIRequest<T> setTimeout(long timeout){
this.timeout=timeout;
return this;
}
protected String getPathPrefix(){

View File

@@ -125,17 +125,16 @@ public class PushSubscriptionManager{
// this function is used for registering push notifications using FCM
// to avoid NonFreeNet in F-Droid, this registration is disabled in it
// see https://github.com/LucasGGamerM/moshidon/issues/206 for more context
if(BuildConfig.BUILD_TYPE.equals("fdroidRelease"))
if(BuildConfig.BUILD_TYPE.equals("fdroidRelease") || TextUtils.isEmpty(deviceToken)){
Log.d(TAG, "Skipping registering for FCM push notifications");
return;
}
if(TextUtils.isEmpty(deviceToken))
throw new IllegalStateException("No device push token available");
String endpoint = "https://app.joinmastodon.org/relay-to/fcm/"+deviceToken+"/"+accountID;
String endpoint = "https://app.joinmastodon.org/relay-to/fcm/"+deviceToken+"/";
registerAccountForPush(subscription, endpoint);
}
public void registerAccountForPush(PushSubscription subscription, String endpoint){
MastodonAPIController.runInBackground(()->{
Log.d(TAG, "registerAccountForPush: started for "+accountID);
String encodedPublicKey, encodedAuthKey, pushAccountID;
@@ -164,7 +163,13 @@ public class PushSubscriptionManager{
Log.e(TAG, "registerAccountForPush: error generating encryption key", e);
return;
}
new RegisterForPushNotifications(endpoint,
//work-around for adding the randomAccountId
String newEndpoint = endpoint;
if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/"))
newEndpoint += pushAccountID;
new RegisterForPushNotifications(newEndpoint,
encodedPublicKey,
encodedAuthKey,
subscription==null ? PushSubscription.Alerts.ofAll() : subscription.alerts,

View File

@@ -7,7 +7,10 @@ import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.events.ReblogDeletedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusDeletedEvent;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
@@ -48,7 +51,7 @@ public class StatusInteractionController{
runningFavoriteRequests.remove(status.id);
result.favouritesCount = Math.max(0, status.favouritesCount + (favorited ? 1 : -1));
cb.accept(result);
if (updateCounters) E.post(new StatusCountersUpdatedEvent(result));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(result));
}
@Override
@@ -57,13 +60,13 @@ public class StatusInteractionController{
error.showToast(MastodonApp.context);
status.favourited=!favorited;
cb.accept(status);
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
}
})
.exec(accountID);
runningFavoriteRequests.put(status.id, req);
status.favourited=favorited;
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
}
public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer<Status> cb){
@@ -78,11 +81,15 @@ public class StatusInteractionController{
.setCallback(new Callback<>(){
@Override
public void onSuccess(Status reblog){
Status result = reblog.getContentStatus();
Status result=reblog.getContentStatus();
runningReblogRequests.remove(status.id);
result.reblogsCount = Math.max(0, status.reblogsCount + (reblogged ? 1 : -1));
cb.accept(result);
if (updateCounters) E.post(new StatusCountersUpdatedEvent(result));
if(updateCounters){
E.post(new StatusCountersUpdatedEvent(result));
if(reblogged) E.post(new StatusCreatedEvent(reblog, accountID));
else E.post(new ReblogDeletedEvent(status.id, accountID));
}
}
@Override
@@ -91,13 +98,13 @@ public class StatusInteractionController{
error.showToast(MastodonApp.context);
status.reblogged=!reblogged;
cb.accept(status);
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
}
})
.exec(accountID);
runningReblogRequests.put(status.id, req);
status.reblogged=reblogged;
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
}
public void setBookmarked(Status status, boolean bookmarked){
@@ -118,7 +125,7 @@ public class StatusInteractionController{
public void onSuccess(Status result){
runningBookmarkRequests.remove(status.id);
cb.accept(result);
if (updateCounters) E.post(new StatusCountersUpdatedEvent(result));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(result));
}
@Override
@@ -127,12 +134,12 @@ public class StatusInteractionController{
error.showToast(MastodonApp.context);
status.bookmarked=!bookmarked;
cb.accept(status);
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
}
})
.exec(accountID);
runningBookmarkRequests.put(status.id, req);
status.bookmarked=bookmarked;
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
}
}

View File

@@ -0,0 +1,16 @@
package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.model.Account;
public class GetAccountBlocks extends HeaderPaginationRequest<Account>{
public GetAccountBlocks(String maxID, int limit){
super(HttpMethod.GET, "/blocks", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
}
}

View File

@@ -0,0 +1,16 @@
package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.model.Account;
public class GetAccountMutes extends HeaderPaginationRequest<Account>{
public GetAccountMutes(String maxID, int limit){
super(HttpMethod.GET, "/mutes/", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
}
}

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

@@ -6,18 +6,19 @@ import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.StatusPrivacy;
public class UpdateAccountCredentialsPreferences extends MastodonAPIRequest<Account>{
public UpdateAccountCredentialsPreferences(Preferences preferences, Boolean locked, Boolean discoverable){
public UpdateAccountCredentialsPreferences(Preferences preferences, Boolean locked, Boolean discoverable, Boolean indexable){
super(HttpMethod.PATCH, "/accounts/update_credentials", Account.class);
setRequestBody(new Request(locked, discoverable, new RequestSource(preferences.postingDefaultVisibility, preferences.postingDefaultLanguage)));
setRequestBody(new Request(locked, discoverable, indexable, new RequestSource(preferences.postingDefaultVisibility, preferences.postingDefaultLanguage)));
}
private static class Request{
public Boolean locked, discoverable;
public Boolean locked, discoverable, indexable;
public RequestSource source;
public Request(Boolean locked, Boolean discoverable, RequestSource source){
public Request(Boolean locked, Boolean discoverable, Boolean indexable, RequestSource source){
this.locked=locked;
this.discoverable=discoverable;
this.indexable=indexable;
this.source=source;
}
}

View File

@@ -6,6 +6,9 @@ import org.joinmastodon.android.model.FilterContext;
import java.util.EnumSet;
import java.util.List;
import androidx.annotation.Keep;
@Keep
class FilterRequest{
public String title;
public EnumSet<FilterContext> context;

View File

@@ -1,16 +0,0 @@
package org.joinmastodon.android.api.requests.instance;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.DomainBlock;
import org.joinmastodon.android.model.ExtendedDescription;
import java.util.List;
public class GetDomainBlocks extends MastodonAPIRequest<List<DomainBlock>>{
public GetDomainBlocks(){
super(HttpMethod.GET, "/instance/domain_blocks", new TypeToken<>(){});
}
}

View File

@@ -1,12 +0,0 @@
package org.joinmastodon.android.api.requests.instance;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.ExtendedDescription;
import org.joinmastodon.android.model.Instance;
public class GetExtendedDescription extends MastodonAPIRequest<ExtendedDescription>{
public GetExtendedDescription(){
super(HttpMethod.GET, "/instance/extended_description", ExtendedDescription.class);
}
}

View File

@@ -1,15 +0,0 @@
package org.joinmastodon.android.api.requests.instance;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.WeeklyActivity;
import java.util.List;
public class GetWeeklyActivity extends MastodonAPIRequest<List<WeeklyActivity>>{
public GetWeeklyActivity(){
super(HttpMethod.GET, "/instance/activity", new TypeToken<>(){});
}
}

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

@@ -13,7 +13,7 @@ import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> {
private String maxID;
private final String maxID;
public PleromaMarkNotificationsRead(String maxID) {
super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
this.maxID = maxID;

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

@@ -4,13 +4,19 @@ import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.SearchResults;
public class GetSearchResults extends MastodonAPIRequest<SearchResults>{
public GetSearchResults(String query, Type type, boolean resolve){
public GetSearchResults(String query, Type type, boolean resolve, String maxID, int offset, int count){
super(HttpMethod.GET, "/search", SearchResults.class);
addQueryParameter("q", query);
if(type!=null)
addQueryParameter("type", type.name().toLowerCase());
if(resolve)
addQueryParameter("resolve", "true");
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(offset>0)
addQueryParameter("offset", String.valueOf(offset));
if(count>0)
addQueryParameter("limit", String.valueOf(count));
}
public GetSearchResults limit(int limit){

View File

@@ -11,13 +11,11 @@ import java.util.ArrayList;
import java.util.List;
public class CreateStatus extends MastodonAPIRequest<Status>{
public static final Instant DRAFTS_AFTER_INSTANT = Instant.ofEpochMilli(253370764799999L) /* end of 9998 */;
private static final float draftFactor = 31536000000f /* one year */ / 253370764799999f /* end of 9998 */;
public static long EPOCH_OF_THE_YEAR_FIVE_THOUSAND=95617584000000L;
public static final Instant DRAFTS_AFTER_INSTANT=Instant.ofEpochMilli(EPOCH_OF_THE_YEAR_FIVE_THOUSAND - 1) /* end of 4999 */;
public static Instant getDraftInstant() {
// returns an instant between 9999-01-01 00:00:00 and 9999-12-31 23:59:59
// yes, this is a weird implementation for something that hardly matters
return DRAFTS_AFTER_INSTANT.plusMillis(1 + (long) (System.currentTimeMillis() * draftFactor));
return DRAFTS_AFTER_INSTANT.plusMillis(System.currentTimeMillis());
}
public CreateStatus(CreateStatus.Request req, String uuid){
@@ -36,6 +34,7 @@ public class CreateStatus extends MastodonAPIRequest<Status>{
public static class Request{
public String status;
public List<MediaAttribute> mediaAttributes;
public List<String> mediaIds;
public Poll poll;
public String inReplyToId;
@@ -55,5 +54,17 @@ public class CreateStatus extends MastodonAPIRequest<Status>{
public boolean multiple;
public boolean hideTotals;
}
public static class MediaAttribute{
public String id;
public String description;
public String focus;
public MediaAttribute(String id, String description, String focus){
this.id=id;
this.description=description;
this.focus=focus;
}
}
}
}

View File

@@ -1,11 +1,13 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.TranslatedStatus;
import org.joinmastodon.android.model.Translation;
public class TranslateStatus extends MastodonAPIRequest<TranslatedStatus> {
public TranslateStatus(String id) {
super(HttpMethod.POST, "/statuses/"+id+"/translate", TranslatedStatus.class);
setRequestBody(new Object());
}
import java.util.Map;
public class TranslateStatus extends MastodonAPIRequest<Translation>{
public TranslateStatus(String id, String lang){
super(HttpMethod.POST, "/statuses/"+id+"/translate", Translation.class);
setRequestBody(Map.of("lang", lang));
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.tags;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Hashtag;
public class GetTag extends MastodonAPIRequest<Hashtag>{
public GetTag(String tag){
super(HttpMethod.GET, "/tags/"+tag, Hashtag.class);
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.tags;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Hashtag;
public class SetTagFollowed extends MastodonAPIRequest<Hashtag>{
public SetTagFollowed(String tag, boolean followed){
super(HttpMethod.POST, "/tags/"+tag+(followed ? "/follow" : "/unfollow"), Hashtag.class);
setRequestBody(new Object());
}
}

View File

@@ -6,17 +6,18 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.SharedPreferences;
import androidx.annotation.StringRes;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.TimelineDefinition;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AccountLocalPreferences{
private final SharedPreferences prefs;
@@ -40,16 +41,14 @@ public class AccountLocalPreferences{
public String publishButtonText;
public String timelineReplyVisibility; // akkoma-only
public boolean keepOnlyLatestNotification;
public boolean emojiReactionsEnabled;
public boolean showEmojiReactionsInLists;
public ShowEmojiReactions showEmojiReactions;
public ColorPreference color;
public ArrayList<Emoji> recentCustomEmoji;
private final static Type recentLanguagesType = new TypeToken<ArrayList<String>>() {}.getType();
private final static Type timelinesType = new TypeToken<ArrayList<TimelineDefinition>>() {}.getType();
// MOSHIDON
private final static Type recentEmojisType = new TypeToken<Map<String, Integer>>() {}.getType();
public Map<String, Integer> recentEmojis;
private final static Type recentLanguagesType=new TypeToken<ArrayList<String>>() {}.getType();
private final static Type timelinesType=new TypeToken<ArrayList<TimelineDefinition>>() {}.getType();
private final static Type recentCustomEmojiType=new TypeToken<ArrayList<Emoji>>() {}.getType();
public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
this.prefs=prefs;
@@ -73,10 +72,9 @@ public class AccountLocalPreferences{
timelineReplyVisibility=prefs.getString("timelineReplyVisibility", null);
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
showEmojiReactionsInLists=prefs.getBoolean("showEmojiReactionsInLists", false);
// MOSHIDON
recentEmojis=fromJson(prefs.getString("recentEmojis", "{}"), recentEmojisType, new HashMap<>());
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
color=prefs.contains("color") ? ColorPreference.valueOf(prefs.getString("color", null)) : null;
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
}
public long getNotificationsPauseEndTime(){
@@ -87,6 +85,10 @@ public class AccountLocalPreferences{
prefs.edit().putLong("notificationsPauseTime", time).apply();
}
public ColorPreference getCurrentColor(){
return color!=null ? color : GlobalUserPreferences.color!=null ? GlobalUserPreferences.color : ColorPreference.MATERIAL3;
}
public void save(){
prefs.edit()
.putBoolean("interactionCounts", showInteractionCounts)
@@ -109,10 +111,39 @@ public class AccountLocalPreferences{
.putString("timelineReplyVisibility", timelineReplyVisibility)
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
.putBoolean("showEmojiReactionsInLists", showEmojiReactionsInLists)
// MOSHIDON
.putString("recentEmojis", gson.toJson(recentEmojis))
.putString("showEmojiReactions", showEmojiReactions.name())
.putString("color", color!=null ? color.name() : null)
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
.apply();
}
public enum ColorPreference{
MATERIAL3,
PINK,
PURPLE,
GREEN,
BLUE,
BROWN,
RED,
YELLOW;
public @StringRes int getName() {
return switch(this){
case MATERIAL3 -> R.string.sk_color_palette_material3;
case PINK -> R.string.sk_color_palette_pink;
case PURPLE -> R.string.sk_color_palette_purple;
case GREEN -> R.string.sk_color_palette_green;
case BLUE -> R.string.sk_color_palette_blue;
case BROWN -> R.string.sk_color_palette_brown;
case RED -> R.string.sk_color_palette_red;
case YELLOW -> R.string.sk_color_palette_yellow;
};
}
}
public enum ShowEmojiReactions{
HIDE_EMPTY,
ONLY_OPENED,
ALWAYS
}
}

View File

@@ -40,7 +40,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -146,6 +145,9 @@ public class AccountSession{
@Override
public void onError(ErrorResponse error){
Log.w(TAG, "Failed to load preferences for account "+getID()+": "+error);
if (preferences==null)
preferences=new Preferences();
preferencesFromAccountSource(self);
}
})
.exec(getID());
@@ -216,7 +218,7 @@ public class AccountSession{
public void savePreferencesIfPending(){
if(preferencesNeedSaving){
new UpdateAccountCredentialsPreferences(preferences, null, null)
new UpdateAccountCredentialsPreferences(preferences, self.locked, self.discoverable, self.source.indexable)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Account result){
@@ -252,52 +254,75 @@ public class AccountSession{
filterStatusContainingObjects(objects, extractor, context, null);
}
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
Predicate<Status> statusIsOnOwnProfile = (s) -> self != null && profile != null && s.account != null
private boolean statusIsOnOwnProfile(Status s, Account profile){
return self != null && profile != null && s.account != null
&& Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id);
}
if(getLocalPreferences().serverSideFiltersSupported){
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
objects.removeIf(o->{
Status s=extractor.apply(o);
if(s==null)
return false;
if(s.filtered==null)
return false;
// don't hide own posts in own profile
if (statusIsOnOwnProfile.test(s))
return false;
for(FilterResult filter:s.filtered){
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
return true;
}
return false;
});
return;
}
if(wordFilters==null)
return;
for(T obj:objects){
private boolean isFilteredType(Status s){
return (!localPreferences.showReplies && s.inReplyToId != null)
|| (!localPreferences.showBoosts && s.reblog != null);
}
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
if(!localPreferences.serverSideFiltersSupported) for(T obj:objects){
Status s=extractor.apply(obj);
if(s!=null && s.filtered!=null){
getLocalPreferences().serverSideFiltersSupported=true;
getLocalPreferences().save();
return;
localPreferences.serverSideFiltersSupported=true;
localPreferences.save();
break;
}
}
objects.removeIf(o->{
Status s=extractor.apply(o);
if(s==null)
return false;
// don't hide own posts in own profile
if (statusIsOnOwnProfile.test(s))
return false;
for(LegacyFilter filter:wordFilters){
List<T> removeUs=new ArrayList<>();
for(int i=0; i<objects.size(); i++){
T o=objects.get(i);
if(filterStatusContainingObject(o, extractor, context, profile)){
Status s=extractor.apply(o);
removeUs.add(o);
if(s!=null && s.hasGapAfter!=null && i>0){
// oops, we're about to remove an item that has a gap after...
// gotta find the previous status that's not also about to be removed
for(int j=i-1; j>=0; j--){
T p=objects.get(j);
Status prev=extractor.apply(objects.get(j));
if(prev!=null && !removeUs.contains(p)){
prev.hasGapAfter=s.hasGapAfter;
break;
}
}
}
}
}
objects.removeAll(removeUs);
}
public <T> boolean filterStatusContainingObject(T object, Function<T, Status> extractor, FilterContext context, Account profile){
Status s=extractor.apply(object);
if(s==null)
return false;
// don't hide own posts in own profile
if(statusIsOnOwnProfile(s, profile))
return false;
if(isFilteredType(s) && (context == FilterContext.HOME || context == FilterContext.PUBLIC))
return true;
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
if(localPreferences.serverSideFiltersSupported){
for(FilterResult filter : s.filtered){
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
return true;
}
}else if(wordFilters!=null){
for(LegacyFilter filter : wordFilters){
if(filter.context.contains(context) && filter.matches(s) && filter.isActive())
return true;
}
return false;
});
}
return false;
}
public void updateAccountInfo(){
AccountSessionManager.getInstance().updateSessionLocalInfo(this);
}
public Optional<Instance> getInstance() {
@@ -310,4 +335,10 @@ public class AccountSession{
.authority(getInstance().map(i -> i.normalizedUri).orElse(domain))
.build();
}
public String getDefaultAvatarUrl() {
return getInstance()
.map(instance->"https://"+domain+(instance.isAkkoma() ? "/images/avi.png" : "/avatars/original/missing.png"))
.orElse("");
}
}

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 = getRedirectURI();
public static final String REDIRECT_URI="megalodon-android-auth://callback";
private static final AccountSessionManager instance=new AccountSessionManager();
@@ -80,17 +80,6 @@ public class AccountSessionManager{
return instance;
}
public static String getRedirectURI() {
StringBuilder builder = new StringBuilder();
builder.append("moshidon-android-");
if (BuildConfig.BUILD_TYPE.equals("debug") || BuildConfig.BUILD_TYPE.equals("nightly")) {
builder.append(BuildConfig.BUILD_TYPE);
builder.append('-');
}
builder.append("auth://callback");
return builder.toString();
}
private AccountSessionManager(){
prefs=MastodonApp.context.getSharedPreferences("account_manager", Context.MODE_PRIVATE);
File file=new File(MastodonApp.context.getFilesDir(), "accounts.json");
@@ -250,7 +239,7 @@ public class AccountSessionManager{
.path("/oauth/authorize")
.appendQueryParameter("response_type", "code")
.appendQueryParameter("client_id", result.clientId)
.appendQueryParameter("redirect_uri", REDIRECT_URI)
.appendQueryParameter("redirect_uri", "megalodon-android-auth://callback")
.appendQueryParameter("scope", SCOPE)
.build();
@@ -314,8 +303,7 @@ public class AccountSessionManager{
}
}
private void updateSessionLocalInfo(AccountSession session){
/*package*/ void updateSessionLocalInfo(AccountSession session){
new GetOwnAccount()
.setCallback(new Callback<>(){
@Override

View File

@@ -0,0 +1,19 @@
package org.joinmastodon.android.events;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.model.EmojiReaction;
import java.util.List;
public class EmojiReactionsUpdatedEvent{
public final String id;
public final List<EmojiReaction> reactions;
public final boolean updateTextPadding;
public RecyclerView.ViewHolder viewHolder;
public EmojiReactionsUpdatedEvent(String id, List<EmojiReaction> reactions, boolean updateTextPadding, RecyclerView.ViewHolder viewHolder){
this.id=id;
this.reactions=reactions;
this.updateTextPadding=updateTextPadding;
this.viewHolder=viewHolder;
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.events;
public class ReblogDeletedEvent{
public final String statusID;
public final String accountID;
public ReblogDeletedEvent(String statusID, String accountID){
this.statusID=statusID;
this.accountID=accountID;
}
}

View File

@@ -1,7 +1,5 @@
package org.joinmastodon.android.events;
import org.joinmastodon.android.model.ScheduledStatus;
public class ScheduledStatusDeletedEvent{
public final String id;
public final String accountID;

View File

@@ -1,27 +1,14 @@
package org.joinmastodon.android.events;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.api.CacheController;
import org.joinmastodon.android.model.EmojiReaction;
import org.joinmastodon.android.model.Status;
import java.util.ArrayList;
import java.util.List;
public class StatusCountersUpdatedEvent{
public String id;
public long favorites, reblogs, replies;
public boolean favorited, reblogged, bookmarked, pinned;
public List<EmojiReaction> reactions;
public Status status;
public RecyclerView.ViewHolder viewHolder;
public StatusCountersUpdatedEvent(Status s){
this(s, null);
}
public StatusCountersUpdatedEvent(Status s, RecyclerView.ViewHolder vh){
id=s.id;
status=s;
favorites=s.favouritesCount;
@@ -31,7 +18,5 @@ public class StatusCountersUpdatedEvent{
reblogged=s.reblogged;
bookmarked=s.bookmarked;
pinned=s.pinned;
reactions=new ArrayList<>(s.reactions);
viewHolder=vh;
}
}

View File

@@ -9,5 +9,6 @@ public class StatusCreatedEvent{
public StatusCreatedEvent(Status status, String accountID){
this.status=status;
this.accountID=accountID;
status.fromStatusCreated=true;
}
}

View File

@@ -1,6 +0,0 @@
package org.joinmastodon.android.events;
public class TakePictureRequestEvent {
public TakePictureRequestEvent(){
}
}

View File

@@ -9,19 +9,16 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.session.AccountSessionManager;
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.FilterContext;
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.Optional;
import java.util.stream.Collectors;
import me.grishka.appkit.api.SimpleCallback;
@@ -55,15 +52,14 @@ public class AccountTimelineFragment extends StatusListFragment{
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetAccountStatuses(user.id, offset>0 ? getMaxID() : null, null, count, filter)
currentRequest=new GetAccountStatuses(user.id, getMaxID(), null, count, filter)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
if(getActivity()==null) return;
AccountSessionManager asm = AccountSessionManager.getInstance();
boolean empty=result.isEmpty();
boolean more=applyMaxID(result);
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
onDataLoaded(result, !empty);
onDataLoaded(result, more);
}
})
.exec(accountID);

View File

@@ -97,7 +97,7 @@ public class AnnouncementsFragment extends BaseStatusListFragment<Announcement>
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Announcement> result){
if (getActivity() == null) return;
if(getActivity()==null) return;
// get unread items first
List<Announcement> data = result.stream().filter(a -> !a.read).collect(toList());

View File

@@ -9,7 +9,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -17,15 +16,12 @@ import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
import org.joinmastodon.android.api.requests.statuses.TranslateStatus;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.model.Account;
@@ -33,9 +29,10 @@ import org.joinmastodon.android.model.DisplayItemsParent;
import org.joinmastodon.android.model.Poll;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.Translation;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
@@ -59,6 +56,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -70,7 +68,6 @@ 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;
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
@@ -91,6 +88,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
protected Rect tmpRect=new Rect();
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
protected boolean currentlyScrolling;
protected String maxID;
public BaseStatusListFragment(){
super(20);
@@ -157,6 +155,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
}
protected String getMaxID(){
if(refreshing) return null;
if(maxID!=null) return maxID;
if(!preloadedData.isEmpty())
return preloadedData.get(preloadedData.size()-1).getID();
else if(!data.isEmpty())
@@ -165,6 +165,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
return null;
}
protected boolean applyMaxID(List<Status> result){
boolean empty=result.isEmpty();
if(!empty) maxID=result.get(result.size()-1).id;
return !empty;
}
protected abstract List<StatusDisplayItem> buildDisplayItems(T s);
protected abstract void addAccountToKnown(T s);
@@ -462,10 +468,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
protected void updatePoll(String itemID, Status status, Poll poll){
status.poll=poll;
int firstOptionIndex=-1, footerIndex=-1;
int spoilerFirstOptionIndex=-1, spoilerFooterIndex=-1;
SpoilerStatusDisplayItem spoilerItem=null;
int i=0;
for(StatusDisplayItem item:displayItems){
if(item.parentID.equals(itemID)){
if(item instanceof PollOptionStatusDisplayItem && firstOptionIndex==-1){
if(item instanceof SpoilerStatusDisplayItem){
spoilerItem=(SpoilerStatusDisplayItem) item;
}else if(item instanceof PollOptionStatusDisplayItem && firstOptionIndex==-1){
firstOptionIndex=i;
}else if(item instanceof PollFooterStatusDisplayItem){
footerIndex=i;
@@ -478,8 +488,16 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
throw new IllegalStateException("Can't find all poll items in displayItems");
List<StatusDisplayItem> pollItems=displayItems.subList(firstOptionIndex, footerIndex+1);
int prevSize=pollItems.size();
if(spoilerItem!=null){
spoilerFirstOptionIndex=spoilerItem.contentItems.indexOf(pollItems.get(0));
spoilerFooterIndex=spoilerItem.contentItems.indexOf(pollItems.get(pollItems.size()-1));
}
pollItems.clear();
StatusDisplayItem.buildPollItems(itemID, this, poll, pollItems, status);
StatusDisplayItem.buildPollItems(itemID, this, poll, pollItems);
if(spoilerItem!=null){
spoilerItem.contentItems.subList(spoilerFirstOptionIndex, spoilerFooterIndex+1).clear();
spoilerItem.contentItems.addAll(spoilerFirstOptionIndex, pollItems);
}
if(prevSize!=pollItems.size()){
adapter.notifyItemRangeRemoved(firstOptionIndex, prevSize);
adapter.notifyItemRangeInserted(firstOptionIndex, pollItems.size());
@@ -551,21 +569,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
public void onVisibilityIconClick(HeaderStatusDisplayItem.Holder holder) {
Status status = holder.getItem().status;
MediaGridStatusDisplayItem.Holder mediaGrid = findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
if (mediaGrid != null) {
if (!status.sensitiveRevealed) mediaGrid.revealSensitive();
if(holder.getItem().hasVisibilityToggle) holder.animateVisibilityToggle(false);
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
if(mediaGrid!=null){
if(!status.sensitiveRevealed) mediaGrid.revealSensitive();
else mediaGrid.hideSensitive();
} else {
// media grid's methods normally change the status' state - we still want to be able
// to do this if the media grid is not bound, tho - so, doing it ourselves here
status.sensitiveRevealed = !status.sensitiveRevealed;
}else{
status.sensitiveRevealed=false;
notifyItemChangedAfter(holder.getItem(), MediaGridStatusDisplayItem.class);
}
holder.rebind();
}
public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) {
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
if(header != null) header.rebind();
HeaderStatusDisplayItem.Holder header=findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
if(header!=null && header.getItem().hasVisibilityToggle) header.animateVisibilityToggle(true);
else notifyItemChangedBefore(holder.getItem(), HeaderStatusDisplayItem.class);
}
protected void toggleSpoiler(Status status, String itemID){
@@ -574,8 +592,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
status.sensitiveRevealed = false;
SpoilerStatusDisplayItem.Holder spoiler=findHolderOfType(itemID, SpoilerStatusDisplayItem.Holder.class);
if(spoiler!=null)
spoiler.rebind();
if(spoiler!=null) spoiler.rebind();
else notifyItemChanged(itemID, SpoilerStatusDisplayItem.class);
SpoilerStatusDisplayItem spoilerItem=Objects.requireNonNull(findItemOfType(itemID, SpoilerStatusDisplayItem.class));
int index=displayItems.indexOf(spoilerItem);
@@ -587,42 +605,32 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
adapter.notifyItemRangeRemoved(index+1, spoilerItem.contentItems.size());
}
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
if(text!=null)
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition()-getMainAdapterOffset());
notifyItemChanged(itemID, TextStatusDisplayItem.class);
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
if(header!=null)
header.rebind();
if(header!=null) header.rebind();
else notifyItemChanged(itemID, HeaderStatusDisplayItem.class);
list.invalidateItemDecorations();
}
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();
Status s=holder.getItem().status;
if(s.textExpandable!=expandable && list!=null) {
s.textExpandable=expandable;
HeaderStatusDisplayItem.Holder header=findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
if(header!=null) header.bindCollapseButton();
}
}
public void onToggleExpanded(Status status, String itemID) {
status.textExpanded = !status.textExpanded;
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
notifyItemChanged(itemID, TextStatusDisplayItem.class);
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
if (text != null) text.rebind();
if (header != null) header.rebind();
if(header!=null) header.animateExpandToggle();
else notifyItemChanged(itemID, HeaderStatusDisplayItem.class);
}
public void updateEmojiReactions(Status status, String itemID){
EmojiReactionsStatusDisplayItem.Holder reactions=findHolderOfType(itemID, EmojiReactionsStatusDisplayItem.Holder.class);
if(reactions != null){
reactions.getItem().status.reactions.clear();
reactions.getItem().status.reactions.addAll(status.reactions);
reactions.rebind();
}
}
public void onGapClick(GapStatusDisplayItem.Holder item){}
public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){}
public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warning){
int startPos = warning.getAbsoluteAdapterPosition();
@@ -678,9 +686,61 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
return null;
}
/**
* Use this as a fallback if findHolderOfType fails to find the ViewHolder.
* It might still be bound but off-screen and therefore not a child of the RecyclerView -
* resulting in the ViewHolder displaying an outdated state once scrolled back into view.
*/
protected <I extends StatusDisplayItem> int notifyItemChanged(String id, Class<I> type){
boolean encounteredParent=false;
for(int i=0; i<displayItems.size(); i++){
StatusDisplayItem item=displayItems.get(i);
boolean idEquals=id.equals(item.parentID);
if(!encounteredParent && idEquals) encounteredParent=true; // reached top of the parent
else if(encounteredParent && !idEquals) break; // passed by bottom of the parent. man muss ja wissen wann schluss is
if(idEquals && type.isInstance(item)){
adapter.notifyItemChanged(i);
return i;
}
}
return -1;
}
protected <I extends StatusDisplayItem> int notifyItemChangedAfter(StatusDisplayItem afterThis, Class<I> type){
int startIndex=displayItems.indexOf(afterThis);
if(startIndex == -1) throw new IllegalStateException("notifyItemChangedAfter didn't find the passed StatusDisplayItem");
String parentID=afterThis.parentID;
for(int i=startIndex; i<displayItems.size(); i++){
StatusDisplayItem item=displayItems.get(i);
if(!parentID.equals(item.parentID)) break; // didn't find anything
if(type.isInstance(item)){
// found it
adapter.notifyItemChanged(i);
return i;
}
}
return -1;
}
protected <I extends StatusDisplayItem> int notifyItemChangedBefore(StatusDisplayItem beforeThis, Class<I> type){
int startIndex=displayItems.indexOf(beforeThis);
if(startIndex == -1) throw new IllegalStateException("notifyItemChangedBefore didn't find the passed StatusDisplayItem");
String parentID=beforeThis.parentID;
for(int i=startIndex; i>=0; i--){
StatusDisplayItem item=displayItems.get(i);
if(!parentID.equals(item.parentID)) break; // didn't find anything
if(type.isInstance(item)){
// found it
adapter.notifyItemChanged(i);
return i;
}
}
return -1;
}
@Nullable
protected <I extends StatusDisplayItem, H extends StatusDisplayItem.Holder<I>> H findHolderOfType(String id, Class<H> type){
for(int i=0;i<list.getChildCount();i++){
for(int i=0; i<list.getChildCount(); i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof StatusDisplayItem.Holder<?> itemHolder && itemHolder.getItemID().equals(id) && type.isInstance(holder))
return type.cast(holder);
@@ -777,6 +837,67 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
assistContent.setWebUri(getWebUri(getSession().getInstanceUri().buildUpon()));
}
public void togglePostTranslation(Status status, String itemID){
switch(status.translationState){
case LOADING -> {
return;
}
case SHOWN -> {
status.translationState=Status.TranslationState.HIDDEN;
}
case HIDDEN -> {
if(status.translation!=null){
status.translationState=Status.TranslationState.SHOWN;
}else{
status.translationState=Status.TranslationState.LOADING;
new TranslateStatus(status.getContentStatus().id, Locale.getDefault().getLanguage())
.setCallback(new Callback<>(){
@Override
public void onSuccess(Translation result){
if(getActivity()==null)
return;
status.translation=result;
status.translationState=Status.TranslationState.SHOWN;
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
if(text!=null){
text.updateTranslation(true);
imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition());
}else{
notifyItemChanged(itemID, TextStatusDisplayItem.class);
}
}
@Override
public void onError(ErrorResponse error){
if(getActivity()==null)
return;
status.translationState=Status.TranslationState.HIDDEN;
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
if(text!=null){
text.updateTranslation(true);
}else{
notifyItemChanged(itemID, TextStatusDisplayItem.class);
}
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.error)
.setMessage(R.string.translation_failed)
.setPositiveButton(R.string.ok, null)
.show();
}
})
.exec(accountID);
}
}
}
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
if(text!=null){
text.updateTranslation(true);
imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition());
}else{
notifyItemChanged(itemID, TextStatusDisplayItem.class);
}
}
public void rebuildAllDisplayItems(){
displayItems.clear();
for(T item:data){
@@ -792,7 +913,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
if(getContext()==null) return;
super.onDataLoaded(d, more);
// more available, but the page isn't even full yet? seems wrong, let's load some more
if(more && d.size() < itemsPerPage){
if(more && data.size() < itemsPerPage){
preloader.onScrolledToLastItem();
}
}
@@ -846,7 +967,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
private Paint dividerPaint=new Paint();
{
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), GlobalUserPreferences.showDividers ? R.attr.colorM3OutlineVariant : R.attr.colorM3Surface));
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OutlineVariant));
dividerPaint.setStyle(Paint.Style.STROKE);
dividerPaint.setStrokeWidth(V.dp(0.5f));
}

View File

@@ -28,7 +28,7 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if (getActivity() == null) return;
if(getActivity()==null) return;
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else

View File

@@ -5,15 +5,12 @@ import static org.joinmastodon.android.GlobalUserPreferences.PrefixRepliesMode.T
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.DRAFTS_AFTER_INSTANT;
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.getDraftInstant;
import android.Manifest;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.ClipData;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Outline;
import android.graphics.PixelFormat;
@@ -56,7 +53,6 @@ import android.widget.TextView;
import android.widget.Toast;
import com.github.bottomSoftwareFoundation.bottom.Bottom;
import com.squareup.otto.Subscribe;
import com.twitter.twittertext.TwitterTextEmojiRegex;
import org.joinmastodon.android.E;
@@ -69,7 +65,6 @@ import org.joinmastodon.android.api.requests.statuses.EditStatus;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.TakePictureRequestEvent;
import org.joinmastodon.android.events.ScheduledStatusCreatedEvent;
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
@@ -95,8 +90,6 @@ import org.joinmastodon.android.ui.text.ComposeAutocompleteSpan;
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
import org.joinmastodon.android.utils.FileProvider;
import org.joinmastodon.android.utils.TransferSpeedTracker;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.viewcontrollers.ComposeAutocompleteViewController;
import org.joinmastodon.android.ui.viewcontrollers.ComposeLanguageAlertViewController;
@@ -109,12 +102,6 @@ import org.joinmastodon.android.utils.MastodonLanguage;
import org.joinmastodon.android.utils.StatusTextEncoder;
import org.parceler.Parcels;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -123,11 +110,11 @@ import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -151,8 +138,6 @@ 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";
public static final int CAMERA_PERMISSION_CODE = 626938;
public static final int CAMERA_PIC_REQUEST_CODE = 6242069;
private static final Pattern MENTION_PATTERN=Pattern.compile("(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)", Pattern.CASE_INSENSITIVE);
@@ -165,7 +150,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
public LinearLayout mainLayout;
private SizeListenerLinearLayout contentView;
private TextView selfName, selfUsername, selfExtraText, extraText, pronouns;
private TextView selfName, selfUsername, selfExtraText, extraText;
private ImageView selfAvatar;
private Account self;
private String instanceDomain;
@@ -176,8 +161,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private int charCount, charLimit, trimmedCharCount;
private Button publishButton, languageButton, scheduleTimeBtn;
private PopupMenu languagePopup, contentTypePopup, visibilityPopup, draftOptionsPopup;
private ImageButton publishButtonRelocated, mediaBtn, pollBtn, emojiBtn, spoilerBtn, draftsBtn, scheduleDraftDismiss, contentTypeBtn;
private PopupMenu contentTypePopup, visibilityPopup, draftOptionsPopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, draftsBtn, scheduleDraftDismiss, contentTypeBtn;
private View sensitiveBtn;
private TextView replyText;
private LinearLayout scheduleDraftView;
@@ -215,11 +200,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
public Instance instance;
public Status editingStatus;
private ScheduledStatus scheduledStatus;
public ScheduledStatus scheduledStatus;
private boolean redraftStatus;
private Uri photoUri;
private ContentType contentType;
private MastodonLanguage.LanguageResolver languageResolver;
@@ -239,7 +222,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
E.register(this);
setRetainInstance(true);
accountID=getArguments().getString("account");
@@ -288,7 +270,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override
public void onDestroy(){
super.onDestroy();
E.unregister(this);
mediaViewController.cancelAllUploads();
}
@@ -312,7 +293,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
creatingView=true;
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), customEmojis, instanceDomain, getAccountID());
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), accountID, customEmojis, instanceDomain);
emojiKeyboard.setListener(new CustomEmojiPopupKeyboard.Listener(){
@Override
public void onEmojiSelected(Emoji emoji){
@@ -334,37 +315,18 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
});
View view=inflater.inflate(R.layout.fragment_compose, container, false);
if(GlobalUserPreferences.relocatePublishButton){
publishButtonRelocated=view.findViewById(R.id.publish);
// publishButton.setText(editingStatus==null || redraftStatus ? R.string.publish : R.string.save);
// publishButton.setEllipsize(TextUtils.TruncateAt.END);
publishButtonRelocated.setOnClickListener(v -> {
if(GlobalUserPreferences.altTextReminders && editingStatus==null)
checkAltTextsAndPublish();
else
publish();
});
publishButtonRelocated.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));
}
mainLayout=view.findViewById(R.id.compose_main_ll);
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);
selfUsername=view.findViewById(R.id.self_username);
selfAvatar=view.findViewById(R.id.self_avatar);
selfExtraText=view.findViewById(R.id.self_extra_text);
HtmlParser.setTextWithCustomEmoji(selfName, self.displayName, self.emojis);
HtmlParser.setTextWithCustomEmoji(selfName, self.getDisplayName(), self.emojis);
selfUsername.setText('@'+self.username+'@'+instanceDomain);
if(self.avatar!=null)
ViewImageLoader.load(selfAvatar, null, new UrlImageLoaderRequest(self.avatar));
@@ -391,27 +353,19 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
sensitiveBtn=view.findViewById(R.id.sensitive_item);
replyText=view.findViewById(R.id.reply_text);
PopupMenu attachPopup = new PopupMenu(getContext(), mediaBtn);
attachPopup.inflate(R.menu.attach);
if(UiUtils.isPhotoPickerAvailable())
attachPopup.getMenu().findItem(R.id.media).setVisible(true);
attachPopup.setOnMenuItemClickListener(i -> {
if (i.getItemId() == R.id.camera){
try {
openCamera();
} catch (IOException e){
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT);
}
} else {
if (UiUtils.isPhotoPickerAvailable()) {
PopupMenu attachPopup = new PopupMenu(getContext(), mediaBtn);
attachPopup.inflate(R.menu.attach);
attachPopup.setOnMenuItemClickListener(i -> {
openFilePicker(i.getItemId() == R.id.media);
}
return true;
});
UiUtils.enablePopupMenuIcons(getContext(), attachPopup);
mediaBtn.setOnClickListener(v->attachPopup.show());
mediaBtn.setOnTouchListener(attachPopup.getDragToOpenListener());
return true;
});
UiUtils.enablePopupMenuIcons(getContext(), attachPopup);
mediaBtn.setOnClickListener(v->attachPopup.show());
mediaBtn.setOnTouchListener(attachPopup.getDragToOpenListener());
} else {
mediaBtn.setOnClickListener(v -> openFilePicker(false));
}
if (isInstancePixelfed()) pollBtn.setVisibility(View.GONE);
pollBtn.setOnClickListener(v->togglePoll());
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
@@ -465,7 +419,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
hasSpoiler=true;
spoilerWrap.setVisibility(View.VISIBLE);
spoilerBtn.setSelected(true);
}else if(editingStatus!=null && !TextUtils.isEmpty(editingStatus.spoilerText)){
}else if(editingStatus!=null && editingStatus.hasSpoiler()){
hasSpoiler=true;
spoilerWrap.setVisibility(View.VISIBLE);
spoilerEdit.setText(getArguments().getString("sourceSpoiler", editingStatus.spoilerText));
@@ -558,19 +512,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_CODE && (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST_CODE);
} else {
Toast.makeText(getContext(), R.string.permission_required, Toast.LENGTH_SHORT);
}
}
@Override
public void onResume(){
super.onResume();
@@ -685,7 +626,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
});
View originalPost=view.findViewById(R.id.original_post);
extraText=view.findViewById(R.id.extra_text);
pronouns=view.findViewById(R.id.pronouns);
originalPost.setVisibility(View.VISIBLE);
originalPost.setOnClickListener(v->{
Bundle args=new Bundle();
@@ -725,7 +665,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
moreBtn.setBackground(null);
TextView name = view.findViewById(R.id.name);
name.setText(HtmlParser.parseCustomEmoji(status.account.displayName, status.account.emojis));
name.setText(HtmlParser.parseCustomEmoji(status.account.getDisplayName(), status.account.emojis));
UiUtils.loadCustomEmojiInTextView(name);
String time = status==null || status.editedAt==null
@@ -737,7 +677,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
view.findViewById(R.id.time).setVisibility(time==null ? View.GONE : View.VISIBLE);
if(time!=null) ((TextView) view.findViewById(R.id.time)).setText(time);
if (status.spoilerText != null && !status.spoilerText.isBlank()) {
if (status.hasSpoiler()) {
TextView replyToSpoiler = view.findViewById(R.id.reply_to_spoiler);
replyToSpoiler.setVisibility(View.VISIBLE);
replyToSpoiler.setText(status.spoilerText);
@@ -759,7 +699,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
}
replyText.setText(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.displayName));
replyText.setText(HtmlParser.parseCustomEmoji(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.getDisplayName()), status.account.emojis));
UiUtils.loadCustomEmojiInTextView(replyText);
int visibilityNameRes = switch (status.visibility) {
case PUBLIC -> R.string.visibility_public;
case UNLISTED -> R.string.sk_visibility_unlisted;
@@ -767,21 +708,15 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
case DIRECT -> R.string.visibility_private;
case LOCAL -> R.string.sk_local_only;
};
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.displayName) + ", " + getString(visibilityNameRes));
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.getDisplayName()) + ", " + getString(visibilityNameRes));
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;
if(!status.account.id.equals(ownID))
mentions.add('@'+status.account.acct);
if(status.rebloggedBy != null && GlobalUserPreferences.mentionRebloggerAutomatically)
mentions.add('@'+status.rebloggedBy.acct);
for(Mention mention:status.mentions){
if(mention.id.equals(ownID))
continue;
@@ -862,6 +797,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
inflater.inflate(editingStatus==null ? R.menu.compose : R.menu.compose_edit, menu);
@@ -871,25 +807,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
actionItem.setActionView(wrap);
actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
if(!GlobalUserPreferences.relocatePublishButton){
publishButton = wrap.findViewById(R.id.publish_btn);
publishButton.setOnClickListener(v -> {
if(GlobalUserPreferences.altTextReminders && editingStatus==null)
checkAltTextsAndPublish();
else
publish();
});
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);
@@ -906,26 +824,39 @@ 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);
languageButton.setOnClickListener(v->showLanguageAlert());
languageButton.setOnLongClickListener(v->{
if(!getLocalPrefs().bottomEncoding){
getLocalPrefs().bottomEncoding=true;
getLocalPrefs().save();
}
return false;
});
publishButton.post(()->publishButton.setMinimumWidth(publishButton.getWidth()));
if(GlobalUserPreferences.relocatePublishButton){
publishButtonRelocated.setOnClickListener(v -> {
if(GlobalUserPreferences.altTextReminders && editingStatus==null)
checkAltTextsAndPublish();
else
publish();
});
} else {
publishButton.setOnClickListener(v -> {
if(GlobalUserPreferences.altTextReminders && editingStatus==null)
checkAltTextsAndPublish();
else
publish();
});
}
publishButton.setOnClickListener(v->{
Consumer<Boolean> draftCheckComplete=(isDraft)->{
if(GlobalUserPreferences.altTextReminders && !isDraft) checkAltTextsAndPublish();
else publish();
};
boolean isAlreadyDraft=scheduledAt!=null && scheduledAt.isAfter(DRAFTS_AFTER_INSTANT);
if(editingStatus!=null && scheduledAt!=null && isAlreadyDraft) {
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_save_draft)
.setMessage(R.string.sk_save_draft_message)
.setPositiveButton(R.string.save, (d, w)->draftCheckComplete.accept(isAlreadyDraft))
.setNegativeButton(R.string.publish, (d, w)->{
updateScheduledAt(null);
draftCheckComplete.accept(false);
})
.show();
}else{
draftCheckComplete.accept(isAlreadyDraft);
}
});
draftsBtn.setOnClickListener(v-> draftOptionsPopup.show());
draftsBtn.setOnTouchListener(draftOptionsPopup.getDragToOpenListener());
updateScheduledAt(scheduledAt != null ? scheduledAt : scheduledStatus != null ? scheduledStatus.scheduledAt : null);
@@ -936,8 +867,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
? languageResolver.fromOrFallback(prefs.postingDefaultLanguage)
: languageResolver.getDefault());
if (isInstancePixelfed()) spoilerBtn.setVisibility(View.GONE);
if (isInstancePixelfed() || (editingStatus != null && scheduledStatus == null)) {
if(isInstancePixelfed()) spoilerBtn.setVisibility(View.GONE);
if(isInstancePixelfed() || (editingStatus!=null && !redraftStatus)) {
// editing an already published post
draftsBtn.setVisibility(View.GONE);
}
@@ -1013,9 +944,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;
}
AccountLocalPreferences prefs=AccountSessionManager.get(accountID).getLocalPreferences();
if (publishText == R.string.publish && !TextUtils.isEmpty(prefs.publishButtonText)) {
publishButton.setText(prefs.publishButtonText);
@@ -1026,10 +954,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
public void updatePublishButtonState(){
uuid=null;
if(GlobalUserPreferences.relocatePublishButton && publishButtonRelocated != null){
publishButtonRelocated.setEnabled((!isInstancePixelfed() || !mediaViewController.isEmpty()) && (trimmedCharCount>0 || !mediaViewController.isEmpty()) && charCount<=charLimit && mediaViewController.getNonDoneAttachmentCount()==0 && (pollViewController.isEmpty() || pollViewController.getNonEmptyOptionsCount()>1));
}
if(publishButton==null)
return;
publishButton.setEnabled((!isInstancePixelfed() || !mediaViewController.isEmpty()) && (trimmedCharCount>0 || !mediaViewController.isEmpty()) && charCount<=charLimit && mediaViewController.getNonDoneAttachmentCount()==0 && (pollViewController.isEmpty() || pollViewController.getNonEmptyOptionsCount()>1));
@@ -1068,7 +992,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override
protected int getNavigationIconDrawableResource(){
return R.drawable.ic_baseline_close_24;
return R.drawable.ic_fluent_dismiss_24_regular;
}
@Override
@@ -1137,31 +1061,23 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
overlayParams.token=mainEditText.getWindowToken();
wm.addView(sendingOverlay, overlayParams);
if(GlobalUserPreferences.relocatePublishButton){
publishButtonRelocated.setEnabled(false);
} else {
publishButton.setEnabled(false);
}
publishButton.setEnabled(false);
V.setVisibilityAnimated(sendProgress, View.VISIBLE);
mediaViewController.saveAltTextsBeforePublishing(this::actuallyPublish, this::handlePublishError);
}
private void actuallyPublish(){
actuallyPublish(false);
}
private void actuallyPublish(boolean force){
String text=mainEditText.getText().toString();
CreateStatus.Request req=new CreateStatus.Request();
if ("bottom".equals(postLang.encoding)) {
text = new StatusTextEncoder(Bottom::encode).encode(text);
req.spoilerText = "bottom-encoded emoji spam";
if("bottom".equals(postLang.encoding)){
text=new StatusTextEncoder(Bottom::encode).encode(text);
req.spoilerText="bottom-encoded emoji spam";
}
if (localOnly &&
if(localOnly &&
AccountSessionManager.get(accountID).getLocalPreferences().glitchInstance &&
!GLITCH_LOCAL_ONLY_PATTERN.matcher(text).matches()) {
text += " " + GLITCH_LOCAL_ONLY_SUFFIX;
!GLITCH_LOCAL_ONLY_PATTERN.matcher(text).matches()){
text+=" "+GLITCH_LOCAL_ONLY_SUFFIX;
}
req.status=text;
req.localOnly=localOnly;
@@ -1171,19 +1087,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.scheduledAt=scheduledAt;
if(!mediaViewController.isEmpty()){
req.mediaIds=mediaViewController.getAttachmentIDs();
}
// ask whether to publish now when editing an existing draft
if (!force && editingStatus != null && scheduledAt != null && scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)) {
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_save_draft)
.setMessage(R.string.sk_save_draft_message)
.setPositiveButton(R.string.save, (d, w) -> actuallyPublish(true))
.setNegativeButton(R.string.publish, (d, w) -> {
updateScheduledAt(null);
actuallyPublish();
})
.show();
return;
if(editingStatus != null){
req.mediaAttributes=mediaViewController.getAttachmentAttributes();
}
}
if(replyTo!=null || (editingStatus != null && editingStatus.inReplyToId!=null)){
req.inReplyToId=editingStatus!=null ? editingStatus.inReplyToId : replyTo.id;
@@ -1379,20 +1285,20 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
private void confirmDiscardDraftAndFinish(){
boolean attachmentsPending = mediaViewController.areAnyAttachmentsNotDone();
if (attachmentsPending) new M3AlertDialogBuilder(getActivity())
boolean attachmentsPending=mediaViewController.areAnyAttachmentsNotDone();
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))
.setPositiveButton(R.string.ok, (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);
.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);
publish();
})
.setNegativeButton(R.string.discard, (d, w) -> Nav.finish(this))
.setNegativeButton(R.string.discard, (d, w)->Nav.finish(this))
.show();
}
@@ -1410,7 +1316,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
boolean usePhotoPicker=photoPicker && UiUtils.isPhotoPickerAvailable();
if(usePhotoPicker){
intent=new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, mediaViewController.getMaxAttachments()-mediaViewController.getMediaAttachmentsCount());
if(mediaViewController.getMaxAttachments()-mediaViewController.getMediaAttachmentsCount()>1)
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, mediaViewController.getMaxAttachments()-mediaViewController.getMediaAttachmentsCount());
}else{
intent=new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
@@ -1446,39 +1353,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
}
}
if(requestCode==CAMERA_PIC_REQUEST_CODE && resultCode==Activity.RESULT_OK){
onAddMediaAttachmentFromEditText(photoUri, null);
}
}
@Subscribe
public void onTakePictureRequest(TakePictureRequestEvent ev) {
if(isVisible()) {
try {
openCamera();
} catch (IOException e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT);
}
}
}
private void openCamera() throws IOException {
if (getContext().checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
File photoFile = File.createTempFile("img", ".jpg");
photoUri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".fileprovider", photoFile);
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
if(getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)){
startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST_CODE);
} else {
Toast.makeText(getContext(), R.string.mo_camera_not_available, Toast.LENGTH_SHORT);
}
} else {
getActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CODE);
}
}
@@ -1555,15 +1429,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
scheduleDraftDismiss.setTooltipText(getString(R.string.sk_compose_no_draft));
}
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_draft));
draftsBtn.setImageDrawable(getContext().getDrawable(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_drafts_24_regular : R.drawable.ic_fluent_drafts_20_filled));
if(GlobalUserPreferences.relocatePublishButton){
publishButtonRelocated.setImageResource(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.drawable.ic_fluent_save_24_selector : R.drawable.ic_fluent_drafts_24_selector);
}else{
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.string.save : R.string.sk_draft);
}
draftsBtn.setImageResource(R.drawable.ic_fluent_drafts_20_filled);
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.string.save : R.string.sk_draft);
} else {
scheduleMenuItem.setVisible(false);
unscheduleMenuItem.setVisible(true);
@@ -1576,28 +1444,19 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
scheduleDraftDismiss.setTooltipText(getString(R.string.sk_compose_no_schedule));
}
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_schedule));
draftsBtn.setImageDrawable(getContext().getDrawable(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_filled : R.drawable.ic_fluent_clock_20_filled));
if(GlobalUserPreferences.relocatePublishButton)
{
publishButtonRelocated.setImageResource(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
? R.drawable.ic_fluent_save_24_selector : R.drawable.ic_fluent_clock_24_selector);
}else{
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.equals(scheduledAt)
? R.string.save : R.string.sk_schedule);
}
draftsBtn.setImageResource(R.drawable.ic_fluent_clock_20_filled);
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.equals(scheduledAt)
? R.string.save : R.string.sk_schedule);
}
} else {
draftsBtn.setImageDrawable(getContext().getDrawable(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_regular : R.drawable.ic_fluent_clock_20_regular));
if(GlobalUserPreferences.relocatePublishButton){
publishButtonRelocated.setImageResource(R.drawable.ic_fluent_send_24_selector);
}
draftsBtn.setImageResource(R.drawable.ic_fluent_clock_20_regular);
resetPublishButtonText();
}
}
private void updateHeaders() {
UiUtils.setExtraTextInfo(getContext(), selfExtraText, null, false, false, localOnly || statusVisibility==StatusPrivacy.LOCAL, null);
if (replyTo != null) UiUtils.setExtraTextInfo(getContext(), extraText, pronouns, true, false, replyTo.localOnly || replyTo.visibility==StatusPrivacy.LOCAL, replyTo.account);
UiUtils.setExtraTextInfo(getContext(), selfExtraText, false, false, localOnly, null);
if (replyTo != null) UiUtils.setExtraTextInfo(getContext(), extraText, true, false, replyTo.localOnly || replyTo.visibility==StatusPrivacy.LOCAL, replyTo.account);
}
private void buildVisibilityPopup(View v){
@@ -1700,10 +1559,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
menu.show();
}
private void loadDefaultStatusVisibility(Bundle savedInstanceState) {
if(replyTo != null) {
statusVisibility = (replyTo.visibility == StatusPrivacy.PUBLIC && GlobalUserPreferences.defaultToUnlistedReplies ? StatusPrivacy.UNLISTED : replyTo.visibility);
}
private void loadDefaultStatusVisibility(Bundle savedInstanceState){
if(replyTo != null) statusVisibility = replyTo.visibility;
AccountSessionManager asm = AccountSessionManager.getInstance();
Preferences prefs=asm.getAccount(accountID).preferences;

View File

@@ -26,12 +26,12 @@ import android.widget.ImageView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.utils.ColorPalette;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.FixedAspectRatioImageView;
import java.util.Collections;
@@ -54,16 +54,17 @@ public class ComposeImageDescriptionFragment extends MastodonToolbarFragment imp
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
attachmentID=getArguments().getString("attachment");
setHasOptionsMenu(true);
}
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
accountID=getArguments().getString("account");
attachmentID=getArguments().getString("attachment");
themeWrapper=new ContextThemeWrapper(activity, R.style.Theme_Mastodon_Dark);
ColorPalette.palettes.get(GlobalUserPreferences.color).apply(themeWrapper, GlobalUserPreferences.ThemePreference.DARK);
ColorPalette.palettes.get(AccountSessionManager.get(accountID).getLocalPreferences().getCurrentColor())
.apply(themeWrapper, GlobalUserPreferences.ThemePreference.DARK);
setTitle(R.string.add_alt_text);
}

View File

@@ -1,97 +0,0 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.net.Uri;
import android.view.Menu;
import android.view.MenuInflater;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.ProvidesAssistContent;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.List;
import java.util.stream.Collectors;
import me.grishka.appkit.api.SimpleCallback;
public class CustomLocalTimelineFragment extends PinnableStatusListFragment implements ProvidesAssistContent.ProvidesWebUri{
// private String name;
private String domain;
private String maxID;
@Override
protected boolean wantsComposeButton() {
return false;
}
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
domain=getArguments().getString("domain");
updateTitle(domain);
setHasOptionsMenu(true);
}
private void updateTitle(String domain) {
this.domain = domain;
setTitle(this.domain);
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
if(!result.isEmpty())
maxID=result.get(result.size()-1).id;
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, FilterContext.PUBLIC)).collect(Collectors.toList());
result.stream().forEach(status -> {
status.account.acct += "@"+domain;
status.mentions.forEach(mention -> mention.id = null);
status.isRemote = true;
});
onDataLoaded(result, !result.isEmpty());
}
})
.execNoAuth(domain);
}
@Override
protected void onShown(){
super.onShown();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
loadData();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.custom_local_timelines, menu);
super.onCreateOptionsMenu(menu, inflater);
UiUtils.enableOptionsMenuIcons(getContext(), menu, R.id.pin);
}
@Override
protected FilterContext getFilterContext() {
return null;
}
@Override
public Uri getWebUri(Uri.Builder base) {
return Uri.parse(domain);
}
@Override
protected TimelineDefinition makeTimelineDefinition() {
return TimelineDefinition.ofCustomLocalTimeline(domain);
}
}

View File

@@ -1,15 +0,0 @@
package org.joinmastodon.android.fragments;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
public interface DomainDisplay {
default String getDomain(){
AccountSession session = AccountSessionManager.getInstance().getLastActiveAccount();
if (session != null)
return session.domain;
else
return "";
}
}

View File

@@ -8,7 +8,6 @@ import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
@@ -19,7 +18,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -41,9 +39,6 @@ import org.joinmastodon.android.api.requests.lists.GetLists;
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.CustomLocalTimeline;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.ListTimeline;
@@ -51,7 +46,6 @@ import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.DividerItemDecoration;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.TextInputFrameLayout;
import java.util.ArrayList;
import java.util.Collections;
@@ -64,7 +58,6 @@ import java.util.function.Consumer;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefinition> implements ScrollableToTop {
@@ -77,7 +70,6 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
private final List<ListTimeline> listTimelines = new ArrayList<>();
private final List<Hashtag> hashtags = new ArrayList<>();
private MenuItem addHashtagItem;
private final List<CustomLocalTimeline> localTimelines = new ArrayList<>();
public EditTimelinesFragment() {
super(10);
@@ -146,10 +138,6 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
optionsMenu.performIdentifierAction(R.id.menu_add_timeline, 0);
return true;
}
if (item.getItemId() == R.id.menu_add_local_timelines) {
addNewLocalTimeline();
return true;
}
TimelineDefinition tl = timelineByMenuItem.get(item);
if (tl != null) {
addTimeline(tl);
@@ -168,26 +156,6 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
updateOptionsMenu();
}
private void addNewLocalTimeline() {
FrameLayout inputWrap = new FrameLayout(getContext());
EditText input = new EditText(getContext());
input.setHint(R.string.sk_example_domain);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(V.dp(16), V.dp(4), V.dp(16), V.dp(16));
input.setLayoutParams(params);
inputWrap.addView(input);
new M3AlertDialogBuilder(getContext()).setTitle(R.string.mo_add_custom_server_local_timeline).setView(inputWrap)
.setPositiveButton(R.string.save, (d, which) -> {
TimelineDefinition tl = TimelineDefinition.ofCustomLocalTimeline(input.getText().toString().trim());
data.add(tl);
saveTimelines();
})
.setNegativeButton(R.string.cancel, (d, which) -> {
})
.show();
}
private void addTimelineToOptions(TimelineDefinition tl, Menu menu) {
if (data.contains(tl)) return;
MenuItem item = addOptionsItem(menu, tl.getTitle(getContext()), tl.getIcon().iconRes);
@@ -201,7 +169,7 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
}
private void updateOptionsMenu() {
if (getActivity() == null) return;
if(getActivity()==null) return;
optionsMenu.clear();
timelineByMenuItem.clear();
@@ -216,9 +184,6 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
SubMenu hashtagsMenu = menu.addSubMenu(R.string.sk_hashtag);
hashtagsMenu.getItem().setIcon(R.drawable.ic_fluent_number_symbol_24_regular);
MenuItem addLocalTimelines = menu.add(0, R.id.menu_add_local_timelines, NONE, R.string.local_timeline);
addLocalTimelines.setIcon(R.drawable.ic_fluent_add_24_regular);
makeBackItem(timelinesMenu);
makeBackItem(listsMenu);
makeBackItem(hashtagsMenu);
@@ -274,16 +239,21 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
private boolean setTagListContent(NachoTextView editText, @Nullable List<String> tags) {
if (tags == null || tags.isEmpty()) return false;
editText.setText(String.join(",", tags));
editText.chipifyAllUnterminatedTokens();
editText.setText(tags);
editText.chipifyAllUnterminatedTokens();
return true;
}
private NachoTextView prepareChipTextView(NachoTextView nacho) {
nacho.addChipTerminator(',', BEHAVIOR_CHIPIFY_ALL);
nacho.addChipTerminator('\n', BEHAVIOR_CHIPIFY_ALL);
nacho.addChipTerminator(' ', BEHAVIOR_CHIPIFY_ALL);
nacho.addChipTerminator(';', BEHAVIOR_CHIPIFY_ALL);
//Ill Be Back
nacho.setChipTerminators(
Map.of(
',', BEHAVIOR_CHIPIFY_ALL,
'\n', BEHAVIOR_CHIPIFY_ALL,
' ', BEHAVIOR_CHIPIFY_ALL,
';', BEHAVIOR_CHIPIFY_ALL
)
);
nacho.enableEditChipOnTouch(true, true);
nacho.setOnFocusChangeListener((v, hasFocus) -> nacho.chipifyAllUnterminatedTokens());
return nacho;
@@ -379,7 +349,7 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
mainHashtag = name;
name = null;
}
if (TextUtils.isEmpty(mainHashtag)) {
if (TextUtils.isEmpty(mainHashtag) && (item != null && item.getType() == TimelineDefinition.TimelineType.HASHTAG)) {
Toast.makeText(ctx, R.string.sk_add_timeline_tag_error_empty, Toast.LENGTH_SHORT).show();
onSave.accept(null);
return;

View File

@@ -27,7 +27,7 @@ public class FavoritedStatusListFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if (getActivity() == null) return;
if(getActivity()==null) return;
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else

View File

@@ -46,7 +46,7 @@ public class FeaturedHashtagsListFragment extends BaseStatusListFragment<Hashtag
@Override
public void onItemClick(String id){
UiUtils.openHashtagTimeline(getActivity(), accountID, id, data.stream().filter(h -> Objects.equals(h.name, id)).findAny().map(h -> h.following).orElse(null));
UiUtils.openHashtagTimeline(getActivity(), accountID, Objects.requireNonNull(findItemOfType(id, HashtagStatusDisplayItem.class)).tag);
}
@Override

View File

@@ -17,6 +17,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.GetFollowRequests;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Relationship;
@@ -81,7 +82,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Account> result){
if (getActivity() == null) return;
if(getActivity()==null) return;
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
@@ -269,7 +270,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
relationship=relationships.get(item.account.id);
UiUtils.setExtraTextInfo(getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account);
UiUtils.setExtraTextInfo(getContext(), null, true, false, false, item.account);
if(relationship==null || !relationship.followedBy){
actionWrap.setVisibility(View.GONE);
@@ -357,15 +358,16 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
public AccountWrapper(Account account){
this.account=account;
if(!TextUtils.isEmpty(account.avatar))
avaRequest=new UrlImageLoaderRequest(account.avatar, V.dp(50), V.dp(50));
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? AccountSessionManager.get(getAccountID()).getDefaultAvatarUrl() : account.avatar,
V.dp(50), V.dp(50));
if(!TextUtils.isEmpty(account.header))
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(account.emojis.isEmpty()){
parsedName=account.displayName;
parsedName= account.getDisplayName();
}else{
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
}
}

View File

@@ -56,7 +56,7 @@ public class FollowedHashtagsFragment extends MastodonRecyclerFragment<Hashtag>
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Hashtag> result){
if (getActivity() == null) return;
if(getActivity()==null) return;
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
@@ -72,7 +72,6 @@ public class FollowedHashtagsFragment extends MastodonRecyclerFragment<Hashtag>
return new HashtagsAdapter();
}
@Override
public void scrollToTop() {
smoothScrollRecyclerViewToTop(list);
@@ -122,7 +121,7 @@ public class FollowedHashtagsFragment extends MastodonRecyclerFragment<Hashtag>
@Override
public void onClick() {
UiUtils.openHashtagTimeline(getActivity(), accountID, item.name, item.following);
UiUtils.openHashtagTimeline(getActivity(), accountID, item.name);
}
}
}

View File

@@ -1,139 +1,104 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.view.HapticFeedbackConstants;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.tags.GetHashtag;
import org.joinmastodon.android.api.requests.tags.SetHashtagFollowed;
import org.joinmastodon.android.api.MastodonErrorResponse;
import org.joinmastodon.android.api.requests.tags.GetTag;
import org.joinmastodon.android.api.requests.tags.SetTagFollowed;
import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline;
import org.joinmastodon.android.events.HashtagUpdatedEvent;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.text.SpacerSpan;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import org.joinmastodon.android.ui.views.ProgressBarButton;
import org.parceler.Parcels;
import java.util.List;
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.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
public class HashtagTimelineFragment extends PinnableStatusListFragment {
private String hashtag;
public class HashtagTimelineFragment extends PinnableStatusListFragment{
private Hashtag hashtag;
private String hashtagName;
private TextView headerTitle, headerSubtitle;
private ProgressBarButton followButton;
private ProgressBar followProgress;
private MenuItem followMenuItem, pinMenuItem;
private boolean followRequestRunning;
private boolean toolbarContentVisible;
private List<String> any;
private List<String> all;
private List<String> none;
private boolean following;
private boolean localOnly;
private MenuItem followButton;
private Menu optionsMenu;
private MenuInflater optionsMenuInflater;
@Override
protected boolean wantsComposeButton() {
return true;
}
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
updateTitle(getArguments().getString("hashtag"));
following=getArguments().getBoolean("following", false);
localOnly=getArguments().getBoolean("localOnly", false);
any=getArguments().getStringArrayList("any");
all=getArguments().getStringArrayList("all");
none=getArguments().getStringArrayList("none");
setHasOptionsMenu(true);
}
private void updateTitle(String hashtagName) {
hashtag = hashtagName;
setTitle('#'+hashtag);
}
private void updateFollowingState(boolean newFollowing) {
this.following = newFollowing;
followButton.setTitle(getString(newFollowing ? R.string.unfollow_user : R.string.follow_user, "#" + hashtag));
followButton.setIcon(newFollowing ? R.drawable.ic_fluent_person_delete_24_filled : R.drawable.ic_fluent_person_add_24_regular);
E.post(new HashtagUpdatedEvent(hashtag, following));
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.hashtag_timeline, menu);
super.onCreateOptionsMenu(menu, inflater);
followButton = menu.findItem(R.id.follow_hashtag);
updateFollowingState(following);
new GetHashtag(hashtag).setCallback(new Callback<>() {
@Override
public void onSuccess(Hashtag hashtag) {
if (getActivity() == null) return;
updateTitle(hashtag.name);
updateFollowingState(hashtag.following);
}
@Override
public void onError(ErrorResponse error) {
error.showToast(getActivity());
}
}).exec(accountID);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (super.onOptionsItemSelected(item)) return true;
if (item.getItemId() == R.id.follow_hashtag) {
updateFollowingState(!following);
getToolbar().performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
new SetHashtagFollowed(hashtag, following).setCallback(new Callback<>() {
@Override
public void onSuccess(Hashtag i) {
if (getActivity() == null) return;
if (i.following == following) Toast.makeText(getActivity(), getString(i.following ? R.string.followed_user : R.string.unfollowed_user, "#" + i.name), Toast.LENGTH_SHORT).show();
updateFollowingState(i.following);
}
@Override
public void onError(ErrorResponse error) {
error.showToast(getActivity());
updateFollowingState(!following);
}
}).exec(accountID);
return true;
if(getArguments().containsKey("hashtag")){
hashtag=Parcels.unwrap(getArguments().getParcelable("hashtag"));
hashtagName=hashtag.name;
}else{
hashtagName=getArguments().getString("hashtagName");
}
return false;
setTitle('#'+hashtagName);
setHasOptionsMenu(true);
}
@Override
protected TimelineDefinition makeTimelineDefinition() {
return TimelineDefinition.ofHashtag(hashtag);
return TimelineDefinition.ofHashtag(hashtagName);
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetHashtagTimeline(hashtag, offset==0 ? null : getMaxID(), null, count, any, all, none, localOnly, getLocalPrefs().timelineReplyVisibility)
currentRequest=new GetHashtagTimeline(hashtagName, getMaxID(), null, count, any, all, none, localOnly, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
if(getActivity()==null) return;
boolean more=applyMaxID(result);
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
onDataLoaded(result, more);
}
})
.exec(accountID);
@@ -147,15 +112,40 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
}
@Override
public boolean onFabLongClick(View v) {
return UiUtils.pickAccountForCompose(getActivity(), accountID, '#'+hashtag+' ');
public void loadData(){
reloadTag();
super.loadData();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
fab=view.findViewById(R.id.fab);
fab.setOnClickListener(this::onFabClick);
if(getParentFragment() instanceof HomeTabFragment) return;
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
View topChild=recyclerView.getChildAt(0);
int firstChildPos=recyclerView.getChildAdapterPosition(topChild);
float newAlpha=firstChildPos>0 ? 1f : Math.min(1f, -topChild.getTop()/(float)headerTitle.getHeight());
toolbarTitleView.setAlpha(newAlpha);
boolean newToolbarVisibility=newAlpha>0.5f;
if(newToolbarVisibility!=toolbarContentVisible){
toolbarContentVisible=newToolbarVisibility;
createOptionsMenu();
}
}
});
}
@Override
public void onFabClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("prefilledText", '#'+hashtag+' ');
args.putString("prefilledText", '#'+hashtagName+' ');
Nav.go(getActivity(), ComposeFragment.class, args);
}
@@ -171,6 +161,202 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
@Override
public Uri getWebUri(Uri.Builder base) {
return base.path((isInstanceAkkoma() ? "/tag/" : "/tags") + hashtag).build();
return base.path((isInstanceAkkoma() ? "/tag/" : "/tags/") + hashtag).build();
}
@Override
protected RecyclerView.Adapter getAdapter(){
View header=getActivity().getLayoutInflater().inflate(R.layout.header_hashtag_timeline, list, false);
headerTitle=header.findViewById(R.id.title);
headerSubtitle=header.findViewById(R.id.subtitle);
followButton=header.findViewById(R.id.profile_action_btn);
followProgress=header.findViewById(R.id.action_progress);
headerTitle.setText("#"+hashtagName);
followButton.setVisibility(View.GONE);
followButton.setOnClickListener(v->{
if(hashtag==null)
return;
setFollowed(!hashtag.following);
});
followButton.setOnLongClickListener(v->{
if(hashtag==null) return false;
UiUtils.pickAccount(getActivity(), accountID, R.string.sk_follow_as, R.drawable.ic_fluent_person_add_28_regular, session -> {
new SetTagFollowed(hashtagName, true).setCallback(new Callback<>(){
@Override
public void onSuccess(Hashtag hashtag) {
Toast.makeText(
getActivity(),
getString(R.string.sk_followed_as, session.self.getShortUsername()),
Toast.LENGTH_SHORT
).show();
}
@Override
public void onError(ErrorResponse error) {
error.showToast(getActivity());
}
}).exec(session.getID());
}, null);
return true;
});
updateHeader();
MergeRecyclerAdapter mergeAdapter=new MergeRecyclerAdapter();
if(!(getParentFragment() instanceof HomeTabFragment)){
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(header));
}
mergeAdapter.addAdapter(super.getAdapter());
return mergeAdapter;
}
@Override
protected int getMainAdapterOffset(){
return 1;
}
private void createOptionsMenu(){
optionsMenu.clear();
optionsMenuInflater.inflate(R.menu.hashtag_timeline, optionsMenu);
followMenuItem=optionsMenu.findItem(R.id.follow_hashtag);
pinMenuItem=optionsMenu.findItem(R.id.pin);
followMenuItem.setVisible(toolbarContentVisible);
pinMenuItem.setShowAsAction(toolbarContentVisible ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_ALWAYS);
super.updatePinButton(pinMenuItem);
if(toolbarContentVisible){
UiUtils.enableOptionsMenuIcons(getContext(), optionsMenu);
}else{
UiUtils.enableOptionsMenuIcons(getContext(), optionsMenu, R.id.pin);
}
}
@Override
public void updatePinButton(MenuItem pin){
super.updatePinButton(pin);
if(toolbarContentVisible) UiUtils.insetPopupMenuIcon(getContext(), pin);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
inflater.inflate(R.menu.hashtag_timeline, menu);
super.onCreateOptionsMenu(menu, inflater);
optionsMenu=menu;
optionsMenuInflater=inflater;
createOptionsMenu();
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
if (super.onOptionsItemSelected(item)) return true;
if (item.getItemId() == R.id.follow_hashtag && hashtag!=null) {
setFollowed(!hashtag.following);
}
return true;
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
toolbarTitleView.setAlpha(toolbarContentVisible ? 1f : 0f);
createOptionsMenu();
}
private void updateHeader(){
if(hashtag==null || getActivity()==null)
return;
if(hashtag.history!=null && !hashtag.history.isEmpty()){
int weekPosts=hashtag.history.stream().mapToInt(h->h.uses).sum();
int todayPosts=hashtag.history.get(0).uses;
int numAccounts=hashtag.history.stream().mapToInt(h->h.accounts).sum();
int hSpace=V.dp(8);
SpannableStringBuilder ssb=new SpannableStringBuilder();
ssb.append(getResources().getQuantityString(R.plurals.x_posts, weekPosts, weekPosts));
ssb.append(" ", new SpacerSpan(hSpace, 0), 0);
ssb.append('·');
ssb.append(" ", new SpacerSpan(hSpace, 0), 0);
ssb.append(getResources().getQuantityString(R.plurals.x_participants, numAccounts, numAccounts));
ssb.append(" ", new SpacerSpan(hSpace, 0), 0);
ssb.append('·');
ssb.append(" ", new SpacerSpan(hSpace, 0), 0);
ssb.append(getResources().getQuantityString(R.plurals.x_posts_today, todayPosts, todayPosts));
headerSubtitle.setText(ssb);
}
int styleRes;
followButton.setVisibility(View.VISIBLE);
if(hashtag.following){
followButton.setText(R.string.button_following);
styleRes=R.style.Widget_Mastodon_M3_Button_Tonal;
}else{
followButton.setText(R.string.button_follow);
styleRes=R.style.Widget_Mastodon_M3_Button_Filled;
}
TypedArray ta=followButton.getContext().obtainStyledAttributes(styleRes, new int[]{android.R.attr.background});
followButton.setBackground(ta.getDrawable(0));
ta.recycle();
ta=followButton.getContext().obtainStyledAttributes(styleRes, new int[]{android.R.attr.textColor});
followButton.setTextColor(ta.getColorStateList(0));
followProgress.setIndeterminateTintList(ta.getColorStateList(0));
ta.recycle();
followButton.setTextVisible(true);
followProgress.setVisibility(View.GONE);
if(followMenuItem!=null){
followMenuItem.setTitle(getString(hashtag.following ? R.string.unfollow_user : R.string.follow_user, "#"+hashtagName));
followMenuItem.setIcon(hashtag.following ? R.drawable.ic_fluent_person_delete_24_filled : R.drawable.ic_fluent_person_add_24_regular);
UiUtils.insetPopupMenuIcon(getContext(), followMenuItem);
}
}
private void reloadTag(){
new GetTag(hashtagName)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Hashtag result){
hashtag=result;
updateHeader();
}
@Override
public void onError(ErrorResponse error){
}
})
.exec(accountID);
}
private void setFollowed(boolean followed){
if(followRequestRunning)
return;
getToolbar().performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
followButton.setTextVisible(false);
followProgress.setVisibility(View.VISIBLE);
followRequestRunning=true;
new SetTagFollowed(hashtagName, followed)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Hashtag result){
if(getActivity()==null)
return;
hashtag=result;
updateHeader();
followRequestRunning=false;
}
@Override
public void onError(ErrorResponse error){
if(getActivity()==null)
return;
if(error instanceof MastodonErrorResponse er && "Duplicate record".equals(er.error)){
hashtag.following=true;
}else{
error.showToast(getActivity());
}
updateHeader();
followRequestRunning=false;
}
})
.exec(accountID);
}
}

View File

@@ -5,8 +5,6 @@ import android.app.Fragment;
import android.app.NotificationManager;
import android.app.assist.AssistContent;
import android.graphics.drawable.RippleDrawable;
import android.content.Intent;
import android.graphics.Outline;
import android.os.Build;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -33,9 +31,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent;
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
import org.joinmastodon.android.fragments.onboarding.OnboardingFollowSuggestionsFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.ui.AccountSwitcherSheet;
@@ -50,7 +46,6 @@ import java.util.ArrayList;
import java.util.List;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.fragments.AppKitFragment;
@@ -75,15 +70,12 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private TextView notificationsBadge;
private String accountID;
private boolean isAkkoma;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
setTitle(R.string.mo_app_name);
isAkkoma = getInstance().map(Instance::isAkkoma).orElse(false);
setTitle(R.string.sk_app_name);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
setRetainInstance(true);
@@ -94,7 +86,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
homeTabFragment=new HomeTabFragment();
homeTabFragment.setArguments(args);
args=new Bundle(args);
args.putBoolean("disableDiscover", isAkkoma);
args.putBoolean("noAutoLoad", true);
discoverFragment=new DiscoverFragment();
discoverFragment.setArguments(args);
@@ -189,6 +180,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
});
}
}
tabBar.selectTab(currentTab);
return content;
}
@@ -268,11 +260,8 @@ 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)
discoverFragment.openSearch();
else if(newFragment instanceof ScrollableToTop scrollable)
scrollable.scrollToTop();
if(tab==currentTab && newFragment instanceof ScrollableToTop scrollable) {
scrollable.scrollToTop();
return;
}
getChildFragmentManager().beginTransaction().hide(fragmentForTab(currentTab)).show(newFragment).commit();
@@ -303,22 +292,16 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
if(tab==R.id.tab_profile){
ArrayList<String> options=new ArrayList<>();
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")");
options.add(session.self.getDisplayName()+"\n("+session.self.username+"@"+session.domain+")");
}
new AccountSwitcherSheet(getActivity(), this).show();
return true;
}
if(tab==R.id.tab_search){
onTabSelected(R.id.tab_search);
} else if(tab==R.id.tab_search){
tabBar.selectTab(R.id.tab_search);
onTabSelected(R.id.tab_search);
discoverFragment.openSearch();
return true;
}
if(tab==R.id.tab_home){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), OnboardingFollowSuggestionsFragment.class, args);
}
return false;
}

View File

@@ -122,10 +122,6 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
fragments=new Fragment[count];
tabViews=new FrameLayout[count];
timelines=new TimelineDefinition[count];
if(GlobalUserPreferences.toolbarMarquee){
setTitleMarqueeEnabled(false);
setSubtitleMarqueeEnabled(false);
}
}
@Override
@@ -237,21 +233,25 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
ViewTreeObserver vto = getToolbar().getViewTreeObserver();
if (vto.isAlive()) {
vto.addOnGlobalLayoutListener(() -> {
Toolbar t = getToolbar();
if (t == null) return;
int toolbarWidth = t.getWidth();
if (toolbarWidth == 0) return;
vto.addOnGlobalLayoutListener(()->{
Toolbar t=getToolbar();
if(t==null) return;
int toolbarWidth=t.getWidth();
if(toolbarWidth==0) return;
int toolbarFrameWidth = toolbarFrame.getWidth();
int padding = toolbarWidth - toolbarFrameWidth;
FrameLayout parent = ((FrameLayout) toolbarShowNewPostsBtn.getParent());
if (padding == parent.getPaddingStart()) return;
int toolbarFrameWidth=toolbarFrame.getWidth();
int actionsWidth=toolbarWidth-toolbarFrameWidth;
// margin (4) + padding (12) + icon (24) + margin (8) + chevron (16) + padding (12)
int switcherWidth=V.dp(76);
FrameLayout parent=((FrameLayout) toolbarShowNewPostsBtn.getParent());
if(actionsWidth==parent.getPaddingStart()) return;
int paddingMax=Math.max(actionsWidth, switcherWidth);
int paddingEnd=(Math.max(0, switcherWidth-actionsWidth));
// toolbar frame goes from screen edge to beginning of right-aligned option buttons.
// centering button by applying the same space on the left
parent.setPaddingRelative(padding, 0, 0, 0);
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth - padding * 2);
parent.setPaddingRelative(paddingMax, 0, paddingEnd, 0);
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth-paddingMax*2);
switcher.setPivotX(V.dp(28)); // padding + half of icon
switcher.setPivotY(switcher.getHeight() / 2f);
@@ -291,7 +291,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
new GetAnnouncements(false).setCallback(new Callback<>() {
@Override
public void onSuccess(List<Announcement> result) {
if (getActivity() == null) return;
if(getActivity()==null) return;
if (result.stream().anyMatch(a -> !a.read)) {
announcementsBadged = true;
announcements.setVisible(false);
@@ -385,7 +385,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
}
private void updateOverflowMenu() {
if (getActivity() == null) return;
if(getActivity()==null) return;
Menu m = overflowPopup.getMenu();
m.clear();
overflowPopup.inflate(R.menu.home_overflow);
@@ -404,9 +404,8 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
addListsToOverflowMenu();
addHashtagsToOverflowMenu();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !UiUtils.isEMUI()) {
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P && !UiUtils.isEMUI())
m.setGroupDividerEnabled(true);
}
}
@Override
@@ -528,21 +527,13 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
if (list.repliesPolicy != null) args.putInt("repliesPolicy", list.repliesPolicy.ordinal());
Nav.go(getActivity(), ListTimelineFragment.class, args);
} else if ((hashtag = hashtagsItems.get(id)) != null) {
args.putString("hashtag", hashtag.name);
args.putBoolean("following", hashtag.following);
Nav.go(getActivity(), HashtagTimelineFragment.class, args);
UiUtils.openHashtagTimeline(getContext(), accountID, hashtag);
}
return true;
}
@Override
public void scrollToTop(){
if (((IsOnTop) fragments[pager.getCurrentItem()]).isOnTop() &&
GlobalUserPreferences.doubleTapToSwipe && !newPostsBtnShown) {
int nextPage = (pager.getCurrentItem() + 1) % count;
navigateTo(nextPage);
return;
}
((ScrollableToTop) fragments[pager.getCurrentItem()]).scrollToTop();
}
@@ -616,8 +607,8 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
private void onNewPostsBtnClick(View view) {
if(newPostsBtnShown){
scrollToTop();
hideNewPostsButton();
scrollToTop();
}
}

View File

@@ -11,27 +11,26 @@ import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineMarkers;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.V;
public class HomeTimelineFragment extends StatusListFragment {
private HomeTabFragment parent;
@@ -50,16 +49,6 @@ public class HomeTimelineFragment extends StatusListFragment {
loadData();
}
private boolean typeFilterPredicate(Status s) {
AccountLocalPreferences lp=getLocalPrefs();
return (lp.showReplies || s.inReplyToId == null) &&
(lp.showBoosts || s.reblog == null);
}
private List<Status> filterPosts(List<Status> items) {
return items.stream().filter(this::typeFilterPredicate).collect(Collectors.toList());
}
@Override
protected void doLoadData(int offset, int count){
AccountSessionManager.getInstance()
@@ -67,11 +56,12 @@ public class HomeTimelineFragment extends StatusListFragment {
.getHomeTimeline(offset>0 ? maxID : null, count, refreshing, new SimpleCallback<>(this){
@Override
public void onSuccess(CacheablePaginatedResponse<List<Status>> result){
if (getActivity() == null) return;
List<Status> filteredItems = filterPosts(result.items);
if(getActivity()==null) return;
boolean empty=result.items.isEmpty();
maxID=result.maxID;
onDataLoaded(filteredItems, !result.items.isEmpty());
if(result.isFromCache())
AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
onDataLoaded(result.items, !empty);
if(result.isFromCache() && GlobalUserPreferences.loadNewPosts)
loadNewPosts();
}
});
@@ -84,7 +74,7 @@ public class HomeTimelineFragment extends StatusListFragment {
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
if(parent != null && parent.isNewPostsBtnShown() && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){
if(parent!=null && parent.isNewPostsBtnShown() && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){
parent.hideNewPostsButton();
}
}
@@ -97,7 +87,7 @@ public class HomeTimelineFragment extends StatusListFragment {
if(!getArguments().getBoolean("noAutoLoad")){
if(!loaded && !dataLoading){
loadData();
}else if(!dataLoading){
}else if(!dataLoading && GlobalUserPreferences.loadNewPosts){
loadNewPosts();
}
}
@@ -127,38 +117,46 @@ public class HomeTimelineFragment extends StatusListFragment {
}
public void onStatusCreated(Status status){
if(status.reblog!=null) return;
prependItems(Collections.singletonList(status), true);
}
private void loadNewPosts(){
if (!GlobalUserPreferences.loadNewPosts) return;
dataLoading=true;
// we only care about the data that was actually retrieved from the timeline api since
// user-created statuses are probably in the wrong position
List<Status> dataFromTimeline=data.stream().filter(s->!s.fromStatusCreated).collect(Collectors.toList());
// The idea here is that we request the timeline such that if there are fewer than `limit` posts,
// we'll get the currently topmost post as last in the response. This way we know there's no gap
// between the existing and newly loaded parts of the timeline.
String sinceID=data.size()>1 ? data.get(1).id : "1";
String sinceID=dataFromTimeline.size()>1 ? dataFromTimeline.get(1).id : "1";
currentRequest=new GetHomeTimeline(null, null, 20, sinceID, getLocalPrefs().timelineReplyVisibility)
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Status> result){
currentRequest=null;
dataLoading=false;
result = filterPosts(result);
refreshDone();
if(result.isEmpty() || getActivity()==null)
return;
Status last=result.get(result.size()-1);
List<Status> toAdd;
if(!data.isEmpty() && last.id.equals(data.get(0).id)){ // This part intersects with the existing one
toAdd=result.subList(0, result.size()-1); // Remove the already known last post
if(!dataFromTimeline.isEmpty() && last.id.equals(dataFromTimeline.get(0).id)){ // This part intersects with the existing one
toAdd=new ArrayList<>(result.subList(0, result.size()-1)); // Remove the already known last post
}else{
result.get(result.size()-1).hasGapAfter=true;
last.hasGapAfter=last.id;
toAdd=result;
}
if(!toAdd.isEmpty())
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(new ArrayList<>(toAdd), false);
// removing statuses that come up as duplicates (hopefully only posts and boosts that were locally created
// and thus were already prepended to the timeline earlier)
List<String> existingIds=data.stream().map(Status::getID).collect(Collectors.toList());
toAdd.removeIf(s->existingIds.contains(s.getID()));
AccountSessionManager.get(accountID).filterStatuses(toAdd, getFilterContext());
if(!toAdd.isEmpty()){
prependItems(toAdd, true);
if (parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAdd, false);
if(parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
}
}
@@ -166,6 +164,7 @@ public class HomeTimelineFragment extends StatusListFragment {
public void onError(ErrorResponse error){
currentRequest=null;
dataLoading=false;
refreshDone();
}
})
.exec(accountID);
@@ -176,15 +175,23 @@ public class HomeTimelineFragment extends StatusListFragment {
}
@Override
public void onGapClick(GapStatusDisplayItem.Holder item){
public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){
if(dataLoading)
return;
item.getItem().loading=true;
V.setVisibilityAnimated(item.progress, View.VISIBLE);
V.setVisibilityAnimated(item.text, View.GONE);
GapStatusDisplayItem gap=item.getItem();
gap.loading=true;
dataLoading=true;
currentRequest=new GetHomeTimeline(item.getItemID(), null, 20, null, getLocalPrefs().timelineReplyVisibility)
String maxID=null;
String minID=null;
if (downwards) {
maxID=item.getItem().getMaxID();
} else {
int gapPos=displayItems.indexOf(gap);
StatusDisplayItem nextItem=displayItems.get(gapPos + 1);
minID=nextItem.parentID;
}
currentRequest=new GetHomeTimeline(maxID, minID, 20, null, getLocalPrefs().timelineReplyVisibility)
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Status> result){
@@ -195,61 +202,108 @@ public class HomeTimelineFragment extends StatusListFragment {
int gapPos=displayItems.indexOf(gap);
if(gapPos==-1)
return;
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
if(result.isEmpty()){
displayItems.remove(gapPos);
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
Status gapStatus=getStatusByID(gap.parentID);
if(gapStatus!=null){
gapStatus.hasGapAfter=false;
gapStatus.hasGapAfter=null;
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus), false);
}
}else{
Set<String> idsBelowGap=new HashSet<>();
boolean belowGap=false;
int gapPostIndex=0;
for(Status s:data){
if(belowGap){
idsBelowGap.add(s.id);
}else if(s.id.equals(gap.parentID)){
belowGap=true;
s.hasGapAfter=false;
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(s), false);
}else{
gapPostIndex++;
// TODO: refactor this code. it's too long. incomprehensible, even
if(downwards) {
Set<String> idsBelowGap=new HashSet<>();
boolean belowGap=false;
int gapPostIndex=0;
for(Status s:data){
if(belowGap){
idsBelowGap.add(s.id);
}else if(s.id.equals(gap.parentID)){
belowGap=true;
s.hasGapAfter=null;
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(s), false);
}else{
gapPostIndex++;
}
}
}
int endIndex=0;
for(Status s:result){
endIndex++;
if(idsBelowGap.contains(s.id))
break;
}
if(endIndex==result.size()){
result.get(result.size()-1).hasGapAfter=true;
}else{
result=result.subList(0, endIndex);
}
List<StatusDisplayItem> targetList=displayItems.subList(gapPos, gapPos+1);
targetList.clear();
List<Status> insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1);
StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, getFilterContext());
for(Status s:result){
if(idsBelowGap.contains(s.id))
break;
if(typeFilterPredicate(s) && filterPredicate.test(s)){
int endIndex=0;
for(Status s:result){
endIndex++;
if(idsBelowGap.contains(s.id))
break;
}
if(endIndex==result.size()){
Status last=result.get(result.size()-1);
last.hasGapAfter=last.id;
}else{
result=result.subList(0, endIndex);
}
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME);
List<StatusDisplayItem> targetList=displayItems.subList(gapPos, gapPos+1);
targetList.clear();
List<Status> insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1);
for(Status s:result){
if(idsBelowGap.contains(s.id))
break;
targetList.addAll(buildDisplayItems(s));
insertedPosts.add(s);
}
if(targetList.isEmpty()){
// oops. We didn't add new posts, but at least we know there are none.
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
}else{
adapter.notifyItemChanged(getMainAdapterOffset()+gapPos);
adapter.notifyItemRangeInserted(getMainAdapterOffset()+gapPos+1, targetList.size()-1);
}
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(insertedPosts, false);
} else {
String aboveGapID = gap.parentID;
int gapPostIndex = 0;
for (;gapPostIndex<data.size();gapPostIndex++){
if (Objects.equals(aboveGapID, data.get(gapPostIndex).id)) {
break;
}
}
// find if there's an overlap between the new data and the current data
int indexOfGapInResponse = 0;
for (;indexOfGapInResponse<result.size();indexOfGapInResponse++){
if (Objects.equals(aboveGapID, result.get(indexOfGapInResponse).id)) {
break;
}
}
// there is an overlap between new and current data
List<StatusDisplayItem> targetList=displayItems.subList(gapPos, gapPos+1);
if(indexOfGapInResponse<result.size()){
result=result.subList(indexOfGapInResponse+1,result.size());
Optional<Status> gapStatus=data.stream()
.filter(s->Objects.equals(s.id, gap.parentID))
.findFirst();
if (gapStatus.isPresent()) {
gapStatus.get().hasGapAfter=null;
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus.get()), false);
}
targetList.clear();
} else {
gap.loading=false;
}
List<Status> insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1);
for(Status s:result){
targetList.addAll(buildDisplayItems(s));
insertedPosts.add(s);
}
AccountSessionManager.get(accountID).filterStatuses(insertedPosts, FilterContext.HOME);
if(targetList.isEmpty()){
// oops. We didn't add new posts, but at least we know there are none.
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
}else{
adapter.notifyItemChanged(getMainAdapterOffset()+gapPos);
adapter.notifyItemRangeInserted(getMainAdapterOffset()+gapPos+1, targetList.size()-1);
}
list.scrollToPosition(getMainAdapterOffset()+gapPos+targetList.size());
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(insertedPosts, false);
}
AccountSessionManager.get(accountID).filterStatuses(insertedPosts, getFilterContext());
if(targetList.isEmpty()){
// oops. We didn't add new posts, but at least we know there are none.
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
}else{
adapter.notifyItemChanged(getMainAdapterOffset()+gapPos);
adapter.notifyItemRangeInserted(getMainAdapterOffset()+gapPos+1, targetList.size()-1);
}
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(insertedPosts, false);
}
}
@@ -278,7 +332,7 @@ public class HomeTimelineFragment extends StatusListFragment {
currentRequest=null;
dataLoading=false;
}
if (parent != null) parent.hideNewPostsButton();
if(parent!=null) parent.hideNewPostsButton();
super.onRefresh();
}

View File

@@ -16,6 +16,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.lists.GetList;
import org.joinmastodon.android.api.requests.lists.UpdateList;
import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.ListDeletedEvent;
import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
import org.joinmastodon.android.model.FilterContext;
@@ -25,10 +26,8 @@ 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.ListEditor;
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;
@@ -63,7 +62,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
new GetList(listID).setCallback(new Callback<>() {
@Override
public void onSuccess(ListTimeline listTimeline) {
if (getActivity() == null) return;
if(getActivity()==null) return;
// TODO: save updated info
if (!listTimeline.title.equals(listTitle)) setTitle(listTimeline.title);
if (listTimeline.repliesPolicy != null && !listTimeline.repliesPolicy.equals(repliesPolicy)) {
@@ -101,7 +100,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
new UpdateList(listID, newTitle, editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
@Override
public void onSuccess(ListTimeline list) {
if (getActivity() == null) return;
if(getActivity()==null) return;
setTitle(list.title);
listTitle = list.title;
repliesPolicy = list.repliesPolicy;
@@ -134,13 +133,14 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
@Override
protected void doLoadData(int offset, int count) {
currentRequest=new GetListTimeline(listID, offset==0 ? null : getMaxID(), null, count, null, getLocalPrefs().timelineReplyVisibility)
currentRequest=new GetListTimeline(listID, getMaxID(), null, count, null, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this) {
@Override
public void onSuccess(List<Status> result) {
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
if(getActivity()==null) return;
boolean more=applyMaxID(result);
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
onDataLoaded(result, more);
}
})
.exec(accountID);

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